xref: /rk3399_rockchip-uboot/drivers/mmc/mmc.c (revision a6a1f5f85880c92c2c95b2ea76429e6aeff2379d)
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__);
3114a1a06bcSAlagu Sankar 			return 0;
31211692991SSimon Glass 		}
3134a1a06bcSAlagu Sankar 		blocks_todo -= cur;
3144a1a06bcSAlagu Sankar 		start += cur;
3154a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
3164a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
317272cc70bSAndy Fleming 
318272cc70bSAndy Fleming 	return blkcnt;
319272cc70bSAndy Fleming }
320272cc70bSAndy Fleming 
32149dba033SZiyuan Xu void mmc_set_clock(struct mmc *mmc, uint clock)
32249dba033SZiyuan Xu {
32349dba033SZiyuan Xu 	if (clock > mmc->cfg->f_max)
32449dba033SZiyuan Xu 		clock = mmc->cfg->f_max;
32549dba033SZiyuan Xu 
32649dba033SZiyuan Xu 	if (clock < mmc->cfg->f_min)
32749dba033SZiyuan Xu 		clock = mmc->cfg->f_min;
32849dba033SZiyuan Xu 
32949dba033SZiyuan Xu 	mmc->clock = clock;
33049dba033SZiyuan Xu 
33149dba033SZiyuan Xu 	mmc_set_ios(mmc);
33249dba033SZiyuan Xu }
33349dba033SZiyuan Xu 
33449dba033SZiyuan Xu static void mmc_set_bus_width(struct mmc *mmc, uint width)
33549dba033SZiyuan Xu {
33649dba033SZiyuan Xu 	mmc->bus_width = width;
33749dba033SZiyuan Xu 
33849dba033SZiyuan Xu 	mmc_set_ios(mmc);
33949dba033SZiyuan Xu }
34049dba033SZiyuan Xu 
34181db2d36SZiyuan Xu static void mmc_set_timing(struct mmc *mmc, uint timing)
34281db2d36SZiyuan Xu {
34381db2d36SZiyuan Xu 	mmc->timing = timing;
34481db2d36SZiyuan Xu 	mmc_set_ios(mmc);
34581db2d36SZiyuan Xu }
34681db2d36SZiyuan Xu 
347fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
348272cc70bSAndy Fleming {
349272cc70bSAndy Fleming 	struct mmc_cmd cmd;
350272cc70bSAndy Fleming 	int err;
351272cc70bSAndy Fleming 
352272cc70bSAndy Fleming 	udelay(1000);
353272cc70bSAndy Fleming 
354272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
355272cc70bSAndy Fleming 	cmd.cmdarg = 0;
356272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
357272cc70bSAndy Fleming 
358272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
359272cc70bSAndy Fleming 
360272cc70bSAndy Fleming 	if (err)
361272cc70bSAndy Fleming 		return err;
362272cc70bSAndy Fleming 
363272cc70bSAndy Fleming 	udelay(2000);
364272cc70bSAndy Fleming 
365272cc70bSAndy Fleming 	return 0;
366272cc70bSAndy Fleming }
367272cc70bSAndy Fleming 
368fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
369272cc70bSAndy Fleming {
370272cc70bSAndy Fleming 	int timeout = 1000;
371272cc70bSAndy Fleming 	int err;
372272cc70bSAndy Fleming 	struct mmc_cmd cmd;
373272cc70bSAndy Fleming 
3741677eef4SAndrew Gabbasov 	while (1) {
375272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
376272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
377272cc70bSAndy Fleming 		cmd.cmdarg = 0;
378272cc70bSAndy Fleming 
379272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
380272cc70bSAndy Fleming 
381272cc70bSAndy Fleming 		if (err)
382272cc70bSAndy Fleming 			return err;
383272cc70bSAndy Fleming 
384272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
385272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
386250de12bSStefano Babic 
387250de12bSStefano Babic 		/*
388250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
389250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
390250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
391250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
392250de12bSStefano Babic 		 * specified.
393250de12bSStefano Babic 		 */
394d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
39593bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
396272cc70bSAndy Fleming 
397272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
398272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
399272cc70bSAndy Fleming 
400272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
401272cc70bSAndy Fleming 
402272cc70bSAndy Fleming 		if (err)
403272cc70bSAndy Fleming 			return err;
404272cc70bSAndy Fleming 
4051677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
4061677eef4SAndrew Gabbasov 			break;
407272cc70bSAndy Fleming 
4081677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
409915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
410272cc70bSAndy Fleming 
4111677eef4SAndrew Gabbasov 		udelay(1000);
4121677eef4SAndrew Gabbasov 	}
4131677eef4SAndrew Gabbasov 
414272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
415272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
416272cc70bSAndy Fleming 
417d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
418d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
419d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
420d52ebf10SThomas Chou 		cmd.cmdarg = 0;
421d52ebf10SThomas Chou 
422d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
423d52ebf10SThomas Chou 
424d52ebf10SThomas Chou 		if (err)
425d52ebf10SThomas Chou 			return err;
426d52ebf10SThomas Chou 	}
427d52ebf10SThomas Chou 
428998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
429272cc70bSAndy Fleming 
430272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
431272cc70bSAndy Fleming 	mmc->rca = 0;
432272cc70bSAndy Fleming 
433272cc70bSAndy Fleming 	return 0;
434272cc70bSAndy Fleming }
435272cc70bSAndy Fleming 
4365289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
437272cc70bSAndy Fleming {
4385289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
439272cc70bSAndy Fleming 	int err;
440272cc70bSAndy Fleming 
4415289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
4425289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
4435289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
4445a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
4455a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
44693bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
447a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
448a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
449e9550449SChe-Liang Chiou 
4505289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
451e9550449SChe-Liang Chiou 	if (err)
452e9550449SChe-Liang Chiou 		return err;
4535289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
454e9550449SChe-Liang Chiou 	return 0;
455e9550449SChe-Liang Chiou }
456e9550449SChe-Liang Chiou 
457750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
458e9550449SChe-Liang Chiou {
459e9550449SChe-Liang Chiou 	int err, i;
460e9550449SChe-Liang Chiou 
461272cc70bSAndy Fleming 	/* Some cards seem to need this */
462272cc70bSAndy Fleming 	mmc_go_idle(mmc);
463272cc70bSAndy Fleming 
46431cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
465e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
4665289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
46731cacbabSRaffaele Recalcati 		if (err)
46831cacbabSRaffaele Recalcati 			return err;
46931cacbabSRaffaele Recalcati 
470e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
471a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
472bd47c135SAndrew Gabbasov 			break;
473e9550449SChe-Liang Chiou 	}
474bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
475bd47c135SAndrew Gabbasov 	return 0;
476e9550449SChe-Liang Chiou }
47731cacbabSRaffaele Recalcati 
478750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
479e9550449SChe-Liang Chiou {
480e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
481e9550449SChe-Liang Chiou 	int timeout = 1000;
482e9550449SChe-Liang Chiou 	uint start;
483e9550449SChe-Liang Chiou 	int err;
484e9550449SChe-Liang Chiou 
485e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
486cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
487d188b113SYangbo Lu 		/* Some cards seem to need this */
488d188b113SYangbo Lu 		mmc_go_idle(mmc);
489d188b113SYangbo Lu 
490e9550449SChe-Liang Chiou 		start = get_timer(0);
4911677eef4SAndrew Gabbasov 		while (1) {
4925289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
493272cc70bSAndy Fleming 			if (err)
494272cc70bSAndy Fleming 				return err;
4951677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
4961677eef4SAndrew Gabbasov 				break;
497e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
498915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
499e9550449SChe-Liang Chiou 			udelay(100);
5001677eef4SAndrew Gabbasov 		}
501cc17c01fSAndrew Gabbasov 	}
502272cc70bSAndy Fleming 
503d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
504d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
505d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
506d52ebf10SThomas Chou 		cmd.cmdarg = 0;
507d52ebf10SThomas Chou 
508d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
509d52ebf10SThomas Chou 
510d52ebf10SThomas Chou 		if (err)
511d52ebf10SThomas Chou 			return err;
512a626c8d4SAndrew Gabbasov 
513a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
514d52ebf10SThomas Chou 	}
515d52ebf10SThomas Chou 
516272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
517272cc70bSAndy Fleming 
518272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
519def816a2SStephen Warren 	mmc->rca = 1;
520272cc70bSAndy Fleming 
521272cc70bSAndy Fleming 	return 0;
522272cc70bSAndy Fleming }
523272cc70bSAndy Fleming 
524272cc70bSAndy Fleming 
525fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
526272cc70bSAndy Fleming {
527272cc70bSAndy Fleming 	struct mmc_cmd cmd;
528272cc70bSAndy Fleming 	struct mmc_data data;
529272cc70bSAndy Fleming 	int err;
530272cc70bSAndy Fleming 
531272cc70bSAndy Fleming 	/* Get the Card Status Register */
532272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
533272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
534272cc70bSAndy Fleming 	cmd.cmdarg = 0;
535272cc70bSAndy Fleming 
536cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
537272cc70bSAndy Fleming 	data.blocks = 1;
5388bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
539272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
540272cc70bSAndy Fleming 
541272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
542272cc70bSAndy Fleming 
543272cc70bSAndy Fleming 	return err;
544272cc70bSAndy Fleming }
545272cc70bSAndy Fleming 
54655e5defdSZiyuan Xu static int mmc_poll_for_busy(struct mmc *mmc)
547272cc70bSAndy Fleming {
548272cc70bSAndy Fleming 	struct mmc_cmd cmd;
54955e5defdSZiyuan Xu 	u8 busy = true;
55055e5defdSZiyuan Xu 	uint start;
55155e5defdSZiyuan Xu 	int ret;
5525d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
55355e5defdSZiyuan Xu 
55455e5defdSZiyuan Xu 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
55555e5defdSZiyuan Xu 	cmd.resp_type = MMC_RSP_R1;
55655e5defdSZiyuan Xu 	cmd.cmdarg = mmc->rca << 16;
55755e5defdSZiyuan Xu 
55855e5defdSZiyuan Xu 	start = get_timer(0);
55955e5defdSZiyuan Xu 
56055e5defdSZiyuan Xu 	do {
56155e5defdSZiyuan Xu 		if (mmc_can_card_busy(mmc)) {
56255e5defdSZiyuan Xu 			busy = mmc_card_busy(mmc);
56355e5defdSZiyuan Xu 		} else {
56455e5defdSZiyuan Xu 			ret = mmc_send_cmd(mmc, &cmd, NULL);
56555e5defdSZiyuan Xu 
56655e5defdSZiyuan Xu 			if (ret)
56755e5defdSZiyuan Xu 				return ret;
56855e5defdSZiyuan Xu 
56955e5defdSZiyuan Xu 			if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR)
57055e5defdSZiyuan Xu 				return -EBADMSG;
57155e5defdSZiyuan Xu 			busy = (cmd.response[0] & MMC_STATUS_CURR_STATE) ==
57255e5defdSZiyuan Xu 				MMC_STATE_PRG;
57355e5defdSZiyuan Xu 		}
57455e5defdSZiyuan Xu 
57555e5defdSZiyuan Xu 		if (get_timer(start) > timeout && busy)
57655e5defdSZiyuan Xu 			return -ETIMEDOUT;
57755e5defdSZiyuan Xu 	} while (busy);
57855e5defdSZiyuan Xu 
57955e5defdSZiyuan Xu 	return 0;
58055e5defdSZiyuan Xu }
58155e5defdSZiyuan Xu 
58255e5defdSZiyuan Xu static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value,
58355e5defdSZiyuan Xu 			u8 send_status)
58455e5defdSZiyuan Xu {
58555e5defdSZiyuan Xu 	struct mmc_cmd cmd;
586a9003dc6SMaxime Ripard 	int retries = 3;
5875d4fc8d9SRaffaele Recalcati 	int ret;
588272cc70bSAndy Fleming 
589272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
590272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
591272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
592272cc70bSAndy Fleming 				 (index << 16) |
593272cc70bSAndy Fleming 				 (value << 8);
594272cc70bSAndy Fleming 
59555e5defdSZiyuan Xu 	do {
5965d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
5975d4fc8d9SRaffaele Recalcati 
59855e5defdSZiyuan Xu 		if (!ret && send_status)
59955e5defdSZiyuan Xu 			return mmc_poll_for_busy(mmc);
60055e5defdSZiyuan Xu 	} while (--retries > 0 && ret);
60155e5defdSZiyuan Xu 
602a9003dc6SMaxime Ripard 	return ret;
603a9003dc6SMaxime Ripard }
604a9003dc6SMaxime Ripard 
60555e5defdSZiyuan Xu int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
60655e5defdSZiyuan Xu {
60755e5defdSZiyuan Xu 	return __mmc_switch(mmc, set, index, value, true);
608272cc70bSAndy Fleming }
609272cc70bSAndy Fleming 
61049dba033SZiyuan Xu static int mmc_select_bus_width(struct mmc *mmc)
61149dba033SZiyuan Xu {
61249dba033SZiyuan Xu 	u32 ext_csd_bits[] = {
61349dba033SZiyuan Xu 		EXT_CSD_BUS_WIDTH_8,
61449dba033SZiyuan Xu 		EXT_CSD_BUS_WIDTH_4,
61549dba033SZiyuan Xu 	};
61649dba033SZiyuan Xu 	u32 bus_widths[] = {
61749dba033SZiyuan Xu 		MMC_BUS_WIDTH_8BIT,
61849dba033SZiyuan Xu 		MMC_BUS_WIDTH_4BIT,
61949dba033SZiyuan Xu 	};
62049dba033SZiyuan Xu 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
62149dba033SZiyuan Xu 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
62249dba033SZiyuan Xu 	u32 idx, bus_width = 0;
62349dba033SZiyuan Xu 	int err = 0;
62449dba033SZiyuan Xu 
62549dba033SZiyuan Xu 	if (mmc->version < MMC_VERSION_4 ||
62649dba033SZiyuan Xu 	    !(mmc->cfg->host_caps & (MMC_MODE_4BIT | MMC_MODE_8BIT)))
62749dba033SZiyuan Xu 		return 0;
62849dba033SZiyuan Xu 
62949dba033SZiyuan Xu 	err = mmc_send_ext_csd(mmc, ext_csd);
63049dba033SZiyuan Xu 
63149dba033SZiyuan Xu 	if (err)
63249dba033SZiyuan Xu 		return err;
63349dba033SZiyuan Xu 
63449dba033SZiyuan Xu 	idx = (mmc->cfg->host_caps & MMC_MODE_8BIT) ? 0 : 1;
63549dba033SZiyuan Xu 
63649dba033SZiyuan Xu 	/*
63749dba033SZiyuan Xu 	 * Unlike SD, MMC cards dont have a configuration register to notify
63849dba033SZiyuan Xu 	 * supported bus width. So bus test command should be run to identify
63949dba033SZiyuan Xu 	 * the supported bus width or compare the ext csd values of current
64049dba033SZiyuan Xu 	 * bus width and ext csd values of 1 bit mode read earlier.
64149dba033SZiyuan Xu 	 */
64249dba033SZiyuan Xu 	for (; idx < ARRAY_SIZE(bus_widths); idx++) {
64349dba033SZiyuan Xu 		/*
64449dba033SZiyuan Xu 		 * Host is capable of 8bit transfer, then switch
64549dba033SZiyuan Xu 		 * the device to work in 8bit transfer mode. If the
64649dba033SZiyuan Xu 		 * mmc switch command returns error then switch to
64749dba033SZiyuan Xu 		 * 4bit transfer mode. On success set the corresponding
64849dba033SZiyuan Xu 		 * bus width on the host.
64949dba033SZiyuan Xu 		 */
65049dba033SZiyuan Xu 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
65149dba033SZiyuan Xu 				 EXT_CSD_BUS_WIDTH, ext_csd_bits[idx]);
65249dba033SZiyuan Xu 		if (err)
65349dba033SZiyuan Xu 			continue;
65449dba033SZiyuan Xu 
65549dba033SZiyuan Xu 		bus_width = bus_widths[idx];
65649dba033SZiyuan Xu 		mmc_set_bus_width(mmc, bus_width);
65749dba033SZiyuan Xu 
65849dba033SZiyuan Xu 		err = mmc_send_ext_csd(mmc, test_csd);
65949dba033SZiyuan Xu 
66049dba033SZiyuan Xu 		if (err)
66149dba033SZiyuan Xu 			continue;
66249dba033SZiyuan Xu 
66349dba033SZiyuan Xu 		/* Only compare read only fields */
66449dba033SZiyuan Xu 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] ==
66549dba033SZiyuan Xu 			test_csd[EXT_CSD_PARTITIONING_SUPPORT]) &&
66649dba033SZiyuan Xu 		    (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] ==
66749dba033SZiyuan Xu 			test_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
66849dba033SZiyuan Xu 		    (ext_csd[EXT_CSD_REV] == test_csd[EXT_CSD_REV]) &&
66949dba033SZiyuan Xu 			(ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] ==
67049dba033SZiyuan Xu 			test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
67149dba033SZiyuan Xu 		    !memcmp(&ext_csd[EXT_CSD_SEC_CNT],
67249dba033SZiyuan Xu 			&test_csd[EXT_CSD_SEC_CNT], 4)) {
67349dba033SZiyuan Xu 			err = bus_width;
67449dba033SZiyuan Xu 			break;
67549dba033SZiyuan Xu 		} else {
67649dba033SZiyuan Xu 			err = -EBADMSG;
67749dba033SZiyuan Xu 		}
67849dba033SZiyuan Xu 	}
67949dba033SZiyuan Xu 
68049dba033SZiyuan Xu 	return err;
68149dba033SZiyuan Xu }
68249dba033SZiyuan Xu 
68349dba033SZiyuan Xu static const u8 tuning_blk_pattern_4bit[] = {
68449dba033SZiyuan Xu 	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
68549dba033SZiyuan Xu 	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
68649dba033SZiyuan Xu 	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
68749dba033SZiyuan Xu 	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
68849dba033SZiyuan Xu 	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
68949dba033SZiyuan Xu 	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
69049dba033SZiyuan Xu 	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
69149dba033SZiyuan Xu 	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
69249dba033SZiyuan Xu };
69349dba033SZiyuan Xu 
69449dba033SZiyuan Xu static const u8 tuning_blk_pattern_8bit[] = {
69549dba033SZiyuan Xu 	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
69649dba033SZiyuan Xu 	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
69749dba033SZiyuan Xu 	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
69849dba033SZiyuan Xu 	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
69949dba033SZiyuan Xu 	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
70049dba033SZiyuan Xu 	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
70149dba033SZiyuan Xu 	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
70249dba033SZiyuan Xu 	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
70349dba033SZiyuan Xu 	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
70449dba033SZiyuan Xu 	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
70549dba033SZiyuan Xu 	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
70649dba033SZiyuan Xu 	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
70749dba033SZiyuan Xu 	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
70849dba033SZiyuan Xu 	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
70949dba033SZiyuan Xu 	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
71049dba033SZiyuan Xu 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
71149dba033SZiyuan Xu };
71249dba033SZiyuan Xu 
71349dba033SZiyuan Xu int mmc_send_tuning(struct mmc *mmc, u32 opcode)
71449dba033SZiyuan Xu {
71549dba033SZiyuan Xu 	struct mmc_cmd cmd;
71649dba033SZiyuan Xu 	struct mmc_data data;
71749dba033SZiyuan Xu 	const u8 *tuning_block_pattern;
71849dba033SZiyuan Xu 	int size, err = 0;
71949dba033SZiyuan Xu 	u8 *data_buf;
72049dba033SZiyuan Xu 
72149dba033SZiyuan Xu 	if (mmc->bus_width == MMC_BUS_WIDTH_8BIT) {
72249dba033SZiyuan Xu 		tuning_block_pattern = tuning_blk_pattern_8bit;
72349dba033SZiyuan Xu 		size = sizeof(tuning_blk_pattern_8bit);
72449dba033SZiyuan Xu 	} else if (mmc->bus_width == MMC_BUS_WIDTH_4BIT) {
72549dba033SZiyuan Xu 		tuning_block_pattern = tuning_blk_pattern_4bit;
72649dba033SZiyuan Xu 		size = sizeof(tuning_blk_pattern_4bit);
72749dba033SZiyuan Xu 	} else {
72849dba033SZiyuan Xu 		return -EINVAL;
72949dba033SZiyuan Xu 	}
73049dba033SZiyuan Xu 
73149dba033SZiyuan Xu 	data_buf = calloc(1, size);
73249dba033SZiyuan Xu 	if (!data_buf)
73349dba033SZiyuan Xu 		return -ENOMEM;
73449dba033SZiyuan Xu 
73549dba033SZiyuan Xu 	cmd.cmdidx = opcode;
73649dba033SZiyuan Xu 	cmd.resp_type = MMC_RSP_R1;
73749dba033SZiyuan Xu 	cmd.cmdarg = 0;
73849dba033SZiyuan Xu 
73949dba033SZiyuan Xu 	data.dest = (char *)data_buf;
74049dba033SZiyuan Xu 	data.blocksize = size;
74149dba033SZiyuan Xu 	data.blocks = 1;
74249dba033SZiyuan Xu 	data.flags = MMC_DATA_READ;
74349dba033SZiyuan Xu 
74449dba033SZiyuan Xu 	err = mmc_send_cmd(mmc, &cmd, &data);
74549dba033SZiyuan Xu 	if (err)
74649dba033SZiyuan Xu 		goto out;
74749dba033SZiyuan Xu 
74849dba033SZiyuan Xu 	if (memcmp(data_buf, tuning_block_pattern, size))
74949dba033SZiyuan Xu 		err = -EIO;
75049dba033SZiyuan Xu out:
75149dba033SZiyuan Xu 	free(data_buf);
75249dba033SZiyuan Xu 	return err;
75349dba033SZiyuan Xu }
75449dba033SZiyuan Xu 
75549dba033SZiyuan Xu static int mmc_execute_tuning(struct mmc *mmc)
75649dba033SZiyuan Xu {
75749dba033SZiyuan Xu #ifdef CONFIG_DM_MMC
75849dba033SZiyuan Xu 	struct dm_mmc_ops *ops = mmc_get_ops(mmc->dev);
75949dba033SZiyuan Xu #endif
76049dba033SZiyuan Xu 	u32 opcode;
76149dba033SZiyuan Xu 
76249dba033SZiyuan Xu 	if (IS_SD(mmc))
76349dba033SZiyuan Xu 		opcode = MMC_SEND_TUNING_BLOCK;
76449dba033SZiyuan Xu 	else
76549dba033SZiyuan Xu 		opcode = MMC_SEND_TUNING_BLOCK_HS200;
76649dba033SZiyuan Xu 
76749dba033SZiyuan Xu #ifndef CONFIG_DM_MMC
76849dba033SZiyuan Xu 	if (mmc->cfg->ops->execute_tuning) {
76949dba033SZiyuan Xu 		return mmc->cfg->ops->execute_tuning(mmc, opcode);
77049dba033SZiyuan Xu #else
77149dba033SZiyuan Xu 	if (ops->execute_tuning) {
77249dba033SZiyuan Xu 		return ops->execute_tuning(mmc->dev, opcode);
77349dba033SZiyuan Xu #endif
77449dba033SZiyuan Xu 	} else {
77549dba033SZiyuan Xu 		debug("Tuning feature required for HS200 mode.\n");
77649dba033SZiyuan Xu 		return -EIO;
77749dba033SZiyuan Xu 	}
77849dba033SZiyuan Xu }
77949dba033SZiyuan Xu 
78049dba033SZiyuan Xu static int mmc_hs200_tuning(struct mmc *mmc)
78149dba033SZiyuan Xu {
78249dba033SZiyuan Xu 	return mmc_execute_tuning(mmc);
78349dba033SZiyuan Xu }
78449dba033SZiyuan Xu 
785e61cd3d7SZiyuan Xu static int mmc_select_hs(struct mmc *mmc)
786e61cd3d7SZiyuan Xu {
787e61cd3d7SZiyuan Xu 	int ret;
788e61cd3d7SZiyuan Xu 
789e61cd3d7SZiyuan Xu 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
790e61cd3d7SZiyuan Xu 			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS);
791e61cd3d7SZiyuan Xu 
792e61cd3d7SZiyuan Xu 	if (!ret)
793e61cd3d7SZiyuan Xu 		mmc_set_timing(mmc, MMC_TIMING_MMC_HS);
794e61cd3d7SZiyuan Xu 
795e61cd3d7SZiyuan Xu 	return ret;
796e61cd3d7SZiyuan Xu }
797e61cd3d7SZiyuan Xu 
7985545757fSZiyuan Xu static int mmc_select_hs_ddr(struct mmc *mmc)
7995545757fSZiyuan Xu {
8005545757fSZiyuan Xu 	u32 ext_csd_bits;
8015545757fSZiyuan Xu 	int err = 0;
8025545757fSZiyuan Xu 
8035545757fSZiyuan Xu 	if (mmc->bus_width == MMC_BUS_WIDTH_1BIT)
8045545757fSZiyuan Xu 		return 0;
8055545757fSZiyuan Xu 
8065545757fSZiyuan Xu 	ext_csd_bits = (mmc->bus_width == MMC_BUS_WIDTH_8BIT) ?
8075545757fSZiyuan Xu 			EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
8085545757fSZiyuan Xu 
8095545757fSZiyuan Xu 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
8105545757fSZiyuan Xu 			 EXT_CSD_BUS_WIDTH, ext_csd_bits);
8115545757fSZiyuan Xu 	if (err)
8125545757fSZiyuan Xu 		return err;
8135545757fSZiyuan Xu 
8145545757fSZiyuan Xu 	mmc_set_timing(mmc, MMC_TIMING_MMC_DDR52);
8155545757fSZiyuan Xu 
8165545757fSZiyuan Xu 	return 0;
8175545757fSZiyuan Xu }
8185545757fSZiyuan Xu 
81949dba033SZiyuan Xu #ifndef CONFIG_SPL_BUILD
82049dba033SZiyuan Xu static int mmc_select_hs200(struct mmc *mmc)
82149dba033SZiyuan Xu {
82249dba033SZiyuan Xu 	int ret;
82349dba033SZiyuan Xu 	struct mmc_cmd cmd;
82449dba033SZiyuan Xu 
82549dba033SZiyuan Xu 	/*
82649dba033SZiyuan Xu 	 * Set the bus width(4 or 8) with host's support and
82749dba033SZiyuan Xu 	 * switch to HS200 mode if bus width is set successfully.
82849dba033SZiyuan Xu 	 */
82949dba033SZiyuan Xu 	ret = mmc_select_bus_width(mmc);
83049dba033SZiyuan Xu 
83149dba033SZiyuan Xu 	if (ret > 0) {
83249dba033SZiyuan Xu 		ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
83349dba033SZiyuan Xu 				   EXT_CSD_HS_TIMING,
83449dba033SZiyuan Xu 				   EXT_CSD_TIMING_HS200, false);
83549dba033SZiyuan Xu 
83649dba033SZiyuan Xu 		if (ret)
83749dba033SZiyuan Xu 			return ret;
83849dba033SZiyuan Xu 
83949dba033SZiyuan Xu 		mmc_set_timing(mmc, MMC_TIMING_MMC_HS200);
84049dba033SZiyuan Xu 
84149dba033SZiyuan Xu 		cmd.cmdidx = MMC_CMD_SEND_STATUS;
84249dba033SZiyuan Xu 		cmd.resp_type = MMC_RSP_R1;
84349dba033SZiyuan Xu 		cmd.cmdarg = mmc->rca << 16;
84449dba033SZiyuan Xu 
84549dba033SZiyuan Xu 		ret = mmc_send_cmd(mmc, &cmd, NULL);
84649dba033SZiyuan Xu 
84749dba033SZiyuan Xu 		if (ret)
84849dba033SZiyuan Xu 			return ret;
84949dba033SZiyuan Xu 
85049dba033SZiyuan Xu 		if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR)
85149dba033SZiyuan Xu 			return -EBADMSG;
85249dba033SZiyuan Xu 	}
85349dba033SZiyuan Xu 
85449dba033SZiyuan Xu 	return ret;
85549dba033SZiyuan Xu }
85649dba033SZiyuan Xu #endif
85749dba033SZiyuan Xu 
858b673f29aSZiyuan Xu static int mmc_select_hs400(struct mmc *mmc)
859b673f29aSZiyuan Xu {
860b673f29aSZiyuan Xu 	int ret;
861b673f29aSZiyuan Xu 
862b673f29aSZiyuan Xu 	/* Switch card to HS mode */
863b673f29aSZiyuan Xu 	ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
864b673f29aSZiyuan Xu 			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, false);
865b673f29aSZiyuan Xu 	if (ret)
866b673f29aSZiyuan Xu 		return ret;
867b673f29aSZiyuan Xu 
868b673f29aSZiyuan Xu 	/* Set host controller to HS timing */
869b673f29aSZiyuan Xu 	mmc_set_timing(mmc, MMC_TIMING_MMC_HS);
870b673f29aSZiyuan Xu 
871b673f29aSZiyuan Xu 	/* Reduce frequency to HS frequency */
872b673f29aSZiyuan Xu 	mmc_set_clock(mmc, MMC_HIGH_52_MAX_DTR);
873b673f29aSZiyuan Xu 
874b673f29aSZiyuan Xu 	ret = mmc_send_status(mmc, 1000);
875b673f29aSZiyuan Xu 	if (ret)
876b673f29aSZiyuan Xu 		return ret;
877b673f29aSZiyuan Xu 
878b673f29aSZiyuan Xu 	/* Switch card to DDR */
879b673f29aSZiyuan Xu 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
880b673f29aSZiyuan Xu 			 EXT_CSD_BUS_WIDTH,
881b673f29aSZiyuan Xu 			 EXT_CSD_DDR_BUS_WIDTH_8);
882b673f29aSZiyuan Xu 	if (ret)
883b673f29aSZiyuan Xu 		return ret;
884b673f29aSZiyuan Xu 
885b673f29aSZiyuan Xu 	/* Switch card to HS400 */
886b673f29aSZiyuan Xu 	ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
887b673f29aSZiyuan Xu 			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400, false);
888b673f29aSZiyuan Xu 	if (ret)
889b673f29aSZiyuan Xu 		return ret;
890b673f29aSZiyuan Xu 
891b673f29aSZiyuan Xu 	/* Set host controller to HS400 timing and frequency */
892b673f29aSZiyuan Xu 	mmc_set_timing(mmc, MMC_TIMING_MMC_HS400);
893b673f29aSZiyuan Xu 
894b673f29aSZiyuan Xu 	return ret;
895b673f29aSZiyuan Xu }
896b673f29aSZiyuan Xu 
897227f658eSZiyuan Xu static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd)
898227f658eSZiyuan Xu {
899227f658eSZiyuan Xu 	u8 card_type;
900227f658eSZiyuan Xu 	u32 host_caps, avail_type = 0;
901227f658eSZiyuan Xu 
902227f658eSZiyuan Xu 	card_type = ext_csd[EXT_CSD_CARD_TYPE];
903227f658eSZiyuan Xu 	host_caps = mmc->cfg->host_caps;
904227f658eSZiyuan Xu 
905227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS) &&
906227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_26))
907227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_26;
908227f658eSZiyuan Xu 
909227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS) &&
910227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_52))
911227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_52;
912227f658eSZiyuan Xu 
913227f658eSZiyuan Xu 	/*
914227f658eSZiyuan Xu 	 * For the moment, u-boot doesn't support signal voltage
915227f658eSZiyuan Xu 	 * switch, therefor we assume that host support ddr52
916227f658eSZiyuan Xu 	 * at 1.8v or 3.3v I/O(1.2v I/O not supported, hs200 and
917227f658eSZiyuan Xu 	 * hs400 are the same).
918227f658eSZiyuan Xu 	 */
919227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_DDR_52MHz) &&
920227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V))
921227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
922227f658eSZiyuan Xu 
923227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS200) &&
924227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V))
925227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
926227f658eSZiyuan Xu 
927227f658eSZiyuan Xu 	/*
928227f658eSZiyuan Xu 	 * If host can support HS400, it means that host can also
929227f658eSZiyuan Xu 	 * support HS200.
930227f658eSZiyuan Xu 	 */
931227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS400) &&
932227f658eSZiyuan Xu 	    (host_caps & MMC_MODE_8BIT) &&
933227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V))
934227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V |
935227f658eSZiyuan Xu 				EXT_CSD_CARD_TYPE_HS400_1_8V;
936227f658eSZiyuan Xu 
937227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS400ES) &&
938227f658eSZiyuan Xu 	    (host_caps & MMC_MODE_8BIT) &&
939227f658eSZiyuan Xu 	    ext_csd[EXT_CSD_STROBE_SUPPORT] &&
940227f658eSZiyuan Xu 	    (avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V))
941227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V |
942227f658eSZiyuan Xu 				EXT_CSD_CARD_TYPE_HS400_1_8V |
943227f658eSZiyuan Xu 				EXT_CSD_CARD_TYPE_HS400ES;
944227f658eSZiyuan Xu 
945227f658eSZiyuan Xu 	return avail_type;
946227f658eSZiyuan Xu }
947227f658eSZiyuan Xu 
94849dba033SZiyuan Xu static void mmc_set_bus_speed(struct mmc *mmc, u8 avail_type)
94949dba033SZiyuan Xu {
95049dba033SZiyuan Xu 	int clock = 0;
95149dba033SZiyuan Xu 
95249dba033SZiyuan Xu 	if (mmc_card_hs(mmc))
95349dba033SZiyuan Xu 		clock = (avail_type & EXT_CSD_CARD_TYPE_52) ?
95449dba033SZiyuan Xu 			MMC_HIGH_52_MAX_DTR : MMC_HIGH_26_MAX_DTR;
95549dba033SZiyuan Xu 	else if (mmc_card_hs200(mmc) ||
95649dba033SZiyuan Xu 		 mmc_card_hs400(mmc) ||
95749dba033SZiyuan Xu 		 mmc_card_hs400es(mmc))
95849dba033SZiyuan Xu 		clock = MMC_HS200_MAX_DTR;
95949dba033SZiyuan Xu 
96049dba033SZiyuan Xu 	mmc_set_clock(mmc, clock);
96149dba033SZiyuan Xu }
96249dba033SZiyuan Xu 
963fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
964272cc70bSAndy Fleming {
9658bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
966227f658eSZiyuan Xu 	u32 avail_type;
967272cc70bSAndy Fleming 	int err;
968272cc70bSAndy Fleming 
969fc5b32fbSAndrew Gabbasov 	mmc->card_caps = 0;
970272cc70bSAndy Fleming 
971d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
972d52ebf10SThomas Chou 		return 0;
973d52ebf10SThomas Chou 
974272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
975272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
976272cc70bSAndy Fleming 		return 0;
977272cc70bSAndy Fleming 
978fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
979fc5b32fbSAndrew Gabbasov 
980272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
981272cc70bSAndy Fleming 
982272cc70bSAndy Fleming 	if (err)
983272cc70bSAndy Fleming 		return err;
984272cc70bSAndy Fleming 
985227f658eSZiyuan Xu 	avail_type = mmc_select_card_type(mmc, ext_csd);
986272cc70bSAndy Fleming 
98749dba033SZiyuan Xu #ifndef CONFIG_SPL_BUILD
98849dba033SZiyuan Xu 	if (avail_type & EXT_CSD_CARD_TYPE_HS200)
98949dba033SZiyuan Xu 		err = mmc_select_hs200(mmc);
99049dba033SZiyuan Xu 	else
99149dba033SZiyuan Xu #endif
992227f658eSZiyuan Xu 	if (avail_type & EXT_CSD_CARD_TYPE_HS)
993e61cd3d7SZiyuan Xu 		err = mmc_select_hs(mmc);
994227f658eSZiyuan Xu 	else
995227f658eSZiyuan Xu 		err = -EINVAL;
996272cc70bSAndy Fleming 
997272cc70bSAndy Fleming 	if (err)
998a5e27b41SHeiko Schocher 		return err;
999272cc70bSAndy Fleming 
100049dba033SZiyuan Xu 	mmc_set_bus_speed(mmc, avail_type);
1001272cc70bSAndy Fleming 
1002b673f29aSZiyuan Xu 	if (mmc_card_hs200(mmc)) {
100349dba033SZiyuan Xu 		err = mmc_hs200_tuning(mmc);
1004b673f29aSZiyuan Xu 		if (avail_type & EXT_CSD_CARD_TYPE_HS400 &&
1005b673f29aSZiyuan Xu 		    mmc->bus_width == MMC_BUS_WIDTH_8BIT) {
1006b673f29aSZiyuan Xu 			err = mmc_select_hs400(mmc);
1007b673f29aSZiyuan Xu 			mmc_set_bus_speed(mmc, avail_type);
1008b673f29aSZiyuan Xu 		}
1009b673f29aSZiyuan Xu 	} else if (!mmc_card_hs400es(mmc)) {
101049dba033SZiyuan Xu 		err = mmc_select_bus_width(mmc) > 0 ? 0 : err;
10115545757fSZiyuan Xu 		if (!err && avail_type & EXT_CSD_CARD_TYPE_DDR_52)
10125545757fSZiyuan Xu 			err = mmc_select_hs_ddr(mmc);
10135545757fSZiyuan Xu 	}
101449dba033SZiyuan Xu 
1015272cc70bSAndy Fleming 	return err;
1016272cc70bSAndy Fleming }
1017272cc70bSAndy Fleming 
1018f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
1019f866a46dSStephen Warren {
1020f866a46dSStephen Warren 	switch (part_num) {
1021f866a46dSStephen Warren 	case 0:
1022f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
1023f866a46dSStephen Warren 		break;
1024f866a46dSStephen Warren 	case 1:
1025f866a46dSStephen Warren 	case 2:
1026f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
1027f866a46dSStephen Warren 		break;
1028f866a46dSStephen Warren 	case 3:
1029f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
1030f866a46dSStephen Warren 		break;
1031f866a46dSStephen Warren 	case 4:
1032f866a46dSStephen Warren 	case 5:
1033f866a46dSStephen Warren 	case 6:
1034f866a46dSStephen Warren 	case 7:
1035f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
1036f866a46dSStephen Warren 		break;
1037f866a46dSStephen Warren 	default:
1038f866a46dSStephen Warren 		return -1;
1039f866a46dSStephen Warren 	}
1040f866a46dSStephen Warren 
1041c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1042f866a46dSStephen Warren 
1043f866a46dSStephen Warren 	return 0;
1044f866a46dSStephen Warren }
1045f866a46dSStephen Warren 
10467dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
1047bc897b1dSLei Wen {
1048f866a46dSStephen Warren 	int ret;
1049bc897b1dSLei Wen 
1050f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
1051bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
1052bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
1053f866a46dSStephen Warren 
10546dc93e70SPeter Bigot 	/*
10556dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
10566dc93e70SPeter Bigot 	 * to return to representing the raw device.
10576dc93e70SPeter Bigot 	 */
1058873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
10596dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
1060fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
1061873cc1d7SStephen Warren 	}
10626dc93e70SPeter Bigot 
10636dc93e70SPeter Bigot 	return ret;
1064bc897b1dSLei Wen }
1065bc897b1dSLei Wen 
1066ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
1067ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
1068ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
1069ac9da0e0SDiego Santa Cruz {
1070ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
1071ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
1072ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
1073ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
1074ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
1075ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
10768dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
1077ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
1078ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
1079ac9da0e0SDiego Santa Cruz 
1080ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
1081ac9da0e0SDiego Santa Cruz 		return -EINVAL;
1082ac9da0e0SDiego Santa Cruz 
1083ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
1084ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
1085ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1086ac9da0e0SDiego Santa Cruz 	}
1087ac9da0e0SDiego Santa Cruz 
1088ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
1089ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
1090ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1091ac9da0e0SDiego Santa Cruz 	}
1092ac9da0e0SDiego Santa Cruz 
1093ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
1094ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
1095ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1096ac9da0e0SDiego Santa Cruz 	}
1097ac9da0e0SDiego Santa Cruz 
1098ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
1099ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
1100ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
1101ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
1102ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
1103ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
1104ac9da0e0SDiego Santa Cruz 			return -EINVAL;
1105ac9da0e0SDiego Santa Cruz 		}
1106ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
1107ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
1108ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
1109ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
1110ac9da0e0SDiego Santa Cruz 		} else {
1111ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
1112ac9da0e0SDiego Santa Cruz 		}
1113ac9da0e0SDiego Santa Cruz 	} else {
1114ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
1115ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
1116ac9da0e0SDiego Santa Cruz 	}
1117ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
1118ac9da0e0SDiego Santa Cruz 
1119ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1120ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
1121ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
1122ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
1123ac9da0e0SDiego Santa Cruz 			return -EINVAL;
1124ac9da0e0SDiego Santa Cruz 		}
1125ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
1126ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
1127ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
1128ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
1129ac9da0e0SDiego Santa Cruz 		}
1130ac9da0e0SDiego Santa Cruz 	}
1131ac9da0e0SDiego Santa Cruz 
1132ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
1133ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
1134ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1135ac9da0e0SDiego Santa Cruz 	}
1136ac9da0e0SDiego Santa Cruz 
1137ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
1138ac9da0e0SDiego Santa Cruz 	if (err)
1139ac9da0e0SDiego Santa Cruz 		return err;
1140ac9da0e0SDiego Santa Cruz 
1141ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
1142ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
1143ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
1144ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
1145ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
1146ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
1147ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
1148ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1149ac9da0e0SDiego Santa Cruz 	}
1150ac9da0e0SDiego Santa Cruz 
11518dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
11528dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
11538dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
11548dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
11558dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
11568dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
11578dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
11588dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
11598dda5b0eSDiego Santa Cruz 		else
11608dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
11618dda5b0eSDiego Santa Cruz 	}
11628dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
11638dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
11648dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
11658dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
11668dda5b0eSDiego Santa Cruz 			else
11678dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
11688dda5b0eSDiego Santa Cruz 		}
11698dda5b0eSDiego Santa Cruz 	}
11708dda5b0eSDiego Santa Cruz 
11718dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
11728dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
11738dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
11748dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
11758dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
11768dda5b0eSDiego Santa Cruz 	}
11778dda5b0eSDiego Santa Cruz 
1178ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
1179ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
1180ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
1181ac9da0e0SDiego Santa Cruz 		return -EPERM;
1182ac9da0e0SDiego Santa Cruz 	}
1183ac9da0e0SDiego Santa Cruz 
1184ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
1185ac9da0e0SDiego Santa Cruz 		return 0;
1186ac9da0e0SDiego Santa Cruz 
1187ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
1188ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
1189ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1190ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1191ac9da0e0SDiego Santa Cruz 
1192ac9da0e0SDiego Santa Cruz 		if (err)
1193ac9da0e0SDiego Santa Cruz 			return err;
1194ac9da0e0SDiego Santa Cruz 
1195ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1196ac9da0e0SDiego Santa Cruz 
1197ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
1198ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
1199ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1200ac9da0e0SDiego Santa Cruz 
1201ac9da0e0SDiego Santa Cruz 	}
1202ac9da0e0SDiego Santa Cruz 
1203ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
1204ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
1205ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1206ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
1207ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
1208ac9da0e0SDiego Santa Cruz 		if (err)
1209ac9da0e0SDiego Santa Cruz 			return err;
1210ac9da0e0SDiego Santa Cruz 	}
1211ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
1212ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1213ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
1214ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
1215ac9da0e0SDiego Santa Cruz 		if (err)
1216ac9da0e0SDiego Santa Cruz 			return err;
1217ac9da0e0SDiego Santa Cruz 	}
1218ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1219ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
1220ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1221ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
1222ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
1223ac9da0e0SDiego Santa Cruz 			if (err)
1224ac9da0e0SDiego Santa Cruz 				return err;
1225ac9da0e0SDiego Santa Cruz 		}
1226ac9da0e0SDiego Santa Cruz 	}
1227ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1228ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
1229ac9da0e0SDiego Santa Cruz 	if (err)
1230ac9da0e0SDiego Santa Cruz 		return err;
1231ac9da0e0SDiego Santa Cruz 
1232ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
1233ac9da0e0SDiego Santa Cruz 		return 0;
1234ac9da0e0SDiego Santa Cruz 
12358dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
12368dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
12378dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
12388dda5b0eSDiego Santa Cruz 	 * partitioning. */
12398dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
12408dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
12418dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
12428dda5b0eSDiego Santa Cruz 		if (err)
12438dda5b0eSDiego Santa Cruz 			return err;
12448dda5b0eSDiego Santa Cruz 	}
12458dda5b0eSDiego Santa Cruz 
1246ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
1247ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
1248ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
1249ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
1250ac9da0e0SDiego Santa Cruz 
1251ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1252ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
1253ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
1254ac9da0e0SDiego Santa Cruz 	if (err)
1255ac9da0e0SDiego Santa Cruz 		return err;
1256ac9da0e0SDiego Santa Cruz 
1257ac9da0e0SDiego Santa Cruz 	return 0;
1258ac9da0e0SDiego Santa Cruz }
1259ac9da0e0SDiego Santa Cruz 
1260e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
126148972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
126248972d90SThierry Reding {
126348972d90SThierry Reding 	int cd;
126448972d90SThierry Reding 
126548972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
126648972d90SThierry Reding 
1267d4e1da4eSPeter Korsgaard 	if (cd < 0) {
126893bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
126993bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
1270d4e1da4eSPeter Korsgaard 		else
1271d4e1da4eSPeter Korsgaard 			cd = 1;
1272d4e1da4eSPeter Korsgaard 	}
127348972d90SThierry Reding 
127448972d90SThierry Reding 	return cd;
127548972d90SThierry Reding }
12768ca51e51SSimon Glass #endif
127748972d90SThierry Reding 
1278fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
1279272cc70bSAndy Fleming {
1280272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1281272cc70bSAndy Fleming 	struct mmc_data data;
1282272cc70bSAndy Fleming 
1283272cc70bSAndy Fleming 	/* Switch the frequency */
1284272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
1285272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1286272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
1287272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
1288272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
1289272cc70bSAndy Fleming 
1290272cc70bSAndy Fleming 	data.dest = (char *)resp;
1291272cc70bSAndy Fleming 	data.blocksize = 64;
1292272cc70bSAndy Fleming 	data.blocks = 1;
1293272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1294272cc70bSAndy Fleming 
1295272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
1296272cc70bSAndy Fleming }
1297272cc70bSAndy Fleming 
1298272cc70bSAndy Fleming 
1299fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
1300272cc70bSAndy Fleming {
1301272cc70bSAndy Fleming 	int err;
1302272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1303f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
1304f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
1305272cc70bSAndy Fleming 	struct mmc_data data;
1306272cc70bSAndy Fleming 	int timeout;
1307272cc70bSAndy Fleming 
1308272cc70bSAndy Fleming 	mmc->card_caps = 0;
1309272cc70bSAndy Fleming 
1310d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
1311d52ebf10SThomas Chou 		return 0;
1312d52ebf10SThomas Chou 
1313272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
1314272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
1315272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1316272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1317272cc70bSAndy Fleming 
1318272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1319272cc70bSAndy Fleming 
1320272cc70bSAndy Fleming 	if (err)
1321272cc70bSAndy Fleming 		return err;
1322272cc70bSAndy Fleming 
1323272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
1324272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1325272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1326272cc70bSAndy Fleming 
1327272cc70bSAndy Fleming 	timeout = 3;
1328272cc70bSAndy Fleming 
1329272cc70bSAndy Fleming retry_scr:
1330f781dd38SAnton staaf 	data.dest = (char *)scr;
1331272cc70bSAndy Fleming 	data.blocksize = 8;
1332272cc70bSAndy Fleming 	data.blocks = 1;
1333272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1334272cc70bSAndy Fleming 
1335272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
1336272cc70bSAndy Fleming 
1337272cc70bSAndy Fleming 	if (err) {
1338272cc70bSAndy Fleming 		if (timeout--)
1339272cc70bSAndy Fleming 			goto retry_scr;
1340272cc70bSAndy Fleming 
1341272cc70bSAndy Fleming 		return err;
1342272cc70bSAndy Fleming 	}
1343272cc70bSAndy Fleming 
13444e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
13454e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
1346272cc70bSAndy Fleming 
1347272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
1348272cc70bSAndy Fleming 	case 0:
1349272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1350272cc70bSAndy Fleming 		break;
1351272cc70bSAndy Fleming 	case 1:
1352272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
1353272cc70bSAndy Fleming 		break;
1354272cc70bSAndy Fleming 	case 2:
1355272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
13561741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
13571741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
1358272cc70bSAndy Fleming 		break;
1359272cc70bSAndy Fleming 	default:
1360272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1361272cc70bSAndy Fleming 		break;
1362272cc70bSAndy Fleming 	}
1363272cc70bSAndy Fleming 
1364b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1365b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1366b44c7083SAlagu Sankar 
1367272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1368272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1369272cc70bSAndy Fleming 		return 0;
1370272cc70bSAndy Fleming 
1371272cc70bSAndy Fleming 	timeout = 4;
1372272cc70bSAndy Fleming 	while (timeout--) {
1373272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1374f781dd38SAnton staaf 				(u8 *)switch_status);
1375272cc70bSAndy Fleming 
1376272cc70bSAndy Fleming 		if (err)
1377272cc70bSAndy Fleming 			return err;
1378272cc70bSAndy Fleming 
1379272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
13804e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1381272cc70bSAndy Fleming 			break;
1382272cc70bSAndy Fleming 	}
1383272cc70bSAndy Fleming 
1384272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
13854e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
1386272cc70bSAndy Fleming 		return 0;
1387272cc70bSAndy Fleming 
13882c3fbf4cSMacpaul Lin 	/*
13892c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
13902c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
13912c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
13922c3fbf4cSMacpaul Lin 	 * mode between the host.
13932c3fbf4cSMacpaul Lin 	 */
139493bfd616SPantelis Antoniou 	if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
139593bfd616SPantelis Antoniou 		(mmc->cfg->host_caps & MMC_MODE_HS)))
13962c3fbf4cSMacpaul Lin 		return 0;
13972c3fbf4cSMacpaul Lin 
1398f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
1399272cc70bSAndy Fleming 
1400272cc70bSAndy Fleming 	if (err)
1401272cc70bSAndy Fleming 		return err;
1402272cc70bSAndy Fleming 
14034e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
1404272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
1405272cc70bSAndy Fleming 
1406272cc70bSAndy Fleming 	return 0;
1407272cc70bSAndy Fleming }
1408272cc70bSAndy Fleming 
14093697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
14103697e599SPeng Fan {
14113697e599SPeng Fan 	int err, i;
14123697e599SPeng Fan 	struct mmc_cmd cmd;
14133697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
14143697e599SPeng Fan 	struct mmc_data data;
14153697e599SPeng Fan 	int timeout = 3;
14163697e599SPeng Fan 	unsigned int au, eo, et, es;
14173697e599SPeng Fan 
14183697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
14193697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
14203697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
14213697e599SPeng Fan 
14223697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
14233697e599SPeng Fan 	if (err)
14243697e599SPeng Fan 		return err;
14253697e599SPeng Fan 
14263697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
14273697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
14283697e599SPeng Fan 	cmd.cmdarg = 0;
14293697e599SPeng Fan 
14303697e599SPeng Fan retry_ssr:
14313697e599SPeng Fan 	data.dest = (char *)ssr;
14323697e599SPeng Fan 	data.blocksize = 64;
14333697e599SPeng Fan 	data.blocks = 1;
14343697e599SPeng Fan 	data.flags = MMC_DATA_READ;
14353697e599SPeng Fan 
14363697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
14373697e599SPeng Fan 	if (err) {
14383697e599SPeng Fan 		if (timeout--)
14393697e599SPeng Fan 			goto retry_ssr;
14403697e599SPeng Fan 
14413697e599SPeng Fan 		return err;
14423697e599SPeng Fan 	}
14433697e599SPeng Fan 
14443697e599SPeng Fan 	for (i = 0; i < 16; i++)
14453697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
14463697e599SPeng Fan 
14473697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
14483697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
14493697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
14503697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
14513697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
14523697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
14533697e599SPeng Fan 		if (es && et) {
14543697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
14553697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
14563697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
14573697e599SPeng Fan 		}
14583697e599SPeng Fan 	} else {
14593697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
14603697e599SPeng Fan 	}
14613697e599SPeng Fan 
14623697e599SPeng Fan 	return 0;
14633697e599SPeng Fan }
14643697e599SPeng Fan 
1465272cc70bSAndy Fleming /* frequency bases */
1466272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
14675f837c2cSMike Frysinger static const int fbase[] = {
1468272cc70bSAndy Fleming 	10000,
1469272cc70bSAndy Fleming 	100000,
1470272cc70bSAndy Fleming 	1000000,
1471272cc70bSAndy Fleming 	10000000,
1472272cc70bSAndy Fleming };
1473272cc70bSAndy Fleming 
1474272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1475272cc70bSAndy Fleming  * to platforms without floating point.
1476272cc70bSAndy Fleming  */
147761fe076fSSimon Glass static const u8 multipliers[] = {
1478272cc70bSAndy Fleming 	0,	/* reserved */
1479272cc70bSAndy Fleming 	10,
1480272cc70bSAndy Fleming 	12,
1481272cc70bSAndy Fleming 	13,
1482272cc70bSAndy Fleming 	15,
1483272cc70bSAndy Fleming 	20,
1484272cc70bSAndy Fleming 	25,
1485272cc70bSAndy Fleming 	30,
1486272cc70bSAndy Fleming 	35,
1487272cc70bSAndy Fleming 	40,
1488272cc70bSAndy Fleming 	45,
1489272cc70bSAndy Fleming 	50,
1490272cc70bSAndy Fleming 	55,
1491272cc70bSAndy Fleming 	60,
1492272cc70bSAndy Fleming 	70,
1493272cc70bSAndy Fleming 	80,
1494272cc70bSAndy Fleming };
1495272cc70bSAndy Fleming 
1496e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1497fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
1498272cc70bSAndy Fleming {
149993bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
150093bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
1501272cc70bSAndy Fleming }
1502ad77484aSZiyuan Xu 
1503ad77484aSZiyuan Xu static bool mmc_card_busy(struct mmc *mmc)
1504ad77484aSZiyuan Xu {
1505ad77484aSZiyuan Xu 	if (!mmc->cfg->ops->card_busy)
1506ad77484aSZiyuan Xu 		return -ENOSYS;
1507ad77484aSZiyuan Xu 
1508ad77484aSZiyuan Xu 	return mmc->cfg->ops->card_busy(mmc);
1509ad77484aSZiyuan Xu }
1510ad77484aSZiyuan Xu 
1511ad77484aSZiyuan Xu static bool mmc_can_card_busy(struct mmc *)
1512ad77484aSZiyuan Xu {
1513ad77484aSZiyuan Xu 	return !!mmc->cfg->ops->card_busy;
1514ad77484aSZiyuan Xu }
15158ca51e51SSimon Glass #endif
1516272cc70bSAndy Fleming 
1517fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1518272cc70bSAndy Fleming {
1519f866a46dSStephen Warren 	int err, i;
15203e3ff0acSZiyuan Xu 	uint mult, freq, tran_speed;
1521639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
1522272cc70bSAndy Fleming 	struct mmc_cmd cmd;
15238bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
15240c453bb7SDiego Santa Cruz 	bool has_parts = false;
15258a0cf490SDiego Santa Cruz 	bool part_completed;
1526c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1527272cc70bSAndy Fleming 
1528d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1529d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1530d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1531d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1532d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1533d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1534d52ebf10SThomas Chou 
1535d52ebf10SThomas Chou 		if (err)
1536d52ebf10SThomas Chou 			return err;
1537d52ebf10SThomas Chou 	}
1538d52ebf10SThomas Chou #endif
1539d52ebf10SThomas Chou 
1540272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1541d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1542d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1543272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1544272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1545272cc70bSAndy Fleming 
1546272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1547272cc70bSAndy Fleming 
1548272cc70bSAndy Fleming 	if (err)
1549272cc70bSAndy Fleming 		return err;
1550272cc70bSAndy Fleming 
1551272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1552272cc70bSAndy Fleming 
1553272cc70bSAndy Fleming 	/*
1554272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1555272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1556272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1557272cc70bSAndy Fleming 	 */
1558d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1559272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1560272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1561272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1562272cc70bSAndy Fleming 
1563272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1564272cc70bSAndy Fleming 
1565272cc70bSAndy Fleming 		if (err)
1566272cc70bSAndy Fleming 			return err;
1567272cc70bSAndy Fleming 
1568272cc70bSAndy Fleming 		if (IS_SD(mmc))
1569998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1570d52ebf10SThomas Chou 	}
1571272cc70bSAndy Fleming 
1572272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1573272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1574272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1575272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1576272cc70bSAndy Fleming 
1577272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1578272cc70bSAndy Fleming 
1579272cc70bSAndy Fleming 	if (err)
1580272cc70bSAndy Fleming 		return err;
1581272cc70bSAndy Fleming 
1582998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1583998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1584998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1585998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1586272cc70bSAndy Fleming 
1587272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
15880b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1589272cc70bSAndy Fleming 
1590272cc70bSAndy Fleming 		switch (version) {
1591272cc70bSAndy Fleming 		case 0:
1592272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1593272cc70bSAndy Fleming 			break;
1594272cc70bSAndy Fleming 		case 1:
1595272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1596272cc70bSAndy Fleming 			break;
1597272cc70bSAndy Fleming 		case 2:
1598272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1599272cc70bSAndy Fleming 			break;
1600272cc70bSAndy Fleming 		case 3:
1601272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1602272cc70bSAndy Fleming 			break;
1603272cc70bSAndy Fleming 		case 4:
1604272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1605272cc70bSAndy Fleming 			break;
1606272cc70bSAndy Fleming 		default:
1607272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1608272cc70bSAndy Fleming 			break;
1609272cc70bSAndy Fleming 		}
1610272cc70bSAndy Fleming 	}
1611272cc70bSAndy Fleming 
1612272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
16130b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
16140b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1615272cc70bSAndy Fleming 
16163e3ff0acSZiyuan Xu 	tran_speed = freq * mult;
1617272cc70bSAndy Fleming 
1618ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1619998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1620272cc70bSAndy Fleming 
1621272cc70bSAndy Fleming 	if (IS_SD(mmc))
1622272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1623272cc70bSAndy Fleming 	else
1624998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1625272cc70bSAndy Fleming 
1626272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1627272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1628272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1629272cc70bSAndy Fleming 		cmult = 8;
1630272cc70bSAndy Fleming 	} else {
1631272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1632272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1633272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1634272cc70bSAndy Fleming 	}
1635272cc70bSAndy Fleming 
1636f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1637f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1638f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1639f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1640f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1641f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1642272cc70bSAndy Fleming 
16438bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
16448bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1645272cc70bSAndy Fleming 
16468bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
16478bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1648272cc70bSAndy Fleming 
1649ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1650ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1651ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1652ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1653ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1654ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1655ab71188cSMarkus Niebel 	}
1656ab71188cSMarkus Niebel 
1657272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1658d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1659272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1660fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1661272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1662272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1663272cc70bSAndy Fleming 
1664272cc70bSAndy Fleming 		if (err)
1665272cc70bSAndy Fleming 			return err;
1666d52ebf10SThomas Chou 	}
1667272cc70bSAndy Fleming 
1668e6f99a56SLei Wen 	/*
1669e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1670e6f99a56SLei Wen 	 */
1671e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1672bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1673d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
1674d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
1675d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
16769cf199ebSDiego Santa Cruz 		if (err)
16779cf199ebSDiego Santa Cruz 			return err;
16789cf199ebSDiego Santa Cruz 		if (ext_csd[EXT_CSD_REV] >= 2) {
1679639b7827SYoshihiro Shimoda 			/*
1680639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
1681639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
1682639b7827SYoshihiro Shimoda 			 * than 2GB
1683639b7827SYoshihiro Shimoda 			 */
16840560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
16850560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
16860560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
16870560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
16888bfa195eSSimon Glass 			capacity *= MMC_MAX_BLOCK_LEN;
1689b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
1690f866a46dSStephen Warren 				mmc->capacity_user = capacity;
1691d23e2c09SSukumar Ghorai 		}
1692bc897b1dSLei Wen 
169364f4a619SJaehoon Chung 		switch (ext_csd[EXT_CSD_REV]) {
169464f4a619SJaehoon Chung 		case 1:
169564f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_1;
169664f4a619SJaehoon Chung 			break;
169764f4a619SJaehoon Chung 		case 2:
169864f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_2;
169964f4a619SJaehoon Chung 			break;
170064f4a619SJaehoon Chung 		case 3:
170164f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_3;
170264f4a619SJaehoon Chung 			break;
170364f4a619SJaehoon Chung 		case 5:
170464f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_41;
170564f4a619SJaehoon Chung 			break;
170664f4a619SJaehoon Chung 		case 6:
170764f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_5;
170864f4a619SJaehoon Chung 			break;
1709edab723bSMarkus Niebel 		case 7:
1710edab723bSMarkus Niebel 			mmc->version = MMC_VERSION_5_0;
1711edab723bSMarkus Niebel 			break;
17121a3619cfSStefan Wahren 		case 8:
17131a3619cfSStefan Wahren 			mmc->version = MMC_VERSION_5_1;
17141a3619cfSStefan Wahren 			break;
171564f4a619SJaehoon Chung 		}
171664f4a619SJaehoon Chung 
17178a0cf490SDiego Santa Cruz 		/* The partition data may be non-zero but it is only
17188a0cf490SDiego Santa Cruz 		 * effective if PARTITION_SETTING_COMPLETED is set in
17198a0cf490SDiego Santa Cruz 		 * EXT_CSD, so ignore any data if this bit is not set,
17208a0cf490SDiego Santa Cruz 		 * except for enabling the high-capacity group size
17218a0cf490SDiego Santa Cruz 		 * definition (see below). */
17228a0cf490SDiego Santa Cruz 		part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
17238a0cf490SDiego Santa Cruz 				    EXT_CSD_PARTITION_SETTING_COMPLETED);
17248a0cf490SDiego Santa Cruz 
17250c453bb7SDiego Santa Cruz 		/* store the partition info of emmc */
17260c453bb7SDiego Santa Cruz 		mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
17270c453bb7SDiego Santa Cruz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
17280c453bb7SDiego Santa Cruz 		    ext_csd[EXT_CSD_BOOT_MULT])
17290c453bb7SDiego Santa Cruz 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
17308a0cf490SDiego Santa Cruz 		if (part_completed &&
17318a0cf490SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
17320c453bb7SDiego Santa Cruz 			mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
1733*a6a1f5f8SJason Zhu 		if (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] & EXT_CSD_SEC_GB_CL_EN)
1734*a6a1f5f8SJason Zhu 			mmc->esr.mmc_can_trim = 1;
17350c453bb7SDiego Santa Cruz 
17360c453bb7SDiego Santa Cruz 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
17370c453bb7SDiego Santa Cruz 
17380c453bb7SDiego Santa Cruz 		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
17390c453bb7SDiego Santa Cruz 
17400c453bb7SDiego Santa Cruz 		for (i = 0; i < 4; i++) {
17410c453bb7SDiego Santa Cruz 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
17428a0cf490SDiego Santa Cruz 			uint mult = (ext_csd[idx + 2] << 16) +
17430c453bb7SDiego Santa Cruz 				(ext_csd[idx + 1] << 8) + ext_csd[idx];
17448a0cf490SDiego Santa Cruz 			if (mult)
17458a0cf490SDiego Santa Cruz 				has_parts = true;
17468a0cf490SDiego Santa Cruz 			if (!part_completed)
17478a0cf490SDiego Santa Cruz 				continue;
17488a0cf490SDiego Santa Cruz 			mmc->capacity_gp[i] = mult;
17490c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *=
17500c453bb7SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
17510c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1752f8e89d67SDiego Santa Cruz 			mmc->capacity_gp[i] <<= 19;
17530c453bb7SDiego Santa Cruz 		}
17540c453bb7SDiego Santa Cruz 
17558a0cf490SDiego Santa Cruz 		if (part_completed) {
1756a7f852b6SDiego Santa Cruz 			mmc->enh_user_size =
1757a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
1758a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
1759a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_SIZE_MULT];
1760a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1761a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1762a7f852b6SDiego Santa Cruz 			mmc->enh_user_size <<= 19;
1763a7f852b6SDiego Santa Cruz 			mmc->enh_user_start =
1764a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
1765a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
1766a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
1767a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_START_ADDR];
1768a7f852b6SDiego Santa Cruz 			if (mmc->high_capacity)
1769a7f852b6SDiego Santa Cruz 				mmc->enh_user_start <<= 9;
17708a0cf490SDiego Santa Cruz 		}
1771a7f852b6SDiego Santa Cruz 
1772e6f99a56SLei Wen 		/*
17731937e5aaSOliver Metz 		 * Host needs to enable ERASE_GRP_DEF bit if device is
17741937e5aaSOliver Metz 		 * partitioned. This bit will be lost every time after a reset
17751937e5aaSOliver Metz 		 * or power off. This will affect erase size.
1776e6f99a56SLei Wen 		 */
17778a0cf490SDiego Santa Cruz 		if (part_completed)
17780c453bb7SDiego Santa Cruz 			has_parts = true;
17791937e5aaSOliver Metz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
17800c453bb7SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
17810c453bb7SDiego Santa Cruz 			has_parts = true;
17820c453bb7SDiego Santa Cruz 		if (has_parts) {
17831937e5aaSOliver Metz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
17841937e5aaSOliver Metz 				EXT_CSD_ERASE_GROUP_DEF, 1);
17851937e5aaSOliver Metz 
17861937e5aaSOliver Metz 			if (err)
17871937e5aaSOliver Metz 				return err;
1788021a8055SHannes Petermaier 			else
1789021a8055SHannes Petermaier 				ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1790037dc0abSDiego Santa Cruz 		}
17911937e5aaSOliver Metz 
1792037dc0abSDiego Santa Cruz 		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
17931937e5aaSOliver Metz 			/* Read out group size from ext_csd */
17940560db18SLei Wen 			mmc->erase_grp_size =
1795a4ff9f83SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1796d7b29129SMarkus Niebel 			/*
1797d7b29129SMarkus Niebel 			 * if high capacity and partition setting completed
1798d7b29129SMarkus Niebel 			 * SEC_COUNT is valid even if it is smaller than 2 GiB
1799d7b29129SMarkus Niebel 			 * JEDEC Standard JESD84-B45, 6.2.4
1800d7b29129SMarkus Niebel 			 */
18018a0cf490SDiego Santa Cruz 			if (mmc->high_capacity && part_completed) {
1802d7b29129SMarkus Niebel 				capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1803d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1804d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1805d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1806d7b29129SMarkus Niebel 				capacity *= MMC_MAX_BLOCK_LEN;
1807d7b29129SMarkus Niebel 				mmc->capacity_user = capacity;
1808d7b29129SMarkus Niebel 			}
18098bfa195eSSimon Glass 		} else {
18101937e5aaSOliver Metz 			/* Calculate the group size from the csd value. */
1811e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
1812e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1813e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1814e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
1815e6f99a56SLei Wen 				* (erase_gmul + 1);
1816e6f99a56SLei Wen 		}
1817037dc0abSDiego Santa Cruz 
1818037dc0abSDiego Santa Cruz 		mmc->hc_wp_grp_size = 1024
1819037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1820037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
18219e41a00bSDiego Santa Cruz 
18229e41a00bSDiego Santa Cruz 		mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1823f866a46dSStephen Warren 	}
1824f866a46dSStephen Warren 
1825c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
1826f866a46dSStephen Warren 	if (err)
1827f866a46dSStephen Warren 		return err;
1828d23e2c09SSukumar Ghorai 
1829272cc70bSAndy Fleming 	if (IS_SD(mmc))
1830272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1831272cc70bSAndy Fleming 	else
1832272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1833272cc70bSAndy Fleming 
1834272cc70bSAndy Fleming 	if (err)
1835272cc70bSAndy Fleming 		return err;
1836272cc70bSAndy Fleming 
1837272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
183893bfd616SPantelis Antoniou 	mmc->card_caps &= mmc->cfg->host_caps;
1839272cc70bSAndy Fleming 
1840272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1841272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1842272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1843272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1844272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1845272cc70bSAndy Fleming 
1846272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1847272cc70bSAndy Fleming 			if (err)
1848272cc70bSAndy Fleming 				return err;
1849272cc70bSAndy Fleming 
1850272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1851272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1852272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1853272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1854272cc70bSAndy Fleming 			if (err)
1855272cc70bSAndy Fleming 				return err;
1856272cc70bSAndy Fleming 
1857272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1858272cc70bSAndy Fleming 		}
1859272cc70bSAndy Fleming 
18603697e599SPeng Fan 		err = sd_read_ssr(mmc);
18613697e599SPeng Fan 		if (err)
18623697e599SPeng Fan 			return err;
18633697e599SPeng Fan 
1864272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
18653e3ff0acSZiyuan Xu 			tran_speed = 50000000;
1866272cc70bSAndy Fleming 		else
18673e3ff0acSZiyuan Xu 			tran_speed = 25000000;
1868ad5fd922SJaehoon Chung 
18693e3ff0acSZiyuan Xu 		mmc_set_clock(mmc, tran_speed);
187049dba033SZiyuan Xu 	}
1871272cc70bSAndy Fleming 
18725af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
187349dba033SZiyuan Xu 	if (mmc_card_ddr(mmc)) {
18745af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
18755af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
18765af8f45cSAndrew Gabbasov 	}
18775af8f45cSAndrew Gabbasov 
1878272cc70bSAndy Fleming 	/* fill in device description */
1879c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1880c40fdca6SSimon Glass 	bdesc->lun = 0;
1881c40fdca6SSimon Glass 	bdesc->hwpart = 0;
1882c40fdca6SSimon Glass 	bdesc->type = 0;
1883c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
1884c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
1885c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1886fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1887fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1888fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1889c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
1890babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1891babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1892c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
18930b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1894babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1895babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1896c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1897babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
189856196826SPaul Burton #else
1899c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
1900c40fdca6SSimon Glass 	bdesc->product[0] = 0;
1901c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
190256196826SPaul Burton #endif
1903122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1904c40fdca6SSimon Glass 	part_init(bdesc);
1905122efd43SMikhail Kshevetskiy #endif
1906272cc70bSAndy Fleming 
1907272cc70bSAndy Fleming 	return 0;
1908272cc70bSAndy Fleming }
1909272cc70bSAndy Fleming 
1910fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1911272cc70bSAndy Fleming {
1912272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1913272cc70bSAndy Fleming 	int err;
1914272cc70bSAndy Fleming 
1915272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1916272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
191793bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1918272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1919272cc70bSAndy Fleming 
1920272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1921272cc70bSAndy Fleming 
1922272cc70bSAndy Fleming 	if (err)
1923272cc70bSAndy Fleming 		return err;
1924272cc70bSAndy Fleming 
1925998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1926915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
1927272cc70bSAndy Fleming 	else
1928272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1929272cc70bSAndy Fleming 
1930272cc70bSAndy Fleming 	return 0;
1931272cc70bSAndy Fleming }
1932272cc70bSAndy Fleming 
1933c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
193495de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
193595de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
193695de9ab2SPaul Kocialkowski {
193795de9ab2SPaul Kocialkowski }
193805cbeb7cSSimon Glass #endif
193995de9ab2SPaul Kocialkowski 
19402051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
19412051aefeSPeng Fan {
1942c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
194305cbeb7cSSimon Glass #if defined(CONFIG_DM_REGULATOR) && !defined(CONFIG_SPL_BUILD)
19442051aefeSPeng Fan 	struct udevice *vmmc_supply;
19452051aefeSPeng Fan 	int ret;
19462051aefeSPeng Fan 
19472051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
19482051aefeSPeng Fan 					  &vmmc_supply);
19492051aefeSPeng Fan 	if (ret) {
1950288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
19512051aefeSPeng Fan 		return 0;
19522051aefeSPeng Fan 	}
19532051aefeSPeng Fan 
19542051aefeSPeng Fan 	ret = regulator_set_enable(vmmc_supply, true);
19552051aefeSPeng Fan 	if (ret) {
19562051aefeSPeng Fan 		puts("Error enabling VMMC supply\n");
19572051aefeSPeng Fan 		return ret;
19582051aefeSPeng Fan 	}
19592051aefeSPeng Fan #endif
196005cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
196105cbeb7cSSimon Glass 	/*
196205cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
196305cbeb7cSSimon Glass 	 * out to board code.
196405cbeb7cSSimon Glass 	 */
196505cbeb7cSSimon Glass 	board_mmc_power_init();
196605cbeb7cSSimon Glass #endif
19672051aefeSPeng Fan 	return 0;
19682051aefeSPeng Fan }
19692051aefeSPeng Fan 
1970e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1971272cc70bSAndy Fleming {
19728ca51e51SSimon Glass 	bool no_card;
1973afd5932bSMacpaul Lin 	int err;
1974272cc70bSAndy Fleming 
1975ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
19768ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
1977e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
19788ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
19798ca51e51SSimon Glass #endif
19808ca51e51SSimon Glass 	if (no_card) {
198148972d90SThierry Reding 		mmc->has_init = 0;
198256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
198348972d90SThierry Reding 		printf("MMC: no card present\n");
198456196826SPaul Burton #endif
1985915ffa52SJaehoon Chung 		return -ENOMEDIUM;
198648972d90SThierry Reding 	}
198748972d90SThierry Reding 
1988bc897b1dSLei Wen 	if (mmc->has_init)
1989bc897b1dSLei Wen 		return 0;
1990bc897b1dSLei Wen 
19915a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
19925a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
19935a8dbdc6SYangbo Lu #endif
19942051aefeSPeng Fan 	err = mmc_power_init(mmc);
19952051aefeSPeng Fan 	if (err)
19962051aefeSPeng Fan 		return err;
199795de9ab2SPaul Kocialkowski 
1998e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
19998ca51e51SSimon Glass 	/* The device has already been probed ready for use */
20008ca51e51SSimon Glass #else
2001ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
200293bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
2003272cc70bSAndy Fleming 	if (err)
2004272cc70bSAndy Fleming 		return err;
20058ca51e51SSimon Glass #endif
2006b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
2007b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
200881db2d36SZiyuan Xu 	mmc_set_timing(mmc, MMC_TIMING_LEGACY);
2009b86b85e2SIlya Yanok 
2010272cc70bSAndy Fleming 	/* Reset the Card */
2011272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
2012272cc70bSAndy Fleming 
2013272cc70bSAndy Fleming 	if (err)
2014272cc70bSAndy Fleming 		return err;
2015272cc70bSAndy Fleming 
2016bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
2017c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
2018bc897b1dSLei Wen 
2019272cc70bSAndy Fleming 	/* Test for SD version 2 */
2020272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
2021272cc70bSAndy Fleming 
2022272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
2023272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
2024272cc70bSAndy Fleming 
2025272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
2026915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
2027272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
2028272cc70bSAndy Fleming 
2029bd47c135SAndrew Gabbasov 		if (err) {
203056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2031272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
203256196826SPaul Burton #endif
2033915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
2034272cc70bSAndy Fleming 		}
2035272cc70bSAndy Fleming 	}
2036272cc70bSAndy Fleming 
2037bd47c135SAndrew Gabbasov 	if (!err)
2038e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
2039e9550449SChe-Liang Chiou 
2040e9550449SChe-Liang Chiou 	return err;
2041e9550449SChe-Liang Chiou }
2042e9550449SChe-Liang Chiou 
2043e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2044e9550449SChe-Liang Chiou {
2045e9550449SChe-Liang Chiou 	int err = 0;
2046e9550449SChe-Liang Chiou 
2047bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
2048e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
2049e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
2050e9550449SChe-Liang Chiou 
2051e9550449SChe-Liang Chiou 	if (!err)
2052bc897b1dSLei Wen 		err = mmc_startup(mmc);
2053bc897b1dSLei Wen 	if (err)
2054bc897b1dSLei Wen 		mmc->has_init = 0;
2055bc897b1dSLei Wen 	else
2056bc897b1dSLei Wen 		mmc->has_init = 1;
2057e9550449SChe-Liang Chiou 	return err;
2058e9550449SChe-Liang Chiou }
2059e9550449SChe-Liang Chiou 
2060e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2061e9550449SChe-Liang Chiou {
2062bd47c135SAndrew Gabbasov 	int err = 0;
2063ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
2064c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
206533fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2066e9550449SChe-Liang Chiou 
206733fb211dSSimon Glass 	upriv->mmc = mmc;
206833fb211dSSimon Glass #endif
2069e9550449SChe-Liang Chiou 	if (mmc->has_init)
2070e9550449SChe-Liang Chiou 		return 0;
2071d803fea5SMateusz Zalega 
2072d803fea5SMateusz Zalega 	start = get_timer(0);
2073d803fea5SMateusz Zalega 
2074e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2075e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2076e9550449SChe-Liang Chiou 
2077bd47c135SAndrew Gabbasov 	if (!err)
2078e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2079919b4858SJagan Teki 	if (err)
2080919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
2081919b4858SJagan Teki 
2082bc897b1dSLei Wen 	return err;
2083272cc70bSAndy Fleming }
2084272cc70bSAndy Fleming 
2085ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2086ab71188cSMarkus Niebel {
2087ab71188cSMarkus Niebel 	mmc->dsr = val;
2088ab71188cSMarkus Niebel 	return 0;
2089ab71188cSMarkus Niebel }
2090ab71188cSMarkus Niebel 
2091cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2092cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2093272cc70bSAndy Fleming {
2094272cc70bSAndy Fleming 	return -1;
2095272cc70bSAndy Fleming }
2096272cc70bSAndy Fleming 
2097cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2098cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2099cee9ab7cSJeroen Hofstee {
2100cee9ab7cSJeroen Hofstee 	return -1;
2101cee9ab7cSJeroen Hofstee }
2102272cc70bSAndy Fleming 
2103e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2104e9550449SChe-Liang Chiou {
2105e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2106e9550449SChe-Liang Chiou }
2107e9550449SChe-Liang Chiou 
2108c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
21098e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
21108e3332e2SSjoerd Simons {
21118e3332e2SSjoerd Simons 	return 0;
21128e3332e2SSjoerd Simons }
2113c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
21148e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
21158e3332e2SSjoerd Simons {
21164a1db6d8SSimon Glass 	int ret, i;
21178e3332e2SSjoerd Simons 	struct uclass *uc;
21184a1db6d8SSimon Glass 	struct udevice *dev;
21198e3332e2SSjoerd Simons 
21208e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
21218e3332e2SSjoerd Simons 	if (ret)
21228e3332e2SSjoerd Simons 		return ret;
21238e3332e2SSjoerd Simons 
21244a1db6d8SSimon Glass 	/*
21254a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
21264a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
21274a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
21284a1db6d8SSimon Glass 	 */
21294a1db6d8SSimon Glass 	for (i = 0; ; i++) {
21304a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
21314a1db6d8SSimon Glass 		if (ret == -ENODEV)
21324a1db6d8SSimon Glass 			break;
21334a1db6d8SSimon Glass 	}
21344a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
21354a1db6d8SSimon Glass 		ret = device_probe(dev);
21368e3332e2SSjoerd Simons 		if (ret)
21374a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
21388e3332e2SSjoerd Simons 	}
21398e3332e2SSjoerd Simons 
21408e3332e2SSjoerd Simons 	return 0;
21418e3332e2SSjoerd Simons }
21428e3332e2SSjoerd Simons #else
21438e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
21448e3332e2SSjoerd Simons {
21458e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
21468e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
21478e3332e2SSjoerd Simons 
21488e3332e2SSjoerd Simons 	return 0;
21498e3332e2SSjoerd Simons }
21508e3332e2SSjoerd Simons #endif
2151e9550449SChe-Liang Chiou 
2152272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2153272cc70bSAndy Fleming {
21541b26bab1SDaniel Kochmański 	static int initialized = 0;
21558e3332e2SSjoerd Simons 	int ret;
21561b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
21571b26bab1SDaniel Kochmański 		return 0;
21581b26bab1SDaniel Kochmański 	initialized = 1;
21591b26bab1SDaniel Kochmański 
2160c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2161b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2162c40fdca6SSimon Glass 	mmc_list_init();
2163c40fdca6SSimon Glass #endif
2164b5b838f1SMarek Vasut #endif
21658e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
21668e3332e2SSjoerd Simons 	if (ret)
21678e3332e2SSjoerd Simons 		return ret;
2168272cc70bSAndy Fleming 
2169bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2170272cc70bSAndy Fleming 	print_mmc_devices(',');
2171bb0dc108SYing Zhang #endif
2172272cc70bSAndy Fleming 
2173c40fdca6SSimon Glass 	mmc_do_preinit();
2174272cc70bSAndy Fleming 	return 0;
2175272cc70bSAndy Fleming }
2176cd3d4880STomas Melin 
2177cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2178cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2179cd3d4880STomas Melin {
2180cd3d4880STomas Melin 	int err;
2181cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2182cd3d4880STomas Melin 
2183cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2184cd3d4880STomas Melin 	if (err) {
2185cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2186cd3d4880STomas Melin 		return err;
2187cd3d4880STomas Melin 	}
2188cd3d4880STomas Melin 
2189cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2190cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2191cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2192cd3d4880STomas Melin 	}
2193cd3d4880STomas Melin 
2194cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2195cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2196cd3d4880STomas Melin 		return 0;
2197cd3d4880STomas Melin 	}
2198cd3d4880STomas Melin 
2199cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2200cd3d4880STomas Melin 	if (err) {
2201cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2202cd3d4880STomas Melin 		return err;
2203cd3d4880STomas Melin 	}
2204cd3d4880STomas Melin 
2205cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2206cd3d4880STomas Melin 
2207cd3d4880STomas Melin 	return 0;
2208cd3d4880STomas Melin }
2209cd3d4880STomas Melin #endif
2210