xref: /rk3399_rockchip-uboot/drivers/mmc/mmc.c (revision caa21a21f1c85abdcf83060db76159fe85e8e540)
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 
213*caa21a21SZiyuan 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 
79849dba033SZiyuan Xu #ifndef CONFIG_SPL_BUILD
79949dba033SZiyuan Xu static int mmc_select_hs200(struct mmc *mmc)
80049dba033SZiyuan Xu {
80149dba033SZiyuan Xu 	int ret;
80249dba033SZiyuan Xu 	struct mmc_cmd cmd;
80349dba033SZiyuan Xu 
80449dba033SZiyuan Xu 	/*
80549dba033SZiyuan Xu 	 * Set the bus width(4 or 8) with host's support and
80649dba033SZiyuan Xu 	 * switch to HS200 mode if bus width is set successfully.
80749dba033SZiyuan Xu 	 */
80849dba033SZiyuan Xu 	ret = mmc_select_bus_width(mmc);
80949dba033SZiyuan Xu 
81049dba033SZiyuan Xu 	if (ret > 0) {
81149dba033SZiyuan Xu 		ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
81249dba033SZiyuan Xu 				   EXT_CSD_HS_TIMING,
81349dba033SZiyuan Xu 				   EXT_CSD_TIMING_HS200, false);
81449dba033SZiyuan Xu 
81549dba033SZiyuan Xu 		if (ret)
81649dba033SZiyuan Xu 			return ret;
81749dba033SZiyuan Xu 
81849dba033SZiyuan Xu 		mmc_set_timing(mmc, MMC_TIMING_MMC_HS200);
81949dba033SZiyuan Xu 
82049dba033SZiyuan Xu 		cmd.cmdidx = MMC_CMD_SEND_STATUS;
82149dba033SZiyuan Xu 		cmd.resp_type = MMC_RSP_R1;
82249dba033SZiyuan Xu 		cmd.cmdarg = mmc->rca << 16;
82349dba033SZiyuan Xu 
82449dba033SZiyuan Xu 		ret = mmc_send_cmd(mmc, &cmd, NULL);
82549dba033SZiyuan Xu 
82649dba033SZiyuan Xu 		if (ret)
82749dba033SZiyuan Xu 			return ret;
82849dba033SZiyuan Xu 
82949dba033SZiyuan Xu 		if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR)
83049dba033SZiyuan Xu 			return -EBADMSG;
83149dba033SZiyuan Xu 	}
83249dba033SZiyuan Xu 
83349dba033SZiyuan Xu 	return ret;
83449dba033SZiyuan Xu }
83549dba033SZiyuan Xu #endif
83649dba033SZiyuan Xu 
837227f658eSZiyuan Xu static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd)
838227f658eSZiyuan Xu {
839227f658eSZiyuan Xu 	u8 card_type;
840227f658eSZiyuan Xu 	u32 host_caps, avail_type = 0;
841227f658eSZiyuan Xu 
842227f658eSZiyuan Xu 	card_type = ext_csd[EXT_CSD_CARD_TYPE];
843227f658eSZiyuan Xu 	host_caps = mmc->cfg->host_caps;
844227f658eSZiyuan Xu 
845227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS) &&
846227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_26))
847227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_26;
848227f658eSZiyuan Xu 
849227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS) &&
850227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_52))
851227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_52;
852227f658eSZiyuan Xu 
853227f658eSZiyuan Xu 	/*
854227f658eSZiyuan Xu 	 * For the moment, u-boot doesn't support signal voltage
855227f658eSZiyuan Xu 	 * switch, therefor we assume that host support ddr52
856227f658eSZiyuan Xu 	 * at 1.8v or 3.3v I/O(1.2v I/O not supported, hs200 and
857227f658eSZiyuan Xu 	 * hs400 are the same).
858227f658eSZiyuan Xu 	 */
859227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_DDR_52MHz) &&
860227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V))
861227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
862227f658eSZiyuan Xu 
863227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS200) &&
864227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V))
865227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
866227f658eSZiyuan Xu 
867227f658eSZiyuan Xu 	/*
868227f658eSZiyuan Xu 	 * If host can support HS400, it means that host can also
869227f658eSZiyuan Xu 	 * support HS200.
870227f658eSZiyuan Xu 	 */
871227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS400) &&
872227f658eSZiyuan Xu 	    (host_caps & MMC_MODE_8BIT) &&
873227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V))
874227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V |
875227f658eSZiyuan Xu 				EXT_CSD_CARD_TYPE_HS400_1_8V;
876227f658eSZiyuan Xu 
877227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS400ES) &&
878227f658eSZiyuan Xu 	    (host_caps & MMC_MODE_8BIT) &&
879227f658eSZiyuan Xu 	    ext_csd[EXT_CSD_STROBE_SUPPORT] &&
880227f658eSZiyuan Xu 	    (avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V))
881227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V |
882227f658eSZiyuan Xu 				EXT_CSD_CARD_TYPE_HS400_1_8V |
883227f658eSZiyuan Xu 				EXT_CSD_CARD_TYPE_HS400ES;
884227f658eSZiyuan Xu 
885227f658eSZiyuan Xu 	return avail_type;
886227f658eSZiyuan Xu }
887227f658eSZiyuan Xu 
88849dba033SZiyuan Xu static void mmc_set_bus_speed(struct mmc *mmc, u8 avail_type)
88949dba033SZiyuan Xu {
89049dba033SZiyuan Xu 	int clock = 0;
89149dba033SZiyuan Xu 
89249dba033SZiyuan Xu 	if (mmc_card_hs(mmc))
89349dba033SZiyuan Xu 		clock = (avail_type & EXT_CSD_CARD_TYPE_52) ?
89449dba033SZiyuan Xu 			MMC_HIGH_52_MAX_DTR : MMC_HIGH_26_MAX_DTR;
89549dba033SZiyuan Xu 	else if (mmc_card_hs200(mmc) ||
89649dba033SZiyuan Xu 		 mmc_card_hs400(mmc) ||
89749dba033SZiyuan Xu 		 mmc_card_hs400es(mmc))
89849dba033SZiyuan Xu 		clock = MMC_HS200_MAX_DTR;
89949dba033SZiyuan Xu 
90049dba033SZiyuan Xu 	mmc_set_clock(mmc, clock);
90149dba033SZiyuan Xu }
90249dba033SZiyuan Xu 
903fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
904272cc70bSAndy Fleming {
9058bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
906227f658eSZiyuan Xu 	u32 avail_type;
907272cc70bSAndy Fleming 	int err;
908272cc70bSAndy Fleming 
909fc5b32fbSAndrew Gabbasov 	mmc->card_caps = 0;
910272cc70bSAndy Fleming 
911d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
912d52ebf10SThomas Chou 		return 0;
913d52ebf10SThomas Chou 
914272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
915272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
916272cc70bSAndy Fleming 		return 0;
917272cc70bSAndy Fleming 
918fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
919fc5b32fbSAndrew Gabbasov 
920272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
921272cc70bSAndy Fleming 
922272cc70bSAndy Fleming 	if (err)
923272cc70bSAndy Fleming 		return err;
924272cc70bSAndy Fleming 
925227f658eSZiyuan Xu 	avail_type = mmc_select_card_type(mmc, ext_csd);
926272cc70bSAndy Fleming 
92749dba033SZiyuan Xu #ifndef CONFIG_SPL_BUILD
92849dba033SZiyuan Xu 	if (avail_type & EXT_CSD_CARD_TYPE_HS200)
92949dba033SZiyuan Xu 		err = mmc_select_hs200(mmc);
93049dba033SZiyuan Xu 	else
93149dba033SZiyuan Xu #endif
932227f658eSZiyuan Xu 	if (avail_type & EXT_CSD_CARD_TYPE_HS)
933e61cd3d7SZiyuan Xu 		err = mmc_select_hs(mmc);
934227f658eSZiyuan Xu 	else
935227f658eSZiyuan Xu 		err = -EINVAL;
936272cc70bSAndy Fleming 
937272cc70bSAndy Fleming 	if (err)
938a5e27b41SHeiko Schocher 		return err;
939272cc70bSAndy Fleming 
94049dba033SZiyuan Xu 	mmc_set_bus_speed(mmc, avail_type);
941272cc70bSAndy Fleming 
94249dba033SZiyuan Xu 	if (mmc_card_hs200(mmc))
94349dba033SZiyuan Xu 		err = mmc_hs200_tuning(mmc);
94449dba033SZiyuan Xu 	else
94549dba033SZiyuan Xu 		err = mmc_select_bus_width(mmc) > 0 ? 0 : err;
94649dba033SZiyuan Xu 
947272cc70bSAndy Fleming 	return err;
948272cc70bSAndy Fleming }
949272cc70bSAndy Fleming 
950f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
951f866a46dSStephen Warren {
952f866a46dSStephen Warren 	switch (part_num) {
953f866a46dSStephen Warren 	case 0:
954f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
955f866a46dSStephen Warren 		break;
956f866a46dSStephen Warren 	case 1:
957f866a46dSStephen Warren 	case 2:
958f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
959f866a46dSStephen Warren 		break;
960f866a46dSStephen Warren 	case 3:
961f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
962f866a46dSStephen Warren 		break;
963f866a46dSStephen Warren 	case 4:
964f866a46dSStephen Warren 	case 5:
965f866a46dSStephen Warren 	case 6:
966f866a46dSStephen Warren 	case 7:
967f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
968f866a46dSStephen Warren 		break;
969f866a46dSStephen Warren 	default:
970f866a46dSStephen Warren 		return -1;
971f866a46dSStephen Warren 	}
972f866a46dSStephen Warren 
973c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
974f866a46dSStephen Warren 
975f866a46dSStephen Warren 	return 0;
976f866a46dSStephen Warren }
977f866a46dSStephen Warren 
9787dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
979bc897b1dSLei Wen {
980f866a46dSStephen Warren 	int ret;
981bc897b1dSLei Wen 
982f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
983bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
984bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
985f866a46dSStephen Warren 
9866dc93e70SPeter Bigot 	/*
9876dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
9886dc93e70SPeter Bigot 	 * to return to representing the raw device.
9896dc93e70SPeter Bigot 	 */
990873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
9916dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
992fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
993873cc1d7SStephen Warren 	}
9946dc93e70SPeter Bigot 
9956dc93e70SPeter Bigot 	return ret;
996bc897b1dSLei Wen }
997bc897b1dSLei Wen 
998ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
999ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
1000ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
1001ac9da0e0SDiego Santa Cruz {
1002ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
1003ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
1004ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
1005ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
1006ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
1007ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
10088dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
1009ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
1010ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
1011ac9da0e0SDiego Santa Cruz 
1012ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
1013ac9da0e0SDiego Santa Cruz 		return -EINVAL;
1014ac9da0e0SDiego Santa Cruz 
1015ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
1016ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
1017ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1018ac9da0e0SDiego Santa Cruz 	}
1019ac9da0e0SDiego Santa Cruz 
1020ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
1021ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
1022ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1023ac9da0e0SDiego Santa Cruz 	}
1024ac9da0e0SDiego Santa Cruz 
1025ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
1026ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
1027ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1028ac9da0e0SDiego Santa Cruz 	}
1029ac9da0e0SDiego Santa Cruz 
1030ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
1031ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
1032ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
1033ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
1034ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
1035ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
1036ac9da0e0SDiego Santa Cruz 			return -EINVAL;
1037ac9da0e0SDiego Santa Cruz 		}
1038ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
1039ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
1040ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
1041ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
1042ac9da0e0SDiego Santa Cruz 		} else {
1043ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
1044ac9da0e0SDiego Santa Cruz 		}
1045ac9da0e0SDiego Santa Cruz 	} else {
1046ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
1047ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
1048ac9da0e0SDiego Santa Cruz 	}
1049ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
1050ac9da0e0SDiego Santa Cruz 
1051ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1052ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
1053ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
1054ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
1055ac9da0e0SDiego Santa Cruz 			return -EINVAL;
1056ac9da0e0SDiego Santa Cruz 		}
1057ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
1058ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
1059ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
1060ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
1061ac9da0e0SDiego Santa Cruz 		}
1062ac9da0e0SDiego Santa Cruz 	}
1063ac9da0e0SDiego Santa Cruz 
1064ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
1065ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
1066ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1067ac9da0e0SDiego Santa Cruz 	}
1068ac9da0e0SDiego Santa Cruz 
1069ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
1070ac9da0e0SDiego Santa Cruz 	if (err)
1071ac9da0e0SDiego Santa Cruz 		return err;
1072ac9da0e0SDiego Santa Cruz 
1073ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
1074ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
1075ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
1076ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
1077ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
1078ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
1079ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
1080ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1081ac9da0e0SDiego Santa Cruz 	}
1082ac9da0e0SDiego Santa Cruz 
10838dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
10848dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
10858dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
10868dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
10878dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
10888dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
10898dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
10908dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
10918dda5b0eSDiego Santa Cruz 		else
10928dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
10938dda5b0eSDiego Santa Cruz 	}
10948dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
10958dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
10968dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
10978dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
10988dda5b0eSDiego Santa Cruz 			else
10998dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
11008dda5b0eSDiego Santa Cruz 		}
11018dda5b0eSDiego Santa Cruz 	}
11028dda5b0eSDiego Santa Cruz 
11038dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
11048dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
11058dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
11068dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
11078dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
11088dda5b0eSDiego Santa Cruz 	}
11098dda5b0eSDiego Santa Cruz 
1110ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
1111ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
1112ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
1113ac9da0e0SDiego Santa Cruz 		return -EPERM;
1114ac9da0e0SDiego Santa Cruz 	}
1115ac9da0e0SDiego Santa Cruz 
1116ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
1117ac9da0e0SDiego Santa Cruz 		return 0;
1118ac9da0e0SDiego Santa Cruz 
1119ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
1120ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
1121ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1122ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1123ac9da0e0SDiego Santa Cruz 
1124ac9da0e0SDiego Santa Cruz 		if (err)
1125ac9da0e0SDiego Santa Cruz 			return err;
1126ac9da0e0SDiego Santa Cruz 
1127ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1128ac9da0e0SDiego Santa Cruz 
1129ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
1130ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
1131ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1132ac9da0e0SDiego Santa Cruz 
1133ac9da0e0SDiego Santa Cruz 	}
1134ac9da0e0SDiego Santa Cruz 
1135ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
1136ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
1137ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1138ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
1139ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
1140ac9da0e0SDiego Santa Cruz 		if (err)
1141ac9da0e0SDiego Santa Cruz 			return err;
1142ac9da0e0SDiego Santa Cruz 	}
1143ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
1144ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1145ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
1146ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
1147ac9da0e0SDiego Santa Cruz 		if (err)
1148ac9da0e0SDiego Santa Cruz 			return err;
1149ac9da0e0SDiego Santa Cruz 	}
1150ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1151ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
1152ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1153ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
1154ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
1155ac9da0e0SDiego Santa Cruz 			if (err)
1156ac9da0e0SDiego Santa Cruz 				return err;
1157ac9da0e0SDiego Santa Cruz 		}
1158ac9da0e0SDiego Santa Cruz 	}
1159ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1160ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
1161ac9da0e0SDiego Santa Cruz 	if (err)
1162ac9da0e0SDiego Santa Cruz 		return err;
1163ac9da0e0SDiego Santa Cruz 
1164ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
1165ac9da0e0SDiego Santa Cruz 		return 0;
1166ac9da0e0SDiego Santa Cruz 
11678dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
11688dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
11698dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
11708dda5b0eSDiego Santa Cruz 	 * partitioning. */
11718dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
11728dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
11738dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
11748dda5b0eSDiego Santa Cruz 		if (err)
11758dda5b0eSDiego Santa Cruz 			return err;
11768dda5b0eSDiego Santa Cruz 	}
11778dda5b0eSDiego Santa Cruz 
1178ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
1179ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
1180ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
1181ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
1182ac9da0e0SDiego Santa Cruz 
1183ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1184ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
1185ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
1186ac9da0e0SDiego Santa Cruz 	if (err)
1187ac9da0e0SDiego Santa Cruz 		return err;
1188ac9da0e0SDiego Santa Cruz 
1189ac9da0e0SDiego Santa Cruz 	return 0;
1190ac9da0e0SDiego Santa Cruz }
1191ac9da0e0SDiego Santa Cruz 
1192e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
119348972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
119448972d90SThierry Reding {
119548972d90SThierry Reding 	int cd;
119648972d90SThierry Reding 
119748972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
119848972d90SThierry Reding 
1199d4e1da4eSPeter Korsgaard 	if (cd < 0) {
120093bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
120193bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
1202d4e1da4eSPeter Korsgaard 		else
1203d4e1da4eSPeter Korsgaard 			cd = 1;
1204d4e1da4eSPeter Korsgaard 	}
120548972d90SThierry Reding 
120648972d90SThierry Reding 	return cd;
120748972d90SThierry Reding }
12088ca51e51SSimon Glass #endif
120948972d90SThierry Reding 
1210fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
1211272cc70bSAndy Fleming {
1212272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1213272cc70bSAndy Fleming 	struct mmc_data data;
1214272cc70bSAndy Fleming 
1215272cc70bSAndy Fleming 	/* Switch the frequency */
1216272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
1217272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1218272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
1219272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
1220272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
1221272cc70bSAndy Fleming 
1222272cc70bSAndy Fleming 	data.dest = (char *)resp;
1223272cc70bSAndy Fleming 	data.blocksize = 64;
1224272cc70bSAndy Fleming 	data.blocks = 1;
1225272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1226272cc70bSAndy Fleming 
1227272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
1228272cc70bSAndy Fleming }
1229272cc70bSAndy Fleming 
1230272cc70bSAndy Fleming 
1231fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
1232272cc70bSAndy Fleming {
1233272cc70bSAndy Fleming 	int err;
1234272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1235f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
1236f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
1237272cc70bSAndy Fleming 	struct mmc_data data;
1238272cc70bSAndy Fleming 	int timeout;
1239272cc70bSAndy Fleming 
1240272cc70bSAndy Fleming 	mmc->card_caps = 0;
1241272cc70bSAndy Fleming 
1242d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
1243d52ebf10SThomas Chou 		return 0;
1244d52ebf10SThomas Chou 
1245272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
1246272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
1247272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1248272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1249272cc70bSAndy Fleming 
1250272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1251272cc70bSAndy Fleming 
1252272cc70bSAndy Fleming 	if (err)
1253272cc70bSAndy Fleming 		return err;
1254272cc70bSAndy Fleming 
1255272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
1256272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1257272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1258272cc70bSAndy Fleming 
1259272cc70bSAndy Fleming 	timeout = 3;
1260272cc70bSAndy Fleming 
1261272cc70bSAndy Fleming retry_scr:
1262f781dd38SAnton staaf 	data.dest = (char *)scr;
1263272cc70bSAndy Fleming 	data.blocksize = 8;
1264272cc70bSAndy Fleming 	data.blocks = 1;
1265272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1266272cc70bSAndy Fleming 
1267272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
1268272cc70bSAndy Fleming 
1269272cc70bSAndy Fleming 	if (err) {
1270272cc70bSAndy Fleming 		if (timeout--)
1271272cc70bSAndy Fleming 			goto retry_scr;
1272272cc70bSAndy Fleming 
1273272cc70bSAndy Fleming 		return err;
1274272cc70bSAndy Fleming 	}
1275272cc70bSAndy Fleming 
12764e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
12774e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
1278272cc70bSAndy Fleming 
1279272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
1280272cc70bSAndy Fleming 	case 0:
1281272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1282272cc70bSAndy Fleming 		break;
1283272cc70bSAndy Fleming 	case 1:
1284272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
1285272cc70bSAndy Fleming 		break;
1286272cc70bSAndy Fleming 	case 2:
1287272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
12881741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
12891741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
1290272cc70bSAndy Fleming 		break;
1291272cc70bSAndy Fleming 	default:
1292272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1293272cc70bSAndy Fleming 		break;
1294272cc70bSAndy Fleming 	}
1295272cc70bSAndy Fleming 
1296b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1297b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1298b44c7083SAlagu Sankar 
1299272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1300272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1301272cc70bSAndy Fleming 		return 0;
1302272cc70bSAndy Fleming 
1303272cc70bSAndy Fleming 	timeout = 4;
1304272cc70bSAndy Fleming 	while (timeout--) {
1305272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1306f781dd38SAnton staaf 				(u8 *)switch_status);
1307272cc70bSAndy Fleming 
1308272cc70bSAndy Fleming 		if (err)
1309272cc70bSAndy Fleming 			return err;
1310272cc70bSAndy Fleming 
1311272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
13124e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1313272cc70bSAndy Fleming 			break;
1314272cc70bSAndy Fleming 	}
1315272cc70bSAndy Fleming 
1316272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
13174e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
1318272cc70bSAndy Fleming 		return 0;
1319272cc70bSAndy Fleming 
13202c3fbf4cSMacpaul Lin 	/*
13212c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
13222c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
13232c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
13242c3fbf4cSMacpaul Lin 	 * mode between the host.
13252c3fbf4cSMacpaul Lin 	 */
132693bfd616SPantelis Antoniou 	if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
132793bfd616SPantelis Antoniou 		(mmc->cfg->host_caps & MMC_MODE_HS)))
13282c3fbf4cSMacpaul Lin 		return 0;
13292c3fbf4cSMacpaul Lin 
1330f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
1331272cc70bSAndy Fleming 
1332272cc70bSAndy Fleming 	if (err)
1333272cc70bSAndy Fleming 		return err;
1334272cc70bSAndy Fleming 
13354e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
1336272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
1337272cc70bSAndy Fleming 
1338272cc70bSAndy Fleming 	return 0;
1339272cc70bSAndy Fleming }
1340272cc70bSAndy Fleming 
13413697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
13423697e599SPeng Fan {
13433697e599SPeng Fan 	int err, i;
13443697e599SPeng Fan 	struct mmc_cmd cmd;
13453697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
13463697e599SPeng Fan 	struct mmc_data data;
13473697e599SPeng Fan 	int timeout = 3;
13483697e599SPeng Fan 	unsigned int au, eo, et, es;
13493697e599SPeng Fan 
13503697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
13513697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
13523697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
13533697e599SPeng Fan 
13543697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
13553697e599SPeng Fan 	if (err)
13563697e599SPeng Fan 		return err;
13573697e599SPeng Fan 
13583697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
13593697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
13603697e599SPeng Fan 	cmd.cmdarg = 0;
13613697e599SPeng Fan 
13623697e599SPeng Fan retry_ssr:
13633697e599SPeng Fan 	data.dest = (char *)ssr;
13643697e599SPeng Fan 	data.blocksize = 64;
13653697e599SPeng Fan 	data.blocks = 1;
13663697e599SPeng Fan 	data.flags = MMC_DATA_READ;
13673697e599SPeng Fan 
13683697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
13693697e599SPeng Fan 	if (err) {
13703697e599SPeng Fan 		if (timeout--)
13713697e599SPeng Fan 			goto retry_ssr;
13723697e599SPeng Fan 
13733697e599SPeng Fan 		return err;
13743697e599SPeng Fan 	}
13753697e599SPeng Fan 
13763697e599SPeng Fan 	for (i = 0; i < 16; i++)
13773697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
13783697e599SPeng Fan 
13793697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
13803697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
13813697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
13823697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
13833697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
13843697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
13853697e599SPeng Fan 		if (es && et) {
13863697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
13873697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
13883697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
13893697e599SPeng Fan 		}
13903697e599SPeng Fan 	} else {
13913697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
13923697e599SPeng Fan 	}
13933697e599SPeng Fan 
13943697e599SPeng Fan 	return 0;
13953697e599SPeng Fan }
13963697e599SPeng Fan 
1397272cc70bSAndy Fleming /* frequency bases */
1398272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
13995f837c2cSMike Frysinger static const int fbase[] = {
1400272cc70bSAndy Fleming 	10000,
1401272cc70bSAndy Fleming 	100000,
1402272cc70bSAndy Fleming 	1000000,
1403272cc70bSAndy Fleming 	10000000,
1404272cc70bSAndy Fleming };
1405272cc70bSAndy Fleming 
1406272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1407272cc70bSAndy Fleming  * to platforms without floating point.
1408272cc70bSAndy Fleming  */
140961fe076fSSimon Glass static const u8 multipliers[] = {
1410272cc70bSAndy Fleming 	0,	/* reserved */
1411272cc70bSAndy Fleming 	10,
1412272cc70bSAndy Fleming 	12,
1413272cc70bSAndy Fleming 	13,
1414272cc70bSAndy Fleming 	15,
1415272cc70bSAndy Fleming 	20,
1416272cc70bSAndy Fleming 	25,
1417272cc70bSAndy Fleming 	30,
1418272cc70bSAndy Fleming 	35,
1419272cc70bSAndy Fleming 	40,
1420272cc70bSAndy Fleming 	45,
1421272cc70bSAndy Fleming 	50,
1422272cc70bSAndy Fleming 	55,
1423272cc70bSAndy Fleming 	60,
1424272cc70bSAndy Fleming 	70,
1425272cc70bSAndy Fleming 	80,
1426272cc70bSAndy Fleming };
1427272cc70bSAndy Fleming 
1428e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1429fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
1430272cc70bSAndy Fleming {
143193bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
143293bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
1433272cc70bSAndy Fleming }
1434ad77484aSZiyuan Xu 
1435ad77484aSZiyuan Xu static bool mmc_card_busy(struct mmc *mmc)
1436ad77484aSZiyuan Xu {
1437ad77484aSZiyuan Xu 	if (!mmc->cfg->ops->card_busy)
1438ad77484aSZiyuan Xu 		return -ENOSYS;
1439ad77484aSZiyuan Xu 
1440ad77484aSZiyuan Xu 	return mmc->cfg->ops->card_busy(mmc);
1441ad77484aSZiyuan Xu }
1442ad77484aSZiyuan Xu 
1443ad77484aSZiyuan Xu static bool mmc_can_card_busy(struct mmc *)
1444ad77484aSZiyuan Xu {
1445ad77484aSZiyuan Xu 	return !!mmc->cfg->ops->card_busy;
1446ad77484aSZiyuan Xu }
14478ca51e51SSimon Glass #endif
1448272cc70bSAndy Fleming 
1449fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1450272cc70bSAndy Fleming {
1451f866a46dSStephen Warren 	int err, i;
1452272cc70bSAndy Fleming 	uint mult, freq;
1453639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
1454272cc70bSAndy Fleming 	struct mmc_cmd cmd;
14558bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
14560c453bb7SDiego Santa Cruz 	bool has_parts = false;
14578a0cf490SDiego Santa Cruz 	bool part_completed;
1458c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1459272cc70bSAndy Fleming 
1460d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1461d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1462d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1463d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1464d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1465d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1466d52ebf10SThomas Chou 
1467d52ebf10SThomas Chou 		if (err)
1468d52ebf10SThomas Chou 			return err;
1469d52ebf10SThomas Chou 	}
1470d52ebf10SThomas Chou #endif
1471d52ebf10SThomas Chou 
1472272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1473d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1474d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1475272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1476272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1477272cc70bSAndy Fleming 
1478272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1479272cc70bSAndy Fleming 
1480272cc70bSAndy Fleming 	if (err)
1481272cc70bSAndy Fleming 		return err;
1482272cc70bSAndy Fleming 
1483272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1484272cc70bSAndy Fleming 
1485272cc70bSAndy Fleming 	/*
1486272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1487272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1488272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1489272cc70bSAndy Fleming 	 */
1490d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1491272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1492272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1493272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1494272cc70bSAndy Fleming 
1495272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1496272cc70bSAndy Fleming 
1497272cc70bSAndy Fleming 		if (err)
1498272cc70bSAndy Fleming 			return err;
1499272cc70bSAndy Fleming 
1500272cc70bSAndy Fleming 		if (IS_SD(mmc))
1501998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1502d52ebf10SThomas Chou 	}
1503272cc70bSAndy Fleming 
1504272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1505272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1506272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1507272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1508272cc70bSAndy Fleming 
1509272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1510272cc70bSAndy Fleming 
1511272cc70bSAndy Fleming 	if (err)
1512272cc70bSAndy Fleming 		return err;
1513272cc70bSAndy Fleming 
1514998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1515998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1516998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1517998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1518272cc70bSAndy Fleming 
1519272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
15200b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1521272cc70bSAndy Fleming 
1522272cc70bSAndy Fleming 		switch (version) {
1523272cc70bSAndy Fleming 		case 0:
1524272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1525272cc70bSAndy Fleming 			break;
1526272cc70bSAndy Fleming 		case 1:
1527272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1528272cc70bSAndy Fleming 			break;
1529272cc70bSAndy Fleming 		case 2:
1530272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1531272cc70bSAndy Fleming 			break;
1532272cc70bSAndy Fleming 		case 3:
1533272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1534272cc70bSAndy Fleming 			break;
1535272cc70bSAndy Fleming 		case 4:
1536272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1537272cc70bSAndy Fleming 			break;
1538272cc70bSAndy Fleming 		default:
1539272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1540272cc70bSAndy Fleming 			break;
1541272cc70bSAndy Fleming 		}
1542272cc70bSAndy Fleming 	}
1543272cc70bSAndy Fleming 
1544272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
15450b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
15460b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1547272cc70bSAndy Fleming 
1548272cc70bSAndy Fleming 	mmc->tran_speed = freq * mult;
1549272cc70bSAndy Fleming 
1550ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1551998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1552272cc70bSAndy Fleming 
1553272cc70bSAndy Fleming 	if (IS_SD(mmc))
1554272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1555272cc70bSAndy Fleming 	else
1556998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1557272cc70bSAndy Fleming 
1558272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1559272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1560272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1561272cc70bSAndy Fleming 		cmult = 8;
1562272cc70bSAndy Fleming 	} else {
1563272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1564272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1565272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1566272cc70bSAndy Fleming 	}
1567272cc70bSAndy Fleming 
1568f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1569f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1570f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1571f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1572f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1573f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1574272cc70bSAndy Fleming 
15758bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
15768bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1577272cc70bSAndy Fleming 
15788bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
15798bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1580272cc70bSAndy Fleming 
1581ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1582ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1583ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1584ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1585ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1586ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1587ab71188cSMarkus Niebel 	}
1588ab71188cSMarkus Niebel 
1589272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1590d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1591272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1592fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1593272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1594272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1595272cc70bSAndy Fleming 
1596272cc70bSAndy Fleming 		if (err)
1597272cc70bSAndy Fleming 			return err;
1598d52ebf10SThomas Chou 	}
1599272cc70bSAndy Fleming 
1600e6f99a56SLei Wen 	/*
1601e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1602e6f99a56SLei Wen 	 */
1603e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1604bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1605d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
1606d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
1607d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
16089cf199ebSDiego Santa Cruz 		if (err)
16099cf199ebSDiego Santa Cruz 			return err;
16109cf199ebSDiego Santa Cruz 		if (ext_csd[EXT_CSD_REV] >= 2) {
1611639b7827SYoshihiro Shimoda 			/*
1612639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
1613639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
1614639b7827SYoshihiro Shimoda 			 * than 2GB
1615639b7827SYoshihiro Shimoda 			 */
16160560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
16170560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
16180560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
16190560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
16208bfa195eSSimon Glass 			capacity *= MMC_MAX_BLOCK_LEN;
1621b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
1622f866a46dSStephen Warren 				mmc->capacity_user = capacity;
1623d23e2c09SSukumar Ghorai 		}
1624bc897b1dSLei Wen 
162564f4a619SJaehoon Chung 		switch (ext_csd[EXT_CSD_REV]) {
162664f4a619SJaehoon Chung 		case 1:
162764f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_1;
162864f4a619SJaehoon Chung 			break;
162964f4a619SJaehoon Chung 		case 2:
163064f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_2;
163164f4a619SJaehoon Chung 			break;
163264f4a619SJaehoon Chung 		case 3:
163364f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_3;
163464f4a619SJaehoon Chung 			break;
163564f4a619SJaehoon Chung 		case 5:
163664f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_41;
163764f4a619SJaehoon Chung 			break;
163864f4a619SJaehoon Chung 		case 6:
163964f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_5;
164064f4a619SJaehoon Chung 			break;
1641edab723bSMarkus Niebel 		case 7:
1642edab723bSMarkus Niebel 			mmc->version = MMC_VERSION_5_0;
1643edab723bSMarkus Niebel 			break;
16441a3619cfSStefan Wahren 		case 8:
16451a3619cfSStefan Wahren 			mmc->version = MMC_VERSION_5_1;
16461a3619cfSStefan Wahren 			break;
164764f4a619SJaehoon Chung 		}
164864f4a619SJaehoon Chung 
16498a0cf490SDiego Santa Cruz 		/* The partition data may be non-zero but it is only
16508a0cf490SDiego Santa Cruz 		 * effective if PARTITION_SETTING_COMPLETED is set in
16518a0cf490SDiego Santa Cruz 		 * EXT_CSD, so ignore any data if this bit is not set,
16528a0cf490SDiego Santa Cruz 		 * except for enabling the high-capacity group size
16538a0cf490SDiego Santa Cruz 		 * definition (see below). */
16548a0cf490SDiego Santa Cruz 		part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
16558a0cf490SDiego Santa Cruz 				    EXT_CSD_PARTITION_SETTING_COMPLETED);
16568a0cf490SDiego Santa Cruz 
16570c453bb7SDiego Santa Cruz 		/* store the partition info of emmc */
16580c453bb7SDiego Santa Cruz 		mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
16590c453bb7SDiego Santa Cruz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
16600c453bb7SDiego Santa Cruz 		    ext_csd[EXT_CSD_BOOT_MULT])
16610c453bb7SDiego Santa Cruz 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
16628a0cf490SDiego Santa Cruz 		if (part_completed &&
16638a0cf490SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
16640c453bb7SDiego Santa Cruz 			mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
16650c453bb7SDiego Santa Cruz 
16660c453bb7SDiego Santa Cruz 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
16670c453bb7SDiego Santa Cruz 
16680c453bb7SDiego Santa Cruz 		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
16690c453bb7SDiego Santa Cruz 
16700c453bb7SDiego Santa Cruz 		for (i = 0; i < 4; i++) {
16710c453bb7SDiego Santa Cruz 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
16728a0cf490SDiego Santa Cruz 			uint mult = (ext_csd[idx + 2] << 16) +
16730c453bb7SDiego Santa Cruz 				(ext_csd[idx + 1] << 8) + ext_csd[idx];
16748a0cf490SDiego Santa Cruz 			if (mult)
16758a0cf490SDiego Santa Cruz 				has_parts = true;
16768a0cf490SDiego Santa Cruz 			if (!part_completed)
16778a0cf490SDiego Santa Cruz 				continue;
16788a0cf490SDiego Santa Cruz 			mmc->capacity_gp[i] = mult;
16790c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *=
16800c453bb7SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
16810c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1682f8e89d67SDiego Santa Cruz 			mmc->capacity_gp[i] <<= 19;
16830c453bb7SDiego Santa Cruz 		}
16840c453bb7SDiego Santa Cruz 
16858a0cf490SDiego Santa Cruz 		if (part_completed) {
1686a7f852b6SDiego Santa Cruz 			mmc->enh_user_size =
1687a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
1688a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
1689a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_SIZE_MULT];
1690a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1691a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1692a7f852b6SDiego Santa Cruz 			mmc->enh_user_size <<= 19;
1693a7f852b6SDiego Santa Cruz 			mmc->enh_user_start =
1694a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
1695a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
1696a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
1697a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_START_ADDR];
1698a7f852b6SDiego Santa Cruz 			if (mmc->high_capacity)
1699a7f852b6SDiego Santa Cruz 				mmc->enh_user_start <<= 9;
17008a0cf490SDiego Santa Cruz 		}
1701a7f852b6SDiego Santa Cruz 
1702e6f99a56SLei Wen 		/*
17031937e5aaSOliver Metz 		 * Host needs to enable ERASE_GRP_DEF bit if device is
17041937e5aaSOliver Metz 		 * partitioned. This bit will be lost every time after a reset
17051937e5aaSOliver Metz 		 * or power off. This will affect erase size.
1706e6f99a56SLei Wen 		 */
17078a0cf490SDiego Santa Cruz 		if (part_completed)
17080c453bb7SDiego Santa Cruz 			has_parts = true;
17091937e5aaSOliver Metz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
17100c453bb7SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
17110c453bb7SDiego Santa Cruz 			has_parts = true;
17120c453bb7SDiego Santa Cruz 		if (has_parts) {
17131937e5aaSOliver Metz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
17141937e5aaSOliver Metz 				EXT_CSD_ERASE_GROUP_DEF, 1);
17151937e5aaSOliver Metz 
17161937e5aaSOliver Metz 			if (err)
17171937e5aaSOliver Metz 				return err;
1718021a8055SHannes Petermaier 			else
1719021a8055SHannes Petermaier 				ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1720037dc0abSDiego Santa Cruz 		}
17211937e5aaSOliver Metz 
1722037dc0abSDiego Santa Cruz 		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
17231937e5aaSOliver Metz 			/* Read out group size from ext_csd */
17240560db18SLei Wen 			mmc->erase_grp_size =
1725a4ff9f83SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1726d7b29129SMarkus Niebel 			/*
1727d7b29129SMarkus Niebel 			 * if high capacity and partition setting completed
1728d7b29129SMarkus Niebel 			 * SEC_COUNT is valid even if it is smaller than 2 GiB
1729d7b29129SMarkus Niebel 			 * JEDEC Standard JESD84-B45, 6.2.4
1730d7b29129SMarkus Niebel 			 */
17318a0cf490SDiego Santa Cruz 			if (mmc->high_capacity && part_completed) {
1732d7b29129SMarkus Niebel 				capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1733d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1734d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1735d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1736d7b29129SMarkus Niebel 				capacity *= MMC_MAX_BLOCK_LEN;
1737d7b29129SMarkus Niebel 				mmc->capacity_user = capacity;
1738d7b29129SMarkus Niebel 			}
17398bfa195eSSimon Glass 		} else {
17401937e5aaSOliver Metz 			/* Calculate the group size from the csd value. */
1741e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
1742e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1743e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1744e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
1745e6f99a56SLei Wen 				* (erase_gmul + 1);
1746e6f99a56SLei Wen 		}
1747037dc0abSDiego Santa Cruz 
1748037dc0abSDiego Santa Cruz 		mmc->hc_wp_grp_size = 1024
1749037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1750037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
17519e41a00bSDiego Santa Cruz 
17529e41a00bSDiego Santa Cruz 		mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1753f866a46dSStephen Warren 	}
1754f866a46dSStephen Warren 
1755c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
1756f866a46dSStephen Warren 	if (err)
1757f866a46dSStephen Warren 		return err;
1758d23e2c09SSukumar Ghorai 
1759272cc70bSAndy Fleming 	if (IS_SD(mmc))
1760272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1761272cc70bSAndy Fleming 	else
1762272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1763272cc70bSAndy Fleming 
1764272cc70bSAndy Fleming 	if (err)
1765272cc70bSAndy Fleming 		return err;
1766272cc70bSAndy Fleming 
1767272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
176893bfd616SPantelis Antoniou 	mmc->card_caps &= mmc->cfg->host_caps;
1769272cc70bSAndy Fleming 
1770272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1771272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1772272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1773272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1774272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1775272cc70bSAndy Fleming 
1776272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1777272cc70bSAndy Fleming 			if (err)
1778272cc70bSAndy Fleming 				return err;
1779272cc70bSAndy Fleming 
1780272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1781272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1782272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1783272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1784272cc70bSAndy Fleming 			if (err)
1785272cc70bSAndy Fleming 				return err;
1786272cc70bSAndy Fleming 
1787272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1788272cc70bSAndy Fleming 		}
1789272cc70bSAndy Fleming 
17903697e599SPeng Fan 		err = sd_read_ssr(mmc);
17913697e599SPeng Fan 		if (err)
17923697e599SPeng Fan 			return err;
17933697e599SPeng Fan 
1794272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
1795ad5fd922SJaehoon Chung 			mmc->tran_speed = 50000000;
1796272cc70bSAndy Fleming 		else
1797ad5fd922SJaehoon Chung 			mmc->tran_speed = 25000000;
1798ad5fd922SJaehoon Chung 
1799ad5fd922SJaehoon Chung 		mmc_set_clock(mmc, mmc->tran_speed);
180049dba033SZiyuan Xu 	}
1801272cc70bSAndy Fleming 
18025af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
180349dba033SZiyuan Xu 	if (mmc_card_ddr(mmc)) {
18045af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
18055af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
18065af8f45cSAndrew Gabbasov 	}
18075af8f45cSAndrew Gabbasov 
1808272cc70bSAndy Fleming 	/* fill in device description */
1809c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1810c40fdca6SSimon Glass 	bdesc->lun = 0;
1811c40fdca6SSimon Glass 	bdesc->hwpart = 0;
1812c40fdca6SSimon Glass 	bdesc->type = 0;
1813c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
1814c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
1815c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1816fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1817fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1818fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1819c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
1820babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1821babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1822c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
18230b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1824babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1825babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1826c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1827babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
182856196826SPaul Burton #else
1829c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
1830c40fdca6SSimon Glass 	bdesc->product[0] = 0;
1831c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
183256196826SPaul Burton #endif
1833122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1834c40fdca6SSimon Glass 	part_init(bdesc);
1835122efd43SMikhail Kshevetskiy #endif
1836272cc70bSAndy Fleming 
1837272cc70bSAndy Fleming 	return 0;
1838272cc70bSAndy Fleming }
1839272cc70bSAndy Fleming 
1840fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1841272cc70bSAndy Fleming {
1842272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1843272cc70bSAndy Fleming 	int err;
1844272cc70bSAndy Fleming 
1845272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1846272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
184793bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1848272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1849272cc70bSAndy Fleming 
1850272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1851272cc70bSAndy Fleming 
1852272cc70bSAndy Fleming 	if (err)
1853272cc70bSAndy Fleming 		return err;
1854272cc70bSAndy Fleming 
1855998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1856915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
1857272cc70bSAndy Fleming 	else
1858272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1859272cc70bSAndy Fleming 
1860272cc70bSAndy Fleming 	return 0;
1861272cc70bSAndy Fleming }
1862272cc70bSAndy Fleming 
1863c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
186495de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
186595de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
186695de9ab2SPaul Kocialkowski {
186795de9ab2SPaul Kocialkowski }
186805cbeb7cSSimon Glass #endif
186995de9ab2SPaul Kocialkowski 
18702051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
18712051aefeSPeng Fan {
1872c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
187305cbeb7cSSimon Glass #if defined(CONFIG_DM_REGULATOR) && !defined(CONFIG_SPL_BUILD)
18742051aefeSPeng Fan 	struct udevice *vmmc_supply;
18752051aefeSPeng Fan 	int ret;
18762051aefeSPeng Fan 
18772051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
18782051aefeSPeng Fan 					  &vmmc_supply);
18792051aefeSPeng Fan 	if (ret) {
1880288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
18812051aefeSPeng Fan 		return 0;
18822051aefeSPeng Fan 	}
18832051aefeSPeng Fan 
18842051aefeSPeng Fan 	ret = regulator_set_enable(vmmc_supply, true);
18852051aefeSPeng Fan 	if (ret) {
18862051aefeSPeng Fan 		puts("Error enabling VMMC supply\n");
18872051aefeSPeng Fan 		return ret;
18882051aefeSPeng Fan 	}
18892051aefeSPeng Fan #endif
189005cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
189105cbeb7cSSimon Glass 	/*
189205cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
189305cbeb7cSSimon Glass 	 * out to board code.
189405cbeb7cSSimon Glass 	 */
189505cbeb7cSSimon Glass 	board_mmc_power_init();
189605cbeb7cSSimon Glass #endif
18972051aefeSPeng Fan 	return 0;
18982051aefeSPeng Fan }
18992051aefeSPeng Fan 
1900e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1901272cc70bSAndy Fleming {
19028ca51e51SSimon Glass 	bool no_card;
1903afd5932bSMacpaul Lin 	int err;
1904272cc70bSAndy Fleming 
1905ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
19068ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
1907e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
19088ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
19098ca51e51SSimon Glass #endif
19108ca51e51SSimon Glass 	if (no_card) {
191148972d90SThierry Reding 		mmc->has_init = 0;
191256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
191348972d90SThierry Reding 		printf("MMC: no card present\n");
191456196826SPaul Burton #endif
1915915ffa52SJaehoon Chung 		return -ENOMEDIUM;
191648972d90SThierry Reding 	}
191748972d90SThierry Reding 
1918bc897b1dSLei Wen 	if (mmc->has_init)
1919bc897b1dSLei Wen 		return 0;
1920bc897b1dSLei Wen 
19215a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
19225a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
19235a8dbdc6SYangbo Lu #endif
19242051aefeSPeng Fan 	err = mmc_power_init(mmc);
19252051aefeSPeng Fan 	if (err)
19262051aefeSPeng Fan 		return err;
192795de9ab2SPaul Kocialkowski 
1928e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
19298ca51e51SSimon Glass 	/* The device has already been probed ready for use */
19308ca51e51SSimon Glass #else
1931ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
193293bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
1933272cc70bSAndy Fleming 	if (err)
1934272cc70bSAndy Fleming 		return err;
19358ca51e51SSimon Glass #endif
1936b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1937b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
193881db2d36SZiyuan Xu 	mmc_set_timing(mmc, MMC_TIMING_LEGACY);
1939b86b85e2SIlya Yanok 
1940272cc70bSAndy Fleming 	/* Reset the Card */
1941272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1942272cc70bSAndy Fleming 
1943272cc70bSAndy Fleming 	if (err)
1944272cc70bSAndy Fleming 		return err;
1945272cc70bSAndy Fleming 
1946bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1947c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
1948bc897b1dSLei Wen 
1949272cc70bSAndy Fleming 	/* Test for SD version 2 */
1950272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1951272cc70bSAndy Fleming 
1952272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1953272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1954272cc70bSAndy Fleming 
1955272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1956915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
1957272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1958272cc70bSAndy Fleming 
1959bd47c135SAndrew Gabbasov 		if (err) {
196056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1961272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
196256196826SPaul Burton #endif
1963915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
1964272cc70bSAndy Fleming 		}
1965272cc70bSAndy Fleming 	}
1966272cc70bSAndy Fleming 
1967bd47c135SAndrew Gabbasov 	if (!err)
1968e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
1969e9550449SChe-Liang Chiou 
1970e9550449SChe-Liang Chiou 	return err;
1971e9550449SChe-Liang Chiou }
1972e9550449SChe-Liang Chiou 
1973e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
1974e9550449SChe-Liang Chiou {
1975e9550449SChe-Liang Chiou 	int err = 0;
1976e9550449SChe-Liang Chiou 
1977bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
1978e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
1979e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
1980e9550449SChe-Liang Chiou 
1981e9550449SChe-Liang Chiou 	if (!err)
1982bc897b1dSLei Wen 		err = mmc_startup(mmc);
1983bc897b1dSLei Wen 	if (err)
1984bc897b1dSLei Wen 		mmc->has_init = 0;
1985bc897b1dSLei Wen 	else
1986bc897b1dSLei Wen 		mmc->has_init = 1;
1987e9550449SChe-Liang Chiou 	return err;
1988e9550449SChe-Liang Chiou }
1989e9550449SChe-Liang Chiou 
1990e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
1991e9550449SChe-Liang Chiou {
1992bd47c135SAndrew Gabbasov 	int err = 0;
1993ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
1994c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
199533fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
1996e9550449SChe-Liang Chiou 
199733fb211dSSimon Glass 	upriv->mmc = mmc;
199833fb211dSSimon Glass #endif
1999e9550449SChe-Liang Chiou 	if (mmc->has_init)
2000e9550449SChe-Liang Chiou 		return 0;
2001d803fea5SMateusz Zalega 
2002d803fea5SMateusz Zalega 	start = get_timer(0);
2003d803fea5SMateusz Zalega 
2004e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2005e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2006e9550449SChe-Liang Chiou 
2007bd47c135SAndrew Gabbasov 	if (!err)
2008e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2009919b4858SJagan Teki 	if (err)
2010919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
2011919b4858SJagan Teki 
2012bc897b1dSLei Wen 	return err;
2013272cc70bSAndy Fleming }
2014272cc70bSAndy Fleming 
2015ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2016ab71188cSMarkus Niebel {
2017ab71188cSMarkus Niebel 	mmc->dsr = val;
2018ab71188cSMarkus Niebel 	return 0;
2019ab71188cSMarkus Niebel }
2020ab71188cSMarkus Niebel 
2021cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2022cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2023272cc70bSAndy Fleming {
2024272cc70bSAndy Fleming 	return -1;
2025272cc70bSAndy Fleming }
2026272cc70bSAndy Fleming 
2027cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2028cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2029cee9ab7cSJeroen Hofstee {
2030cee9ab7cSJeroen Hofstee 	return -1;
2031cee9ab7cSJeroen Hofstee }
2032272cc70bSAndy Fleming 
2033e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2034e9550449SChe-Liang Chiou {
2035e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2036e9550449SChe-Liang Chiou }
2037e9550449SChe-Liang Chiou 
2038c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
20398e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
20408e3332e2SSjoerd Simons {
20418e3332e2SSjoerd Simons 	return 0;
20428e3332e2SSjoerd Simons }
2043c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
20448e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
20458e3332e2SSjoerd Simons {
20464a1db6d8SSimon Glass 	int ret, i;
20478e3332e2SSjoerd Simons 	struct uclass *uc;
20484a1db6d8SSimon Glass 	struct udevice *dev;
20498e3332e2SSjoerd Simons 
20508e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
20518e3332e2SSjoerd Simons 	if (ret)
20528e3332e2SSjoerd Simons 		return ret;
20538e3332e2SSjoerd Simons 
20544a1db6d8SSimon Glass 	/*
20554a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
20564a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
20574a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
20584a1db6d8SSimon Glass 	 */
20594a1db6d8SSimon Glass 	for (i = 0; ; i++) {
20604a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
20614a1db6d8SSimon Glass 		if (ret == -ENODEV)
20624a1db6d8SSimon Glass 			break;
20634a1db6d8SSimon Glass 	}
20644a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
20654a1db6d8SSimon Glass 		ret = device_probe(dev);
20668e3332e2SSjoerd Simons 		if (ret)
20674a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
20688e3332e2SSjoerd Simons 	}
20698e3332e2SSjoerd Simons 
20708e3332e2SSjoerd Simons 	return 0;
20718e3332e2SSjoerd Simons }
20728e3332e2SSjoerd Simons #else
20738e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
20748e3332e2SSjoerd Simons {
20758e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
20768e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
20778e3332e2SSjoerd Simons 
20788e3332e2SSjoerd Simons 	return 0;
20798e3332e2SSjoerd Simons }
20808e3332e2SSjoerd Simons #endif
2081e9550449SChe-Liang Chiou 
2082272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2083272cc70bSAndy Fleming {
20841b26bab1SDaniel Kochmański 	static int initialized = 0;
20858e3332e2SSjoerd Simons 	int ret;
20861b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
20871b26bab1SDaniel Kochmański 		return 0;
20881b26bab1SDaniel Kochmański 	initialized = 1;
20891b26bab1SDaniel Kochmański 
2090c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2091b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2092c40fdca6SSimon Glass 	mmc_list_init();
2093c40fdca6SSimon Glass #endif
2094b5b838f1SMarek Vasut #endif
20958e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
20968e3332e2SSjoerd Simons 	if (ret)
20978e3332e2SSjoerd Simons 		return ret;
2098272cc70bSAndy Fleming 
2099bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2100272cc70bSAndy Fleming 	print_mmc_devices(',');
2101bb0dc108SYing Zhang #endif
2102272cc70bSAndy Fleming 
2103c40fdca6SSimon Glass 	mmc_do_preinit();
2104272cc70bSAndy Fleming 	return 0;
2105272cc70bSAndy Fleming }
2106cd3d4880STomas Melin 
2107cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2108cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2109cd3d4880STomas Melin {
2110cd3d4880STomas Melin 	int err;
2111cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2112cd3d4880STomas Melin 
2113cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2114cd3d4880STomas Melin 	if (err) {
2115cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2116cd3d4880STomas Melin 		return err;
2117cd3d4880STomas Melin 	}
2118cd3d4880STomas Melin 
2119cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2120cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2121cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2122cd3d4880STomas Melin 	}
2123cd3d4880STomas Melin 
2124cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2125cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2126cd3d4880STomas Melin 		return 0;
2127cd3d4880STomas Melin 	}
2128cd3d4880STomas Melin 
2129cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2130cd3d4880STomas Melin 	if (err) {
2131cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2132cd3d4880STomas Melin 		return err;
2133cd3d4880STomas Melin 	}
2134cd3d4880STomas Melin 
2135cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2136cd3d4880STomas Melin 
2137cd3d4880STomas Melin 	return 0;
2138cd3d4880STomas Melin }
2139cd3d4880STomas Melin #endif
2140