xref: /rk3399_rockchip-uboot/drivers/mmc/mmc.c (revision c30b51158f59cb3336bfa7ed29c0c7b0b6993b9e)
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__);
311*c30b5115SJason Zhu 			int timeout = 0;
312*c30b5115SJason Zhu re_init_retry:
313*c30b5115SJason Zhu 			timeout++;
314*c30b5115SJason Zhu 			/*
315*c30b5115SJason Zhu 			 * Try re-init seven times.
316*c30b5115SJason Zhu 			 */
317*c30b5115SJason Zhu 			if (timeout > 7) {
318*c30b5115SJason Zhu 				printf("Re-init retry timeout\n");
3194a1a06bcSAlagu Sankar 				return 0;
32011692991SSimon Glass 			}
321*c30b5115SJason Zhu 
322*c30b5115SJason Zhu 			mmc->has_init = 0;
323*c30b5115SJason Zhu 			if (mmc_init(mmc))
324*c30b5115SJason Zhu 				return 0;
325*c30b5115SJason Zhu 
326*c30b5115SJason Zhu 			if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
327*c30b5115SJason Zhu 				printf("%s: Re-init mmc_read_blocks error\n",
328*c30b5115SJason Zhu 				       __func__);
329*c30b5115SJason Zhu 				goto re_init_retry;
330*c30b5115SJason Zhu 			}
331*c30b5115SJason 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 
56555e5defdSZiyuan Xu static int mmc_poll_for_busy(struct mmc *mmc)
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 
57955e5defdSZiyuan Xu 	do {
58055e5defdSZiyuan Xu 		if (mmc_can_card_busy(mmc)) {
58155e5defdSZiyuan Xu 			busy = mmc_card_busy(mmc);
58255e5defdSZiyuan Xu 		} else {
58355e5defdSZiyuan Xu 			ret = mmc_send_cmd(mmc, &cmd, NULL);
58455e5defdSZiyuan Xu 
58555e5defdSZiyuan Xu 			if (ret)
58655e5defdSZiyuan Xu 				return ret;
58755e5defdSZiyuan Xu 
58855e5defdSZiyuan Xu 			if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR)
58955e5defdSZiyuan Xu 				return -EBADMSG;
59055e5defdSZiyuan Xu 			busy = (cmd.response[0] & MMC_STATUS_CURR_STATE) ==
59155e5defdSZiyuan Xu 				MMC_STATE_PRG;
59255e5defdSZiyuan Xu 		}
59355e5defdSZiyuan Xu 
59455e5defdSZiyuan Xu 		if (get_timer(start) > timeout && busy)
59555e5defdSZiyuan Xu 			return -ETIMEDOUT;
59655e5defdSZiyuan Xu 	} while (busy);
59755e5defdSZiyuan Xu 
59855e5defdSZiyuan Xu 	return 0;
59955e5defdSZiyuan Xu }
60055e5defdSZiyuan Xu 
60155e5defdSZiyuan Xu static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value,
60255e5defdSZiyuan Xu 			u8 send_status)
60355e5defdSZiyuan Xu {
60455e5defdSZiyuan Xu 	struct mmc_cmd cmd;
605a9003dc6SMaxime Ripard 	int retries = 3;
6065d4fc8d9SRaffaele Recalcati 	int ret;
607272cc70bSAndy Fleming 
608272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
609272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
610272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
611272cc70bSAndy Fleming 				 (index << 16) |
612272cc70bSAndy Fleming 				 (value << 8);
613272cc70bSAndy Fleming 
61455e5defdSZiyuan Xu 	do {
6155d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
6165d4fc8d9SRaffaele Recalcati 
61755e5defdSZiyuan Xu 		if (!ret && send_status)
61855e5defdSZiyuan Xu 			return mmc_poll_for_busy(mmc);
61955e5defdSZiyuan Xu 	} while (--retries > 0 && ret);
62055e5defdSZiyuan Xu 
621a9003dc6SMaxime Ripard 	return ret;
622a9003dc6SMaxime Ripard }
623a9003dc6SMaxime Ripard 
62455e5defdSZiyuan Xu int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
62555e5defdSZiyuan Xu {
62655e5defdSZiyuan Xu 	return __mmc_switch(mmc, set, index, value, true);
627272cc70bSAndy Fleming }
628272cc70bSAndy Fleming 
62949dba033SZiyuan Xu static int mmc_select_bus_width(struct mmc *mmc)
63049dba033SZiyuan Xu {
63149dba033SZiyuan Xu 	u32 ext_csd_bits[] = {
63249dba033SZiyuan Xu 		EXT_CSD_BUS_WIDTH_8,
63349dba033SZiyuan Xu 		EXT_CSD_BUS_WIDTH_4,
63449dba033SZiyuan Xu 	};
63549dba033SZiyuan Xu 	u32 bus_widths[] = {
63649dba033SZiyuan Xu 		MMC_BUS_WIDTH_8BIT,
63749dba033SZiyuan Xu 		MMC_BUS_WIDTH_4BIT,
63849dba033SZiyuan Xu 	};
63949dba033SZiyuan Xu 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
64049dba033SZiyuan Xu 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
64149dba033SZiyuan Xu 	u32 idx, bus_width = 0;
64249dba033SZiyuan Xu 	int err = 0;
64349dba033SZiyuan Xu 
64449dba033SZiyuan Xu 	if (mmc->version < MMC_VERSION_4 ||
64549dba033SZiyuan Xu 	    !(mmc->cfg->host_caps & (MMC_MODE_4BIT | MMC_MODE_8BIT)))
64649dba033SZiyuan Xu 		return 0;
64749dba033SZiyuan Xu 
64849dba033SZiyuan Xu 	err = mmc_send_ext_csd(mmc, ext_csd);
64949dba033SZiyuan Xu 
65049dba033SZiyuan Xu 	if (err)
65149dba033SZiyuan Xu 		return err;
65249dba033SZiyuan Xu 
65349dba033SZiyuan Xu 	idx = (mmc->cfg->host_caps & MMC_MODE_8BIT) ? 0 : 1;
65449dba033SZiyuan Xu 
65549dba033SZiyuan Xu 	/*
65649dba033SZiyuan Xu 	 * Unlike SD, MMC cards dont have a configuration register to notify
65749dba033SZiyuan Xu 	 * supported bus width. So bus test command should be run to identify
65849dba033SZiyuan Xu 	 * the supported bus width or compare the ext csd values of current
65949dba033SZiyuan Xu 	 * bus width and ext csd values of 1 bit mode read earlier.
66049dba033SZiyuan Xu 	 */
66149dba033SZiyuan Xu 	for (; idx < ARRAY_SIZE(bus_widths); idx++) {
66249dba033SZiyuan Xu 		/*
66349dba033SZiyuan Xu 		 * Host is capable of 8bit transfer, then switch
66449dba033SZiyuan Xu 		 * the device to work in 8bit transfer mode. If the
66549dba033SZiyuan Xu 		 * mmc switch command returns error then switch to
66649dba033SZiyuan Xu 		 * 4bit transfer mode. On success set the corresponding
66749dba033SZiyuan Xu 		 * bus width on the host.
66849dba033SZiyuan Xu 		 */
66949dba033SZiyuan Xu 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
67049dba033SZiyuan Xu 				 EXT_CSD_BUS_WIDTH, ext_csd_bits[idx]);
67149dba033SZiyuan Xu 		if (err)
67249dba033SZiyuan Xu 			continue;
67349dba033SZiyuan Xu 
67449dba033SZiyuan Xu 		bus_width = bus_widths[idx];
67549dba033SZiyuan Xu 		mmc_set_bus_width(mmc, bus_width);
67649dba033SZiyuan Xu 
67749dba033SZiyuan Xu 		err = mmc_send_ext_csd(mmc, test_csd);
67849dba033SZiyuan Xu 
67949dba033SZiyuan Xu 		if (err)
68049dba033SZiyuan Xu 			continue;
68149dba033SZiyuan Xu 
68249dba033SZiyuan Xu 		/* Only compare read only fields */
68349dba033SZiyuan Xu 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] ==
68449dba033SZiyuan Xu 			test_csd[EXT_CSD_PARTITIONING_SUPPORT]) &&
68549dba033SZiyuan Xu 		    (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] ==
68649dba033SZiyuan Xu 			test_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
68749dba033SZiyuan Xu 		    (ext_csd[EXT_CSD_REV] == test_csd[EXT_CSD_REV]) &&
68849dba033SZiyuan Xu 			(ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] ==
68949dba033SZiyuan Xu 			test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
69049dba033SZiyuan Xu 		    !memcmp(&ext_csd[EXT_CSD_SEC_CNT],
69149dba033SZiyuan Xu 			&test_csd[EXT_CSD_SEC_CNT], 4)) {
69249dba033SZiyuan Xu 			err = bus_width;
69349dba033SZiyuan Xu 			break;
69449dba033SZiyuan Xu 		} else {
69549dba033SZiyuan Xu 			err = -EBADMSG;
69649dba033SZiyuan Xu 		}
69749dba033SZiyuan Xu 	}
69849dba033SZiyuan Xu 
69949dba033SZiyuan Xu 	return err;
70049dba033SZiyuan Xu }
70149dba033SZiyuan Xu 
70249dba033SZiyuan Xu static const u8 tuning_blk_pattern_4bit[] = {
70349dba033SZiyuan Xu 	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
70449dba033SZiyuan Xu 	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
70549dba033SZiyuan Xu 	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
70649dba033SZiyuan Xu 	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
70749dba033SZiyuan Xu 	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
70849dba033SZiyuan Xu 	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
70949dba033SZiyuan Xu 	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
71049dba033SZiyuan Xu 	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
71149dba033SZiyuan Xu };
71249dba033SZiyuan Xu 
71349dba033SZiyuan Xu static const u8 tuning_blk_pattern_8bit[] = {
71449dba033SZiyuan Xu 	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
71549dba033SZiyuan Xu 	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
71649dba033SZiyuan Xu 	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
71749dba033SZiyuan Xu 	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
71849dba033SZiyuan Xu 	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
71949dba033SZiyuan Xu 	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
72049dba033SZiyuan Xu 	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
72149dba033SZiyuan Xu 	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
72249dba033SZiyuan Xu 	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
72349dba033SZiyuan Xu 	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
72449dba033SZiyuan Xu 	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
72549dba033SZiyuan Xu 	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
72649dba033SZiyuan Xu 	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
72749dba033SZiyuan Xu 	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
72849dba033SZiyuan Xu 	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
72949dba033SZiyuan Xu 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
73049dba033SZiyuan Xu };
73149dba033SZiyuan Xu 
73249dba033SZiyuan Xu int mmc_send_tuning(struct mmc *mmc, u32 opcode)
73349dba033SZiyuan Xu {
73449dba033SZiyuan Xu 	struct mmc_cmd cmd;
73549dba033SZiyuan Xu 	struct mmc_data data;
73649dba033SZiyuan Xu 	const u8 *tuning_block_pattern;
73749dba033SZiyuan Xu 	int size, err = 0;
73849dba033SZiyuan Xu 	u8 *data_buf;
73949dba033SZiyuan Xu 
74049dba033SZiyuan Xu 	if (mmc->bus_width == MMC_BUS_WIDTH_8BIT) {
74149dba033SZiyuan Xu 		tuning_block_pattern = tuning_blk_pattern_8bit;
74249dba033SZiyuan Xu 		size = sizeof(tuning_blk_pattern_8bit);
74349dba033SZiyuan Xu 	} else if (mmc->bus_width == MMC_BUS_WIDTH_4BIT) {
74449dba033SZiyuan Xu 		tuning_block_pattern = tuning_blk_pattern_4bit;
74549dba033SZiyuan Xu 		size = sizeof(tuning_blk_pattern_4bit);
74649dba033SZiyuan Xu 	} else {
74749dba033SZiyuan Xu 		return -EINVAL;
74849dba033SZiyuan Xu 	}
74949dba033SZiyuan Xu 
75049dba033SZiyuan Xu 	data_buf = calloc(1, size);
75149dba033SZiyuan Xu 	if (!data_buf)
75249dba033SZiyuan Xu 		return -ENOMEM;
75349dba033SZiyuan Xu 
75449dba033SZiyuan Xu 	cmd.cmdidx = opcode;
75549dba033SZiyuan Xu 	cmd.resp_type = MMC_RSP_R1;
75649dba033SZiyuan Xu 	cmd.cmdarg = 0;
75749dba033SZiyuan Xu 
75849dba033SZiyuan Xu 	data.dest = (char *)data_buf;
75949dba033SZiyuan Xu 	data.blocksize = size;
76049dba033SZiyuan Xu 	data.blocks = 1;
76149dba033SZiyuan Xu 	data.flags = MMC_DATA_READ;
76249dba033SZiyuan Xu 
76349dba033SZiyuan Xu 	err = mmc_send_cmd(mmc, &cmd, &data);
76449dba033SZiyuan Xu 	if (err)
76549dba033SZiyuan Xu 		goto out;
76649dba033SZiyuan Xu 
76749dba033SZiyuan Xu 	if (memcmp(data_buf, tuning_block_pattern, size))
76849dba033SZiyuan Xu 		err = -EIO;
76949dba033SZiyuan Xu out:
77049dba033SZiyuan Xu 	free(data_buf);
77149dba033SZiyuan Xu 	return err;
77249dba033SZiyuan Xu }
77349dba033SZiyuan Xu 
77449dba033SZiyuan Xu static int mmc_execute_tuning(struct mmc *mmc)
77549dba033SZiyuan Xu {
77649dba033SZiyuan Xu #ifdef CONFIG_DM_MMC
77749dba033SZiyuan Xu 	struct dm_mmc_ops *ops = mmc_get_ops(mmc->dev);
77849dba033SZiyuan Xu #endif
77949dba033SZiyuan Xu 	u32 opcode;
78049dba033SZiyuan Xu 
78149dba033SZiyuan Xu 	if (IS_SD(mmc))
78249dba033SZiyuan Xu 		opcode = MMC_SEND_TUNING_BLOCK;
78349dba033SZiyuan Xu 	else
78449dba033SZiyuan Xu 		opcode = MMC_SEND_TUNING_BLOCK_HS200;
78549dba033SZiyuan Xu 
78649dba033SZiyuan Xu #ifndef CONFIG_DM_MMC
78749dba033SZiyuan Xu 	if (mmc->cfg->ops->execute_tuning) {
78849dba033SZiyuan Xu 		return mmc->cfg->ops->execute_tuning(mmc, opcode);
78949dba033SZiyuan Xu #else
79049dba033SZiyuan Xu 	if (ops->execute_tuning) {
79149dba033SZiyuan Xu 		return ops->execute_tuning(mmc->dev, opcode);
79249dba033SZiyuan Xu #endif
79349dba033SZiyuan Xu 	} else {
79449dba033SZiyuan Xu 		debug("Tuning feature required for HS200 mode.\n");
79549dba033SZiyuan Xu 		return -EIO;
79649dba033SZiyuan Xu 	}
79749dba033SZiyuan Xu }
79849dba033SZiyuan Xu 
79949dba033SZiyuan Xu static int mmc_hs200_tuning(struct mmc *mmc)
80049dba033SZiyuan Xu {
80149dba033SZiyuan Xu 	return mmc_execute_tuning(mmc);
80249dba033SZiyuan Xu }
80349dba033SZiyuan Xu 
804e61cd3d7SZiyuan Xu static int mmc_select_hs(struct mmc *mmc)
805e61cd3d7SZiyuan Xu {
806e61cd3d7SZiyuan Xu 	int ret;
807e61cd3d7SZiyuan Xu 
808e61cd3d7SZiyuan Xu 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
809e61cd3d7SZiyuan Xu 			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS);
810e61cd3d7SZiyuan Xu 
811e61cd3d7SZiyuan Xu 	if (!ret)
812e61cd3d7SZiyuan Xu 		mmc_set_timing(mmc, MMC_TIMING_MMC_HS);
813e61cd3d7SZiyuan Xu 
814e61cd3d7SZiyuan Xu 	return ret;
815e61cd3d7SZiyuan Xu }
816e61cd3d7SZiyuan Xu 
8175545757fSZiyuan Xu static int mmc_select_hs_ddr(struct mmc *mmc)
8185545757fSZiyuan Xu {
8195545757fSZiyuan Xu 	u32 ext_csd_bits;
8205545757fSZiyuan Xu 	int err = 0;
8215545757fSZiyuan Xu 
8225545757fSZiyuan Xu 	if (mmc->bus_width == MMC_BUS_WIDTH_1BIT)
8235545757fSZiyuan Xu 		return 0;
8245545757fSZiyuan Xu 
8255545757fSZiyuan Xu 	ext_csd_bits = (mmc->bus_width == MMC_BUS_WIDTH_8BIT) ?
8265545757fSZiyuan Xu 			EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
8275545757fSZiyuan Xu 
8285545757fSZiyuan Xu 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
8295545757fSZiyuan Xu 			 EXT_CSD_BUS_WIDTH, ext_csd_bits);
8305545757fSZiyuan Xu 	if (err)
8315545757fSZiyuan Xu 		return err;
8325545757fSZiyuan Xu 
8335545757fSZiyuan Xu 	mmc_set_timing(mmc, MMC_TIMING_MMC_DDR52);
8345545757fSZiyuan Xu 
8355545757fSZiyuan Xu 	return 0;
8365545757fSZiyuan Xu }
8375545757fSZiyuan Xu 
83849dba033SZiyuan Xu #ifndef CONFIG_SPL_BUILD
83949dba033SZiyuan Xu static int mmc_select_hs200(struct mmc *mmc)
84049dba033SZiyuan Xu {
84149dba033SZiyuan Xu 	int ret;
84249dba033SZiyuan Xu 	struct mmc_cmd cmd;
84349dba033SZiyuan Xu 
84449dba033SZiyuan Xu 	/*
84549dba033SZiyuan Xu 	 * Set the bus width(4 or 8) with host's support and
84649dba033SZiyuan Xu 	 * switch to HS200 mode if bus width is set successfully.
84749dba033SZiyuan Xu 	 */
84849dba033SZiyuan Xu 	ret = mmc_select_bus_width(mmc);
84949dba033SZiyuan Xu 
85049dba033SZiyuan Xu 	if (ret > 0) {
85149dba033SZiyuan Xu 		ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
85249dba033SZiyuan Xu 				   EXT_CSD_HS_TIMING,
85349dba033SZiyuan Xu 				   EXT_CSD_TIMING_HS200, false);
85449dba033SZiyuan Xu 
85549dba033SZiyuan Xu 		if (ret)
85649dba033SZiyuan Xu 			return ret;
85749dba033SZiyuan Xu 
85849dba033SZiyuan Xu 		mmc_set_timing(mmc, MMC_TIMING_MMC_HS200);
85949dba033SZiyuan Xu 
86049dba033SZiyuan Xu 		cmd.cmdidx = MMC_CMD_SEND_STATUS;
86149dba033SZiyuan Xu 		cmd.resp_type = MMC_RSP_R1;
86249dba033SZiyuan Xu 		cmd.cmdarg = mmc->rca << 16;
86349dba033SZiyuan Xu 
86449dba033SZiyuan Xu 		ret = mmc_send_cmd(mmc, &cmd, NULL);
86549dba033SZiyuan Xu 
86649dba033SZiyuan Xu 		if (ret)
86749dba033SZiyuan Xu 			return ret;
86849dba033SZiyuan Xu 
86949dba033SZiyuan Xu 		if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR)
87049dba033SZiyuan Xu 			return -EBADMSG;
87149dba033SZiyuan Xu 	}
87249dba033SZiyuan Xu 
87349dba033SZiyuan Xu 	return ret;
87449dba033SZiyuan Xu }
87549dba033SZiyuan Xu #endif
87649dba033SZiyuan Xu 
877b673f29aSZiyuan Xu static int mmc_select_hs400(struct mmc *mmc)
878b673f29aSZiyuan Xu {
879b673f29aSZiyuan Xu 	int ret;
880b673f29aSZiyuan Xu 
881b673f29aSZiyuan Xu 	/* Switch card to HS mode */
882b673f29aSZiyuan Xu 	ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
883b673f29aSZiyuan Xu 			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, false);
884b673f29aSZiyuan Xu 	if (ret)
885b673f29aSZiyuan Xu 		return ret;
886b673f29aSZiyuan Xu 
887b673f29aSZiyuan Xu 	/* Set host controller to HS timing */
888b673f29aSZiyuan Xu 	mmc_set_timing(mmc, MMC_TIMING_MMC_HS);
889b673f29aSZiyuan Xu 
890b673f29aSZiyuan Xu 	/* Reduce frequency to HS frequency */
891b673f29aSZiyuan Xu 	mmc_set_clock(mmc, MMC_HIGH_52_MAX_DTR);
892b673f29aSZiyuan Xu 
893b673f29aSZiyuan Xu 	ret = mmc_send_status(mmc, 1000);
894b673f29aSZiyuan Xu 	if (ret)
895b673f29aSZiyuan Xu 		return ret;
896b673f29aSZiyuan Xu 
897b673f29aSZiyuan Xu 	/* Switch card to DDR */
898b673f29aSZiyuan Xu 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
899b673f29aSZiyuan Xu 			 EXT_CSD_BUS_WIDTH,
900b673f29aSZiyuan Xu 			 EXT_CSD_DDR_BUS_WIDTH_8);
901b673f29aSZiyuan Xu 	if (ret)
902b673f29aSZiyuan Xu 		return ret;
903b673f29aSZiyuan Xu 
904b673f29aSZiyuan Xu 	/* Switch card to HS400 */
905b673f29aSZiyuan Xu 	ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
906b673f29aSZiyuan Xu 			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400, false);
907b673f29aSZiyuan Xu 	if (ret)
908b673f29aSZiyuan Xu 		return ret;
909b673f29aSZiyuan Xu 
910b673f29aSZiyuan Xu 	/* Set host controller to HS400 timing and frequency */
911b673f29aSZiyuan Xu 	mmc_set_timing(mmc, MMC_TIMING_MMC_HS400);
912b673f29aSZiyuan Xu 
913b673f29aSZiyuan Xu 	return ret;
914b673f29aSZiyuan Xu }
915b673f29aSZiyuan Xu 
916227f658eSZiyuan Xu static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd)
917227f658eSZiyuan Xu {
918227f658eSZiyuan Xu 	u8 card_type;
919227f658eSZiyuan Xu 	u32 host_caps, avail_type = 0;
920227f658eSZiyuan Xu 
921227f658eSZiyuan Xu 	card_type = ext_csd[EXT_CSD_CARD_TYPE];
922227f658eSZiyuan Xu 	host_caps = mmc->cfg->host_caps;
923227f658eSZiyuan Xu 
924227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS) &&
925227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_26))
926227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_26;
927227f658eSZiyuan Xu 
928227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS) &&
929227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_52))
930227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_52;
931227f658eSZiyuan Xu 
932227f658eSZiyuan Xu 	/*
933227f658eSZiyuan Xu 	 * For the moment, u-boot doesn't support signal voltage
934227f658eSZiyuan Xu 	 * switch, therefor we assume that host support ddr52
935227f658eSZiyuan Xu 	 * at 1.8v or 3.3v I/O(1.2v I/O not supported, hs200 and
936227f658eSZiyuan Xu 	 * hs400 are the same).
937227f658eSZiyuan Xu 	 */
938227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_DDR_52MHz) &&
939227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V))
940227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
941227f658eSZiyuan Xu 
942227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS200) &&
943227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V))
944227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
945227f658eSZiyuan Xu 
946227f658eSZiyuan Xu 	/*
947227f658eSZiyuan Xu 	 * If host can support HS400, it means that host can also
948227f658eSZiyuan Xu 	 * support HS200.
949227f658eSZiyuan Xu 	 */
950227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS400) &&
951227f658eSZiyuan Xu 	    (host_caps & MMC_MODE_8BIT) &&
952227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V))
953227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V |
954227f658eSZiyuan Xu 				EXT_CSD_CARD_TYPE_HS400_1_8V;
955227f658eSZiyuan Xu 
956227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS400ES) &&
957227f658eSZiyuan Xu 	    (host_caps & MMC_MODE_8BIT) &&
958227f658eSZiyuan Xu 	    ext_csd[EXT_CSD_STROBE_SUPPORT] &&
959227f658eSZiyuan Xu 	    (avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V))
960227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V |
961227f658eSZiyuan Xu 				EXT_CSD_CARD_TYPE_HS400_1_8V |
962227f658eSZiyuan Xu 				EXT_CSD_CARD_TYPE_HS400ES;
963227f658eSZiyuan Xu 
964227f658eSZiyuan Xu 	return avail_type;
965227f658eSZiyuan Xu }
966227f658eSZiyuan Xu 
96749dba033SZiyuan Xu static void mmc_set_bus_speed(struct mmc *mmc, u8 avail_type)
96849dba033SZiyuan Xu {
96949dba033SZiyuan Xu 	int clock = 0;
97049dba033SZiyuan Xu 
97149dba033SZiyuan Xu 	if (mmc_card_hs(mmc))
97249dba033SZiyuan Xu 		clock = (avail_type & EXT_CSD_CARD_TYPE_52) ?
97349dba033SZiyuan Xu 			MMC_HIGH_52_MAX_DTR : MMC_HIGH_26_MAX_DTR;
97449dba033SZiyuan Xu 	else if (mmc_card_hs200(mmc) ||
97549dba033SZiyuan Xu 		 mmc_card_hs400(mmc) ||
97649dba033SZiyuan Xu 		 mmc_card_hs400es(mmc))
97749dba033SZiyuan Xu 		clock = MMC_HS200_MAX_DTR;
97849dba033SZiyuan Xu 
97949dba033SZiyuan Xu 	mmc_set_clock(mmc, clock);
98049dba033SZiyuan Xu }
98149dba033SZiyuan Xu 
982fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
983272cc70bSAndy Fleming {
9848bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
985227f658eSZiyuan Xu 	u32 avail_type;
986272cc70bSAndy Fleming 	int err;
987272cc70bSAndy Fleming 
988fc5b32fbSAndrew Gabbasov 	mmc->card_caps = 0;
989272cc70bSAndy Fleming 
990d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
991d52ebf10SThomas Chou 		return 0;
992d52ebf10SThomas Chou 
993272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
994272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
995272cc70bSAndy Fleming 		return 0;
996272cc70bSAndy Fleming 
997fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
998fc5b32fbSAndrew Gabbasov 
999272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
1000272cc70bSAndy Fleming 
1001272cc70bSAndy Fleming 	if (err)
1002272cc70bSAndy Fleming 		return err;
1003272cc70bSAndy Fleming 
1004227f658eSZiyuan Xu 	avail_type = mmc_select_card_type(mmc, ext_csd);
1005272cc70bSAndy Fleming 
100649dba033SZiyuan Xu #ifndef CONFIG_SPL_BUILD
100749dba033SZiyuan Xu 	if (avail_type & EXT_CSD_CARD_TYPE_HS200)
100849dba033SZiyuan Xu 		err = mmc_select_hs200(mmc);
100949dba033SZiyuan Xu 	else
101049dba033SZiyuan Xu #endif
1011227f658eSZiyuan Xu 	if (avail_type & EXT_CSD_CARD_TYPE_HS)
1012e61cd3d7SZiyuan Xu 		err = mmc_select_hs(mmc);
1013227f658eSZiyuan Xu 	else
1014227f658eSZiyuan Xu 		err = -EINVAL;
1015272cc70bSAndy Fleming 
1016272cc70bSAndy Fleming 	if (err)
1017a5e27b41SHeiko Schocher 		return err;
1018272cc70bSAndy Fleming 
101949dba033SZiyuan Xu 	mmc_set_bus_speed(mmc, avail_type);
1020272cc70bSAndy Fleming 
1021b673f29aSZiyuan Xu 	if (mmc_card_hs200(mmc)) {
102249dba033SZiyuan Xu 		err = mmc_hs200_tuning(mmc);
1023b673f29aSZiyuan Xu 		if (avail_type & EXT_CSD_CARD_TYPE_HS400 &&
1024b673f29aSZiyuan Xu 		    mmc->bus_width == MMC_BUS_WIDTH_8BIT) {
1025b673f29aSZiyuan Xu 			err = mmc_select_hs400(mmc);
1026b673f29aSZiyuan Xu 			mmc_set_bus_speed(mmc, avail_type);
1027b673f29aSZiyuan Xu 		}
1028b673f29aSZiyuan Xu 	} else if (!mmc_card_hs400es(mmc)) {
102949dba033SZiyuan Xu 		err = mmc_select_bus_width(mmc) > 0 ? 0 : err;
10305545757fSZiyuan Xu 		if (!err && avail_type & EXT_CSD_CARD_TYPE_DDR_52)
10315545757fSZiyuan Xu 			err = mmc_select_hs_ddr(mmc);
10325545757fSZiyuan Xu 	}
103349dba033SZiyuan Xu 
1034272cc70bSAndy Fleming 	return err;
1035272cc70bSAndy Fleming }
1036272cc70bSAndy Fleming 
1037f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
1038f866a46dSStephen Warren {
1039f866a46dSStephen Warren 	switch (part_num) {
1040f866a46dSStephen Warren 	case 0:
1041f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
1042f866a46dSStephen Warren 		break;
1043f866a46dSStephen Warren 	case 1:
1044f866a46dSStephen Warren 	case 2:
1045f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
1046f866a46dSStephen Warren 		break;
1047f866a46dSStephen Warren 	case 3:
1048f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
1049f866a46dSStephen Warren 		break;
1050f866a46dSStephen Warren 	case 4:
1051f866a46dSStephen Warren 	case 5:
1052f866a46dSStephen Warren 	case 6:
1053f866a46dSStephen Warren 	case 7:
1054f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
1055f866a46dSStephen Warren 		break;
1056f866a46dSStephen Warren 	default:
1057f866a46dSStephen Warren 		return -1;
1058f866a46dSStephen Warren 	}
1059f866a46dSStephen Warren 
1060c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1061f866a46dSStephen Warren 
1062f866a46dSStephen Warren 	return 0;
1063f866a46dSStephen Warren }
1064f866a46dSStephen Warren 
10657dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
1066bc897b1dSLei Wen {
1067f866a46dSStephen Warren 	int ret;
1068bc897b1dSLei Wen 
1069f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
1070bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
1071bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
1072f866a46dSStephen Warren 
10736dc93e70SPeter Bigot 	/*
10746dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
10756dc93e70SPeter Bigot 	 * to return to representing the raw device.
10766dc93e70SPeter Bigot 	 */
1077873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
10786dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
1079fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
1080873cc1d7SStephen Warren 	}
10816dc93e70SPeter Bigot 
10826dc93e70SPeter Bigot 	return ret;
1083bc897b1dSLei Wen }
1084bc897b1dSLei Wen 
1085ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
1086ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
1087ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
1088ac9da0e0SDiego Santa Cruz {
1089ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
1090ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
1091ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
1092ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
1093ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
1094ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
10958dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
1096ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
1097ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
1098ac9da0e0SDiego Santa Cruz 
1099ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
1100ac9da0e0SDiego Santa Cruz 		return -EINVAL;
1101ac9da0e0SDiego Santa Cruz 
1102ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
1103ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
1104ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1105ac9da0e0SDiego Santa Cruz 	}
1106ac9da0e0SDiego Santa Cruz 
1107ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
1108ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
1109ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1110ac9da0e0SDiego Santa Cruz 	}
1111ac9da0e0SDiego Santa Cruz 
1112ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
1113ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
1114ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1115ac9da0e0SDiego Santa Cruz 	}
1116ac9da0e0SDiego Santa Cruz 
1117ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
1118ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
1119ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
1120ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
1121ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
1122ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
1123ac9da0e0SDiego Santa Cruz 			return -EINVAL;
1124ac9da0e0SDiego Santa Cruz 		}
1125ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
1126ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
1127ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
1128ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
1129ac9da0e0SDiego Santa Cruz 		} else {
1130ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
1131ac9da0e0SDiego Santa Cruz 		}
1132ac9da0e0SDiego Santa Cruz 	} else {
1133ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
1134ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
1135ac9da0e0SDiego Santa Cruz 	}
1136ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
1137ac9da0e0SDiego Santa Cruz 
1138ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1139ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
1140ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
1141ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
1142ac9da0e0SDiego Santa Cruz 			return -EINVAL;
1143ac9da0e0SDiego Santa Cruz 		}
1144ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
1145ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
1146ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
1147ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
1148ac9da0e0SDiego Santa Cruz 		}
1149ac9da0e0SDiego Santa Cruz 	}
1150ac9da0e0SDiego Santa Cruz 
1151ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
1152ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
1153ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1154ac9da0e0SDiego Santa Cruz 	}
1155ac9da0e0SDiego Santa Cruz 
1156ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
1157ac9da0e0SDiego Santa Cruz 	if (err)
1158ac9da0e0SDiego Santa Cruz 		return err;
1159ac9da0e0SDiego Santa Cruz 
1160ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
1161ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
1162ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
1163ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
1164ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
1165ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
1166ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
1167ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1168ac9da0e0SDiego Santa Cruz 	}
1169ac9da0e0SDiego Santa Cruz 
11708dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
11718dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
11728dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
11738dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
11748dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
11758dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
11768dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
11778dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
11788dda5b0eSDiego Santa Cruz 		else
11798dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
11808dda5b0eSDiego Santa Cruz 	}
11818dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
11828dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
11838dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
11848dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
11858dda5b0eSDiego Santa Cruz 			else
11868dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
11878dda5b0eSDiego Santa Cruz 		}
11888dda5b0eSDiego Santa Cruz 	}
11898dda5b0eSDiego Santa Cruz 
11908dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
11918dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
11928dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
11938dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
11948dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
11958dda5b0eSDiego Santa Cruz 	}
11968dda5b0eSDiego Santa Cruz 
1197ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
1198ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
1199ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
1200ac9da0e0SDiego Santa Cruz 		return -EPERM;
1201ac9da0e0SDiego Santa Cruz 	}
1202ac9da0e0SDiego Santa Cruz 
1203ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
1204ac9da0e0SDiego Santa Cruz 		return 0;
1205ac9da0e0SDiego Santa Cruz 
1206ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
1207ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
1208ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1209ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1210ac9da0e0SDiego Santa Cruz 
1211ac9da0e0SDiego Santa Cruz 		if (err)
1212ac9da0e0SDiego Santa Cruz 			return err;
1213ac9da0e0SDiego Santa Cruz 
1214ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1215ac9da0e0SDiego Santa Cruz 
1216ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
1217ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
1218ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1219ac9da0e0SDiego Santa Cruz 
1220ac9da0e0SDiego Santa Cruz 	}
1221ac9da0e0SDiego Santa Cruz 
1222ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
1223ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
1224ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1225ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
1226ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
1227ac9da0e0SDiego Santa Cruz 		if (err)
1228ac9da0e0SDiego Santa Cruz 			return err;
1229ac9da0e0SDiego Santa Cruz 	}
1230ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
1231ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1232ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
1233ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
1234ac9da0e0SDiego Santa Cruz 		if (err)
1235ac9da0e0SDiego Santa Cruz 			return err;
1236ac9da0e0SDiego Santa Cruz 	}
1237ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1238ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
1239ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1240ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
1241ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
1242ac9da0e0SDiego Santa Cruz 			if (err)
1243ac9da0e0SDiego Santa Cruz 				return err;
1244ac9da0e0SDiego Santa Cruz 		}
1245ac9da0e0SDiego Santa Cruz 	}
1246ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1247ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
1248ac9da0e0SDiego Santa Cruz 	if (err)
1249ac9da0e0SDiego Santa Cruz 		return err;
1250ac9da0e0SDiego Santa Cruz 
1251ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
1252ac9da0e0SDiego Santa Cruz 		return 0;
1253ac9da0e0SDiego Santa Cruz 
12548dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
12558dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
12568dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
12578dda5b0eSDiego Santa Cruz 	 * partitioning. */
12588dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
12598dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
12608dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
12618dda5b0eSDiego Santa Cruz 		if (err)
12628dda5b0eSDiego Santa Cruz 			return err;
12638dda5b0eSDiego Santa Cruz 	}
12648dda5b0eSDiego Santa Cruz 
1265ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
1266ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
1267ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
1268ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
1269ac9da0e0SDiego Santa Cruz 
1270ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1271ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
1272ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
1273ac9da0e0SDiego Santa Cruz 	if (err)
1274ac9da0e0SDiego Santa Cruz 		return err;
1275ac9da0e0SDiego Santa Cruz 
1276ac9da0e0SDiego Santa Cruz 	return 0;
1277ac9da0e0SDiego Santa Cruz }
1278ac9da0e0SDiego Santa Cruz 
1279e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
128048972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
128148972d90SThierry Reding {
128248972d90SThierry Reding 	int cd;
128348972d90SThierry Reding 
128448972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
128548972d90SThierry Reding 
1286d4e1da4eSPeter Korsgaard 	if (cd < 0) {
128793bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
128893bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
1289d4e1da4eSPeter Korsgaard 		else
1290d4e1da4eSPeter Korsgaard 			cd = 1;
1291d4e1da4eSPeter Korsgaard 	}
129248972d90SThierry Reding 
129348972d90SThierry Reding 	return cd;
129448972d90SThierry Reding }
12958ca51e51SSimon Glass #endif
129648972d90SThierry Reding 
1297fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
1298272cc70bSAndy Fleming {
1299272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1300272cc70bSAndy Fleming 	struct mmc_data data;
1301272cc70bSAndy Fleming 
1302272cc70bSAndy Fleming 	/* Switch the frequency */
1303272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
1304272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1305272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
1306272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
1307272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
1308272cc70bSAndy Fleming 
1309272cc70bSAndy Fleming 	data.dest = (char *)resp;
1310272cc70bSAndy Fleming 	data.blocksize = 64;
1311272cc70bSAndy Fleming 	data.blocks = 1;
1312272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1313272cc70bSAndy Fleming 
1314272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
1315272cc70bSAndy Fleming }
1316272cc70bSAndy Fleming 
1317272cc70bSAndy Fleming 
1318fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
1319272cc70bSAndy Fleming {
1320272cc70bSAndy Fleming 	int err;
1321272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1322f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
1323f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
1324272cc70bSAndy Fleming 	struct mmc_data data;
1325272cc70bSAndy Fleming 	int timeout;
1326272cc70bSAndy Fleming 
1327272cc70bSAndy Fleming 	mmc->card_caps = 0;
1328272cc70bSAndy Fleming 
1329d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
1330d52ebf10SThomas Chou 		return 0;
1331d52ebf10SThomas Chou 
1332272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
1333272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
1334272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1335272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1336272cc70bSAndy Fleming 
1337272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1338272cc70bSAndy Fleming 
1339272cc70bSAndy Fleming 	if (err)
1340272cc70bSAndy Fleming 		return err;
1341272cc70bSAndy Fleming 
1342272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
1343272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1344272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1345272cc70bSAndy Fleming 
1346272cc70bSAndy Fleming 	timeout = 3;
1347272cc70bSAndy Fleming 
1348272cc70bSAndy Fleming retry_scr:
1349f781dd38SAnton staaf 	data.dest = (char *)scr;
1350272cc70bSAndy Fleming 	data.blocksize = 8;
1351272cc70bSAndy Fleming 	data.blocks = 1;
1352272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1353272cc70bSAndy Fleming 
1354272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
1355272cc70bSAndy Fleming 
1356272cc70bSAndy Fleming 	if (err) {
1357272cc70bSAndy Fleming 		if (timeout--)
1358272cc70bSAndy Fleming 			goto retry_scr;
1359272cc70bSAndy Fleming 
1360272cc70bSAndy Fleming 		return err;
1361272cc70bSAndy Fleming 	}
1362272cc70bSAndy Fleming 
13634e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
13644e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
1365272cc70bSAndy Fleming 
1366272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
1367272cc70bSAndy Fleming 	case 0:
1368272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1369272cc70bSAndy Fleming 		break;
1370272cc70bSAndy Fleming 	case 1:
1371272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
1372272cc70bSAndy Fleming 		break;
1373272cc70bSAndy Fleming 	case 2:
1374272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
13751741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
13761741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
1377272cc70bSAndy Fleming 		break;
1378272cc70bSAndy Fleming 	default:
1379272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1380272cc70bSAndy Fleming 		break;
1381272cc70bSAndy Fleming 	}
1382272cc70bSAndy Fleming 
1383b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1384b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1385b44c7083SAlagu Sankar 
1386272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1387272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1388272cc70bSAndy Fleming 		return 0;
1389272cc70bSAndy Fleming 
1390272cc70bSAndy Fleming 	timeout = 4;
1391272cc70bSAndy Fleming 	while (timeout--) {
1392272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1393f781dd38SAnton staaf 				(u8 *)switch_status);
1394272cc70bSAndy Fleming 
1395272cc70bSAndy Fleming 		if (err)
1396272cc70bSAndy Fleming 			return err;
1397272cc70bSAndy Fleming 
1398272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
13994e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1400272cc70bSAndy Fleming 			break;
1401272cc70bSAndy Fleming 	}
1402272cc70bSAndy Fleming 
1403272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
14044e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
1405272cc70bSAndy Fleming 		return 0;
1406272cc70bSAndy Fleming 
14072c3fbf4cSMacpaul Lin 	/*
14082c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
14092c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
14102c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
14112c3fbf4cSMacpaul Lin 	 * mode between the host.
14122c3fbf4cSMacpaul Lin 	 */
141393bfd616SPantelis Antoniou 	if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
141493bfd616SPantelis Antoniou 		(mmc->cfg->host_caps & MMC_MODE_HS)))
14152c3fbf4cSMacpaul Lin 		return 0;
14162c3fbf4cSMacpaul Lin 
1417f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
1418272cc70bSAndy Fleming 
1419272cc70bSAndy Fleming 	if (err)
1420272cc70bSAndy Fleming 		return err;
1421272cc70bSAndy Fleming 
14224e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
1423272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
1424272cc70bSAndy Fleming 
1425272cc70bSAndy Fleming 	return 0;
1426272cc70bSAndy Fleming }
1427272cc70bSAndy Fleming 
14283697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
14293697e599SPeng Fan {
14303697e599SPeng Fan 	int err, i;
14313697e599SPeng Fan 	struct mmc_cmd cmd;
14323697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
14333697e599SPeng Fan 	struct mmc_data data;
14343697e599SPeng Fan 	int timeout = 3;
14353697e599SPeng Fan 	unsigned int au, eo, et, es;
14363697e599SPeng Fan 
14373697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
14383697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
14393697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
14403697e599SPeng Fan 
14413697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
14423697e599SPeng Fan 	if (err)
14433697e599SPeng Fan 		return err;
14443697e599SPeng Fan 
14453697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
14463697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
14473697e599SPeng Fan 	cmd.cmdarg = 0;
14483697e599SPeng Fan 
14493697e599SPeng Fan retry_ssr:
14503697e599SPeng Fan 	data.dest = (char *)ssr;
14513697e599SPeng Fan 	data.blocksize = 64;
14523697e599SPeng Fan 	data.blocks = 1;
14533697e599SPeng Fan 	data.flags = MMC_DATA_READ;
14543697e599SPeng Fan 
14553697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
14563697e599SPeng Fan 	if (err) {
14573697e599SPeng Fan 		if (timeout--)
14583697e599SPeng Fan 			goto retry_ssr;
14593697e599SPeng Fan 
14603697e599SPeng Fan 		return err;
14613697e599SPeng Fan 	}
14623697e599SPeng Fan 
14633697e599SPeng Fan 	for (i = 0; i < 16; i++)
14643697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
14653697e599SPeng Fan 
14663697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
14673697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
14683697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
14693697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
14703697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
14713697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
14723697e599SPeng Fan 		if (es && et) {
14733697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
14743697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
14753697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
14763697e599SPeng Fan 		}
14773697e599SPeng Fan 	} else {
14783697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
14793697e599SPeng Fan 	}
14803697e599SPeng Fan 
14813697e599SPeng Fan 	return 0;
14823697e599SPeng Fan }
14833697e599SPeng Fan 
1484272cc70bSAndy Fleming /* frequency bases */
1485272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
14865f837c2cSMike Frysinger static const int fbase[] = {
1487272cc70bSAndy Fleming 	10000,
1488272cc70bSAndy Fleming 	100000,
1489272cc70bSAndy Fleming 	1000000,
1490272cc70bSAndy Fleming 	10000000,
1491272cc70bSAndy Fleming };
1492272cc70bSAndy Fleming 
1493272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1494272cc70bSAndy Fleming  * to platforms without floating point.
1495272cc70bSAndy Fleming  */
149661fe076fSSimon Glass static const u8 multipliers[] = {
1497272cc70bSAndy Fleming 	0,	/* reserved */
1498272cc70bSAndy Fleming 	10,
1499272cc70bSAndy Fleming 	12,
1500272cc70bSAndy Fleming 	13,
1501272cc70bSAndy Fleming 	15,
1502272cc70bSAndy Fleming 	20,
1503272cc70bSAndy Fleming 	25,
1504272cc70bSAndy Fleming 	30,
1505272cc70bSAndy Fleming 	35,
1506272cc70bSAndy Fleming 	40,
1507272cc70bSAndy Fleming 	45,
1508272cc70bSAndy Fleming 	50,
1509272cc70bSAndy Fleming 	55,
1510272cc70bSAndy Fleming 	60,
1511272cc70bSAndy Fleming 	70,
1512272cc70bSAndy Fleming 	80,
1513272cc70bSAndy Fleming };
1514272cc70bSAndy Fleming 
1515e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1516fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
1517272cc70bSAndy Fleming {
151893bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
151993bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
1520272cc70bSAndy Fleming }
1521ad77484aSZiyuan Xu 
1522ad77484aSZiyuan Xu static bool mmc_card_busy(struct mmc *mmc)
1523ad77484aSZiyuan Xu {
1524ad77484aSZiyuan Xu 	if (!mmc->cfg->ops->card_busy)
1525ad77484aSZiyuan Xu 		return -ENOSYS;
1526ad77484aSZiyuan Xu 
1527ad77484aSZiyuan Xu 	return mmc->cfg->ops->card_busy(mmc);
1528ad77484aSZiyuan Xu }
1529ad77484aSZiyuan Xu 
1530ad77484aSZiyuan Xu static bool mmc_can_card_busy(struct mmc *)
1531ad77484aSZiyuan Xu {
1532ad77484aSZiyuan Xu 	return !!mmc->cfg->ops->card_busy;
1533ad77484aSZiyuan Xu }
15348ca51e51SSimon Glass #endif
1535272cc70bSAndy Fleming 
1536fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1537272cc70bSAndy Fleming {
1538f866a46dSStephen Warren 	int err, i;
15393e3ff0acSZiyuan Xu 	uint mult, freq, tran_speed;
1540639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
1541272cc70bSAndy Fleming 	struct mmc_cmd cmd;
15428bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
15430c453bb7SDiego Santa Cruz 	bool has_parts = false;
15448a0cf490SDiego Santa Cruz 	bool part_completed;
1545c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1546272cc70bSAndy Fleming 
1547d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1548d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1549d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1550d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1551d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1552d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1553d52ebf10SThomas Chou 
1554d52ebf10SThomas Chou 		if (err)
1555d52ebf10SThomas Chou 			return err;
1556d52ebf10SThomas Chou 	}
1557d52ebf10SThomas Chou #endif
1558d52ebf10SThomas Chou 
1559272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1560d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1561d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1562272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1563272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1564272cc70bSAndy Fleming 
1565272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1566272cc70bSAndy Fleming 
1567272cc70bSAndy Fleming 	if (err)
1568272cc70bSAndy Fleming 		return err;
1569272cc70bSAndy Fleming 
1570272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1571272cc70bSAndy Fleming 
1572272cc70bSAndy Fleming 	/*
1573272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1574272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1575272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1576272cc70bSAndy Fleming 	 */
1577d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1578272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1579272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1580272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1581272cc70bSAndy Fleming 
1582272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1583272cc70bSAndy Fleming 
1584272cc70bSAndy Fleming 		if (err)
1585272cc70bSAndy Fleming 			return err;
1586272cc70bSAndy Fleming 
1587272cc70bSAndy Fleming 		if (IS_SD(mmc))
1588998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1589d52ebf10SThomas Chou 	}
1590272cc70bSAndy Fleming 
1591272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1592272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1593272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1594272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1595272cc70bSAndy Fleming 
1596272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1597272cc70bSAndy Fleming 
1598272cc70bSAndy Fleming 	if (err)
1599272cc70bSAndy Fleming 		return err;
1600272cc70bSAndy Fleming 
1601998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1602998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1603998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1604998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1605272cc70bSAndy Fleming 
1606272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
16070b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1608272cc70bSAndy Fleming 
1609272cc70bSAndy Fleming 		switch (version) {
1610272cc70bSAndy Fleming 		case 0:
1611272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1612272cc70bSAndy Fleming 			break;
1613272cc70bSAndy Fleming 		case 1:
1614272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1615272cc70bSAndy Fleming 			break;
1616272cc70bSAndy Fleming 		case 2:
1617272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1618272cc70bSAndy Fleming 			break;
1619272cc70bSAndy Fleming 		case 3:
1620272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1621272cc70bSAndy Fleming 			break;
1622272cc70bSAndy Fleming 		case 4:
1623272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1624272cc70bSAndy Fleming 			break;
1625272cc70bSAndy Fleming 		default:
1626272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1627272cc70bSAndy Fleming 			break;
1628272cc70bSAndy Fleming 		}
1629272cc70bSAndy Fleming 	}
1630272cc70bSAndy Fleming 
1631272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
16320b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
16330b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1634272cc70bSAndy Fleming 
16353e3ff0acSZiyuan Xu 	tran_speed = freq * mult;
1636272cc70bSAndy Fleming 
1637ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1638998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1639272cc70bSAndy Fleming 
1640272cc70bSAndy Fleming 	if (IS_SD(mmc))
1641272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1642272cc70bSAndy Fleming 	else
1643998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1644272cc70bSAndy Fleming 
1645272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1646272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1647272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1648272cc70bSAndy Fleming 		cmult = 8;
1649272cc70bSAndy Fleming 	} else {
1650272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1651272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1652272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1653272cc70bSAndy Fleming 	}
1654272cc70bSAndy Fleming 
1655f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1656f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1657f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1658f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1659f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1660f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1661272cc70bSAndy Fleming 
16628bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
16638bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1664272cc70bSAndy Fleming 
16658bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
16668bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1667272cc70bSAndy Fleming 
1668ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1669ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1670ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1671ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1672ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1673ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1674ab71188cSMarkus Niebel 	}
1675ab71188cSMarkus Niebel 
1676272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1677d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1678272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1679fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1680272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1681272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1682272cc70bSAndy Fleming 
1683272cc70bSAndy Fleming 		if (err)
1684272cc70bSAndy Fleming 			return err;
1685d52ebf10SThomas Chou 	}
1686272cc70bSAndy Fleming 
1687e6f99a56SLei Wen 	/*
1688e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1689e6f99a56SLei Wen 	 */
1690e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1691bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1692d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
1693d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
1694d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
16959cf199ebSDiego Santa Cruz 		if (err)
16969cf199ebSDiego Santa Cruz 			return err;
16979cf199ebSDiego Santa Cruz 		if (ext_csd[EXT_CSD_REV] >= 2) {
1698639b7827SYoshihiro Shimoda 			/*
1699639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
1700639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
1701639b7827SYoshihiro Shimoda 			 * than 2GB
1702639b7827SYoshihiro Shimoda 			 */
17030560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
17040560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
17050560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
17060560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
17078bfa195eSSimon Glass 			capacity *= MMC_MAX_BLOCK_LEN;
1708b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
1709f866a46dSStephen Warren 				mmc->capacity_user = capacity;
1710d23e2c09SSukumar Ghorai 		}
1711bc897b1dSLei Wen 
171264f4a619SJaehoon Chung 		switch (ext_csd[EXT_CSD_REV]) {
171364f4a619SJaehoon Chung 		case 1:
171464f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_1;
171564f4a619SJaehoon Chung 			break;
171664f4a619SJaehoon Chung 		case 2:
171764f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_2;
171864f4a619SJaehoon Chung 			break;
171964f4a619SJaehoon Chung 		case 3:
172064f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_3;
172164f4a619SJaehoon Chung 			break;
172264f4a619SJaehoon Chung 		case 5:
172364f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_41;
172464f4a619SJaehoon Chung 			break;
172564f4a619SJaehoon Chung 		case 6:
172664f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_5;
172764f4a619SJaehoon Chung 			break;
1728edab723bSMarkus Niebel 		case 7:
1729edab723bSMarkus Niebel 			mmc->version = MMC_VERSION_5_0;
1730edab723bSMarkus Niebel 			break;
17311a3619cfSStefan Wahren 		case 8:
17321a3619cfSStefan Wahren 			mmc->version = MMC_VERSION_5_1;
17331a3619cfSStefan Wahren 			break;
173464f4a619SJaehoon Chung 		}
173564f4a619SJaehoon Chung 
17368a0cf490SDiego Santa Cruz 		/* The partition data may be non-zero but it is only
17378a0cf490SDiego Santa Cruz 		 * effective if PARTITION_SETTING_COMPLETED is set in
17388a0cf490SDiego Santa Cruz 		 * EXT_CSD, so ignore any data if this bit is not set,
17398a0cf490SDiego Santa Cruz 		 * except for enabling the high-capacity group size
17408a0cf490SDiego Santa Cruz 		 * definition (see below). */
17418a0cf490SDiego Santa Cruz 		part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
17428a0cf490SDiego Santa Cruz 				    EXT_CSD_PARTITION_SETTING_COMPLETED);
17438a0cf490SDiego Santa Cruz 
17440c453bb7SDiego Santa Cruz 		/* store the partition info of emmc */
17450c453bb7SDiego Santa Cruz 		mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
17460c453bb7SDiego Santa Cruz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
17470c453bb7SDiego Santa Cruz 		    ext_csd[EXT_CSD_BOOT_MULT])
17480c453bb7SDiego Santa Cruz 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
17498a0cf490SDiego Santa Cruz 		if (part_completed &&
17508a0cf490SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
17510c453bb7SDiego Santa Cruz 			mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
1752a6a1f5f8SJason Zhu 		if (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] & EXT_CSD_SEC_GB_CL_EN)
1753a6a1f5f8SJason Zhu 			mmc->esr.mmc_can_trim = 1;
17540c453bb7SDiego Santa Cruz 
17550c453bb7SDiego Santa Cruz 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
17560c453bb7SDiego Santa Cruz 
17570c453bb7SDiego Santa Cruz 		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
17580c453bb7SDiego Santa Cruz 
17590c453bb7SDiego Santa Cruz 		for (i = 0; i < 4; i++) {
17600c453bb7SDiego Santa Cruz 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
17618a0cf490SDiego Santa Cruz 			uint mult = (ext_csd[idx + 2] << 16) +
17620c453bb7SDiego Santa Cruz 				(ext_csd[idx + 1] << 8) + ext_csd[idx];
17638a0cf490SDiego Santa Cruz 			if (mult)
17648a0cf490SDiego Santa Cruz 				has_parts = true;
17658a0cf490SDiego Santa Cruz 			if (!part_completed)
17668a0cf490SDiego Santa Cruz 				continue;
17678a0cf490SDiego Santa Cruz 			mmc->capacity_gp[i] = mult;
17680c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *=
17690c453bb7SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
17700c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1771f8e89d67SDiego Santa Cruz 			mmc->capacity_gp[i] <<= 19;
17720c453bb7SDiego Santa Cruz 		}
17730c453bb7SDiego Santa Cruz 
17748a0cf490SDiego Santa Cruz 		if (part_completed) {
1775a7f852b6SDiego Santa Cruz 			mmc->enh_user_size =
1776a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
1777a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
1778a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_SIZE_MULT];
1779a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1780a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1781a7f852b6SDiego Santa Cruz 			mmc->enh_user_size <<= 19;
1782a7f852b6SDiego Santa Cruz 			mmc->enh_user_start =
1783a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
1784a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
1785a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
1786a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_START_ADDR];
1787a7f852b6SDiego Santa Cruz 			if (mmc->high_capacity)
1788a7f852b6SDiego Santa Cruz 				mmc->enh_user_start <<= 9;
17898a0cf490SDiego Santa Cruz 		}
1790a7f852b6SDiego Santa Cruz 
1791e6f99a56SLei Wen 		/*
17921937e5aaSOliver Metz 		 * Host needs to enable ERASE_GRP_DEF bit if device is
17931937e5aaSOliver Metz 		 * partitioned. This bit will be lost every time after a reset
17941937e5aaSOliver Metz 		 * or power off. This will affect erase size.
1795e6f99a56SLei Wen 		 */
17968a0cf490SDiego Santa Cruz 		if (part_completed)
17970c453bb7SDiego Santa Cruz 			has_parts = true;
17981937e5aaSOliver Metz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
17990c453bb7SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
18000c453bb7SDiego Santa Cruz 			has_parts = true;
18010c453bb7SDiego Santa Cruz 		if (has_parts) {
18021937e5aaSOliver Metz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
18031937e5aaSOliver Metz 				EXT_CSD_ERASE_GROUP_DEF, 1);
18041937e5aaSOliver Metz 
18051937e5aaSOliver Metz 			if (err)
18061937e5aaSOliver Metz 				return err;
1807021a8055SHannes Petermaier 			else
1808021a8055SHannes Petermaier 				ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1809037dc0abSDiego Santa Cruz 		}
18101937e5aaSOliver Metz 
1811037dc0abSDiego Santa Cruz 		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
18121937e5aaSOliver Metz 			/* Read out group size from ext_csd */
18130560db18SLei Wen 			mmc->erase_grp_size =
1814a4ff9f83SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1815d7b29129SMarkus Niebel 			/*
1816d7b29129SMarkus Niebel 			 * if high capacity and partition setting completed
1817d7b29129SMarkus Niebel 			 * SEC_COUNT is valid even if it is smaller than 2 GiB
1818d7b29129SMarkus Niebel 			 * JEDEC Standard JESD84-B45, 6.2.4
1819d7b29129SMarkus Niebel 			 */
18208a0cf490SDiego Santa Cruz 			if (mmc->high_capacity && part_completed) {
1821d7b29129SMarkus Niebel 				capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1822d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1823d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1824d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1825d7b29129SMarkus Niebel 				capacity *= MMC_MAX_BLOCK_LEN;
1826d7b29129SMarkus Niebel 				mmc->capacity_user = capacity;
1827d7b29129SMarkus Niebel 			}
18288bfa195eSSimon Glass 		} else {
18291937e5aaSOliver Metz 			/* Calculate the group size from the csd value. */
1830e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
1831e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1832e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1833e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
1834e6f99a56SLei Wen 				* (erase_gmul + 1);
1835e6f99a56SLei Wen 		}
1836037dc0abSDiego Santa Cruz 
1837037dc0abSDiego Santa Cruz 		mmc->hc_wp_grp_size = 1024
1838037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1839037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
18409e41a00bSDiego Santa Cruz 
18419e41a00bSDiego Santa Cruz 		mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1842f866a46dSStephen Warren 	}
1843f866a46dSStephen Warren 
1844c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
1845f866a46dSStephen Warren 	if (err)
1846f866a46dSStephen Warren 		return err;
1847d23e2c09SSukumar Ghorai 
1848272cc70bSAndy Fleming 	if (IS_SD(mmc))
1849272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1850272cc70bSAndy Fleming 	else
1851272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1852272cc70bSAndy Fleming 
1853272cc70bSAndy Fleming 	if (err)
1854272cc70bSAndy Fleming 		return err;
1855272cc70bSAndy Fleming 
1856272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
185793bfd616SPantelis Antoniou 	mmc->card_caps &= mmc->cfg->host_caps;
1858272cc70bSAndy Fleming 
1859272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1860272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1861272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1862272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1863272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1864272cc70bSAndy Fleming 
1865272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1866272cc70bSAndy Fleming 			if (err)
1867272cc70bSAndy Fleming 				return err;
1868272cc70bSAndy Fleming 
1869272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1870272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1871272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1872272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1873272cc70bSAndy Fleming 			if (err)
1874272cc70bSAndy Fleming 				return err;
1875272cc70bSAndy Fleming 
1876272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1877272cc70bSAndy Fleming 		}
1878272cc70bSAndy Fleming 
18793697e599SPeng Fan 		err = sd_read_ssr(mmc);
18803697e599SPeng Fan 		if (err)
18813697e599SPeng Fan 			return err;
18823697e599SPeng Fan 
1883272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
18843e3ff0acSZiyuan Xu 			tran_speed = 50000000;
1885272cc70bSAndy Fleming 		else
18863e3ff0acSZiyuan Xu 			tran_speed = 25000000;
1887ad5fd922SJaehoon Chung 
18883e3ff0acSZiyuan Xu 		mmc_set_clock(mmc, tran_speed);
188949dba033SZiyuan Xu 	}
1890272cc70bSAndy Fleming 
18915af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
189249dba033SZiyuan Xu 	if (mmc_card_ddr(mmc)) {
18935af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
18945af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
18955af8f45cSAndrew Gabbasov 	}
18965af8f45cSAndrew Gabbasov 
1897272cc70bSAndy Fleming 	/* fill in device description */
1898c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1899c40fdca6SSimon Glass 	bdesc->lun = 0;
1900c40fdca6SSimon Glass 	bdesc->hwpart = 0;
1901c40fdca6SSimon Glass 	bdesc->type = 0;
1902c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
1903c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
1904c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1905fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1906fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1907fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1908c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
1909babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1910babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1911c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
19120b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1913babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1914babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1915c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1916babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
191756196826SPaul Burton #else
1918c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
1919c40fdca6SSimon Glass 	bdesc->product[0] = 0;
1920c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
192156196826SPaul Burton #endif
1922122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1923c40fdca6SSimon Glass 	part_init(bdesc);
1924122efd43SMikhail Kshevetskiy #endif
1925272cc70bSAndy Fleming 
1926272cc70bSAndy Fleming 	return 0;
1927272cc70bSAndy Fleming }
1928272cc70bSAndy Fleming 
1929fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1930272cc70bSAndy Fleming {
1931272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1932272cc70bSAndy Fleming 	int err;
1933272cc70bSAndy Fleming 
1934272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1935272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
193693bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1937272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1938272cc70bSAndy Fleming 
1939272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1940272cc70bSAndy Fleming 
1941272cc70bSAndy Fleming 	if (err)
1942272cc70bSAndy Fleming 		return err;
1943272cc70bSAndy Fleming 
1944998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1945915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
1946272cc70bSAndy Fleming 	else
1947272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1948272cc70bSAndy Fleming 
1949272cc70bSAndy Fleming 	return 0;
1950272cc70bSAndy Fleming }
1951272cc70bSAndy Fleming 
1952c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
195395de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
195495de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
195595de9ab2SPaul Kocialkowski {
195695de9ab2SPaul Kocialkowski }
195705cbeb7cSSimon Glass #endif
195895de9ab2SPaul Kocialkowski 
19592051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
19602051aefeSPeng Fan {
1961c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
196205cbeb7cSSimon Glass #if defined(CONFIG_DM_REGULATOR) && !defined(CONFIG_SPL_BUILD)
19632051aefeSPeng Fan 	struct udevice *vmmc_supply;
19642051aefeSPeng Fan 	int ret;
19652051aefeSPeng Fan 
19662051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
19672051aefeSPeng Fan 					  &vmmc_supply);
19682051aefeSPeng Fan 	if (ret) {
1969288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
19702051aefeSPeng Fan 		return 0;
19712051aefeSPeng Fan 	}
19722051aefeSPeng Fan 
19732051aefeSPeng Fan 	ret = regulator_set_enable(vmmc_supply, true);
19742051aefeSPeng Fan 	if (ret) {
19752051aefeSPeng Fan 		puts("Error enabling VMMC supply\n");
19762051aefeSPeng Fan 		return ret;
19772051aefeSPeng Fan 	}
19782051aefeSPeng Fan #endif
197905cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
198005cbeb7cSSimon Glass 	/*
198105cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
198205cbeb7cSSimon Glass 	 * out to board code.
198305cbeb7cSSimon Glass 	 */
198405cbeb7cSSimon Glass 	board_mmc_power_init();
198505cbeb7cSSimon Glass #endif
19862051aefeSPeng Fan 	return 0;
19872051aefeSPeng Fan }
19882051aefeSPeng Fan 
1989e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1990272cc70bSAndy Fleming {
19918ca51e51SSimon Glass 	bool no_card;
1992afd5932bSMacpaul Lin 	int err;
1993272cc70bSAndy Fleming 
1994ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
19958ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
1996e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
19978ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
19988ca51e51SSimon Glass #endif
19998ca51e51SSimon Glass 	if (no_card) {
200048972d90SThierry Reding 		mmc->has_init = 0;
200156196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
200248972d90SThierry Reding 		printf("MMC: no card present\n");
200356196826SPaul Burton #endif
2004915ffa52SJaehoon Chung 		return -ENOMEDIUM;
200548972d90SThierry Reding 	}
200648972d90SThierry Reding 
2007bc897b1dSLei Wen 	if (mmc->has_init)
2008bc897b1dSLei Wen 		return 0;
2009bc897b1dSLei Wen 
20105a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
20115a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
20125a8dbdc6SYangbo Lu #endif
20132051aefeSPeng Fan 	err = mmc_power_init(mmc);
20142051aefeSPeng Fan 	if (err)
20152051aefeSPeng Fan 		return err;
201695de9ab2SPaul Kocialkowski 
2017e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
20188ca51e51SSimon Glass 	/* The device has already been probed ready for use */
20198ca51e51SSimon Glass #else
2020ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
202193bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
2022272cc70bSAndy Fleming 	if (err)
2023272cc70bSAndy Fleming 		return err;
20248ca51e51SSimon Glass #endif
2025b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
2026b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
202781db2d36SZiyuan Xu 	mmc_set_timing(mmc, MMC_TIMING_LEGACY);
2028b86b85e2SIlya Yanok 
2029272cc70bSAndy Fleming 	/* Reset the Card */
2030272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
2031272cc70bSAndy Fleming 
2032272cc70bSAndy Fleming 	if (err)
2033272cc70bSAndy Fleming 		return err;
2034272cc70bSAndy Fleming 
2035bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
2036c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
2037bc897b1dSLei Wen 
2038272cc70bSAndy Fleming 	/* Test for SD version 2 */
2039272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
2040272cc70bSAndy Fleming 
2041272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
2042272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
2043272cc70bSAndy Fleming 
2044272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
2045915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
2046272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
2047272cc70bSAndy Fleming 
2048bd47c135SAndrew Gabbasov 		if (err) {
204956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2050272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
205156196826SPaul Burton #endif
2052915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
2053272cc70bSAndy Fleming 		}
2054272cc70bSAndy Fleming 	}
2055272cc70bSAndy Fleming 
2056bd47c135SAndrew Gabbasov 	if (!err)
2057e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
2058e9550449SChe-Liang Chiou 
2059e9550449SChe-Liang Chiou 	return err;
2060e9550449SChe-Liang Chiou }
2061e9550449SChe-Liang Chiou 
2062e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2063e9550449SChe-Liang Chiou {
2064e9550449SChe-Liang Chiou 	int err = 0;
2065e9550449SChe-Liang Chiou 
2066bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
2067e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
2068e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
2069e9550449SChe-Liang Chiou 
2070e9550449SChe-Liang Chiou 	if (!err)
2071bc897b1dSLei Wen 		err = mmc_startup(mmc);
2072bc897b1dSLei Wen 	if (err)
2073bc897b1dSLei Wen 		mmc->has_init = 0;
2074bc897b1dSLei Wen 	else
2075bc897b1dSLei Wen 		mmc->has_init = 1;
2076e9550449SChe-Liang Chiou 	return err;
2077e9550449SChe-Liang Chiou }
2078e9550449SChe-Liang Chiou 
2079e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2080e9550449SChe-Liang Chiou {
2081bd47c135SAndrew Gabbasov 	int err = 0;
2082ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
2083c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
208433fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2085e9550449SChe-Liang Chiou 
208633fb211dSSimon Glass 	upriv->mmc = mmc;
208733fb211dSSimon Glass #endif
2088e9550449SChe-Liang Chiou 	if (mmc->has_init)
2089e9550449SChe-Liang Chiou 		return 0;
2090d803fea5SMateusz Zalega 
2091d803fea5SMateusz Zalega 	start = get_timer(0);
2092d803fea5SMateusz Zalega 
2093e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2094e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2095e9550449SChe-Liang Chiou 
2096bd47c135SAndrew Gabbasov 	if (!err)
2097e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2098919b4858SJagan Teki 	if (err)
2099919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
2100919b4858SJagan Teki 
2101bc897b1dSLei Wen 	return err;
2102272cc70bSAndy Fleming }
2103272cc70bSAndy Fleming 
2104ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2105ab71188cSMarkus Niebel {
2106ab71188cSMarkus Niebel 	mmc->dsr = val;
2107ab71188cSMarkus Niebel 	return 0;
2108ab71188cSMarkus Niebel }
2109ab71188cSMarkus Niebel 
2110cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2111cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2112272cc70bSAndy Fleming {
2113272cc70bSAndy Fleming 	return -1;
2114272cc70bSAndy Fleming }
2115272cc70bSAndy Fleming 
2116cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2117cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2118cee9ab7cSJeroen Hofstee {
2119cee9ab7cSJeroen Hofstee 	return -1;
2120cee9ab7cSJeroen Hofstee }
2121272cc70bSAndy Fleming 
2122e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2123e9550449SChe-Liang Chiou {
2124e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2125e9550449SChe-Liang Chiou }
2126e9550449SChe-Liang Chiou 
2127c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
21288e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
21298e3332e2SSjoerd Simons {
21308e3332e2SSjoerd Simons 	return 0;
21318e3332e2SSjoerd Simons }
2132c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
21338e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
21348e3332e2SSjoerd Simons {
21354a1db6d8SSimon Glass 	int ret, i;
21368e3332e2SSjoerd Simons 	struct uclass *uc;
21374a1db6d8SSimon Glass 	struct udevice *dev;
21388e3332e2SSjoerd Simons 
21398e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
21408e3332e2SSjoerd Simons 	if (ret)
21418e3332e2SSjoerd Simons 		return ret;
21428e3332e2SSjoerd Simons 
21434a1db6d8SSimon Glass 	/*
21444a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
21454a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
21464a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
21474a1db6d8SSimon Glass 	 */
21484a1db6d8SSimon Glass 	for (i = 0; ; i++) {
21494a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
21504a1db6d8SSimon Glass 		if (ret == -ENODEV)
21514a1db6d8SSimon Glass 			break;
21524a1db6d8SSimon Glass 	}
21534a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
21544a1db6d8SSimon Glass 		ret = device_probe(dev);
21558e3332e2SSjoerd Simons 		if (ret)
21564a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
21578e3332e2SSjoerd Simons 	}
21588e3332e2SSjoerd Simons 
21598e3332e2SSjoerd Simons 	return 0;
21608e3332e2SSjoerd Simons }
21618e3332e2SSjoerd Simons #else
21628e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
21638e3332e2SSjoerd Simons {
21648e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
21658e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
21668e3332e2SSjoerd Simons 
21678e3332e2SSjoerd Simons 	return 0;
21688e3332e2SSjoerd Simons }
21698e3332e2SSjoerd Simons #endif
2170e9550449SChe-Liang Chiou 
2171272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2172272cc70bSAndy Fleming {
21731b26bab1SDaniel Kochmański 	static int initialized = 0;
21748e3332e2SSjoerd Simons 	int ret;
21751b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
21761b26bab1SDaniel Kochmański 		return 0;
21771b26bab1SDaniel Kochmański 	initialized = 1;
21781b26bab1SDaniel Kochmański 
2179c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2180b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2181c40fdca6SSimon Glass 	mmc_list_init();
2182c40fdca6SSimon Glass #endif
2183b5b838f1SMarek Vasut #endif
21848e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
21858e3332e2SSjoerd Simons 	if (ret)
21868e3332e2SSjoerd Simons 		return ret;
2187272cc70bSAndy Fleming 
2188bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2189272cc70bSAndy Fleming 	print_mmc_devices(',');
2190bb0dc108SYing Zhang #endif
2191272cc70bSAndy Fleming 
2192c40fdca6SSimon Glass 	mmc_do_preinit();
2193272cc70bSAndy Fleming 	return 0;
2194272cc70bSAndy Fleming }
2195cd3d4880STomas Melin 
2196cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2197cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2198cd3d4880STomas Melin {
2199cd3d4880STomas Melin 	int err;
2200cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2201cd3d4880STomas Melin 
2202cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2203cd3d4880STomas Melin 	if (err) {
2204cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2205cd3d4880STomas Melin 		return err;
2206cd3d4880STomas Melin 	}
2207cd3d4880STomas Melin 
2208cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2209cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2210cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2211cd3d4880STomas Melin 	}
2212cd3d4880STomas Melin 
2213cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2214cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2215cd3d4880STomas Melin 		return 0;
2216cd3d4880STomas Melin 	}
2217cd3d4880STomas Melin 
2218cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2219cd3d4880STomas Melin 	if (err) {
2220cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2221cd3d4880STomas Melin 		return err;
2222cd3d4880STomas Melin 	}
2223cd3d4880STomas Melin 
2224cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2225cd3d4880STomas Melin 
2226cd3d4880STomas Melin 	return 0;
2227cd3d4880STomas Melin }
2228cd3d4880STomas Melin #endif
2229