xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 7382e691)
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 
213786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
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 
321fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
322272cc70bSAndy Fleming {
323272cc70bSAndy Fleming 	struct mmc_cmd cmd;
324272cc70bSAndy Fleming 	int err;
325272cc70bSAndy Fleming 
326272cc70bSAndy Fleming 	udelay(1000);
327272cc70bSAndy Fleming 
328272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
329272cc70bSAndy Fleming 	cmd.cmdarg = 0;
330272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
331272cc70bSAndy Fleming 
332272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
333272cc70bSAndy Fleming 
334272cc70bSAndy Fleming 	if (err)
335272cc70bSAndy Fleming 		return err;
336272cc70bSAndy Fleming 
337272cc70bSAndy Fleming 	udelay(2000);
338272cc70bSAndy Fleming 
339272cc70bSAndy Fleming 	return 0;
340272cc70bSAndy Fleming }
341272cc70bSAndy Fleming 
342fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
343272cc70bSAndy Fleming {
344272cc70bSAndy Fleming 	int timeout = 1000;
345272cc70bSAndy Fleming 	int err;
346272cc70bSAndy Fleming 	struct mmc_cmd cmd;
347272cc70bSAndy Fleming 
3481677eef4SAndrew Gabbasov 	while (1) {
349272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
350272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
351272cc70bSAndy Fleming 		cmd.cmdarg = 0;
352272cc70bSAndy Fleming 
353272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
354272cc70bSAndy Fleming 
355272cc70bSAndy Fleming 		if (err)
356272cc70bSAndy Fleming 			return err;
357272cc70bSAndy Fleming 
358272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
359272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
360250de12bSStefano Babic 
361250de12bSStefano Babic 		/*
362250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
363250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
364250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
365250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
366250de12bSStefano Babic 		 * specified.
367250de12bSStefano Babic 		 */
368d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
36993bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
370272cc70bSAndy Fleming 
371272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
372272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
373272cc70bSAndy Fleming 
374272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
375272cc70bSAndy Fleming 
376272cc70bSAndy Fleming 		if (err)
377272cc70bSAndy Fleming 			return err;
378272cc70bSAndy Fleming 
3791677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
3801677eef4SAndrew Gabbasov 			break;
381272cc70bSAndy Fleming 
3821677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
383915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
384272cc70bSAndy Fleming 
3851677eef4SAndrew Gabbasov 		udelay(1000);
3861677eef4SAndrew Gabbasov 	}
3871677eef4SAndrew Gabbasov 
388272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
389272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
390272cc70bSAndy Fleming 
391d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
392d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
393d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
394d52ebf10SThomas Chou 		cmd.cmdarg = 0;
395d52ebf10SThomas Chou 
396d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
397d52ebf10SThomas Chou 
398d52ebf10SThomas Chou 		if (err)
399d52ebf10SThomas Chou 			return err;
400d52ebf10SThomas Chou 	}
401d52ebf10SThomas Chou 
402998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
403272cc70bSAndy Fleming 
404272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
405272cc70bSAndy Fleming 	mmc->rca = 0;
406272cc70bSAndy Fleming 
407272cc70bSAndy Fleming 	return 0;
408272cc70bSAndy Fleming }
409272cc70bSAndy Fleming 
4105289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
411272cc70bSAndy Fleming {
4125289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
413272cc70bSAndy Fleming 	int err;
414272cc70bSAndy Fleming 
4155289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
4165289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
4175289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
4185a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
4195a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
42093bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
421a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
422a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
423e9550449SChe-Liang Chiou 
4245289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
425e9550449SChe-Liang Chiou 	if (err)
426e9550449SChe-Liang Chiou 		return err;
4275289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
428e9550449SChe-Liang Chiou 	return 0;
429e9550449SChe-Liang Chiou }
430e9550449SChe-Liang Chiou 
431750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
432e9550449SChe-Liang Chiou {
433e9550449SChe-Liang Chiou 	int err, i;
434e9550449SChe-Liang Chiou 
435272cc70bSAndy Fleming 	/* Some cards seem to need this */
436272cc70bSAndy Fleming 	mmc_go_idle(mmc);
437272cc70bSAndy Fleming 
43831cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
439e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
4405289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
44131cacbabSRaffaele Recalcati 		if (err)
44231cacbabSRaffaele Recalcati 			return err;
44331cacbabSRaffaele Recalcati 
444e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
445a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
446bd47c135SAndrew Gabbasov 			break;
447e9550449SChe-Liang Chiou 	}
448bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
449bd47c135SAndrew Gabbasov 	return 0;
450e9550449SChe-Liang Chiou }
45131cacbabSRaffaele Recalcati 
452750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
453e9550449SChe-Liang Chiou {
454e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
455e9550449SChe-Liang Chiou 	int timeout = 1000;
456e9550449SChe-Liang Chiou 	uint start;
457e9550449SChe-Liang Chiou 	int err;
458e9550449SChe-Liang Chiou 
459e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
460cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
461d188b113SYangbo Lu 		/* Some cards seem to need this */
462d188b113SYangbo Lu 		mmc_go_idle(mmc);
463d188b113SYangbo Lu 
464e9550449SChe-Liang Chiou 		start = get_timer(0);
4651677eef4SAndrew Gabbasov 		while (1) {
4665289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
467272cc70bSAndy Fleming 			if (err)
468272cc70bSAndy Fleming 				return err;
4691677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
4701677eef4SAndrew Gabbasov 				break;
471e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
472915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
473e9550449SChe-Liang Chiou 			udelay(100);
4741677eef4SAndrew Gabbasov 		}
475cc17c01fSAndrew Gabbasov 	}
476272cc70bSAndy Fleming 
477d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
478d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
479d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
480d52ebf10SThomas Chou 		cmd.cmdarg = 0;
481d52ebf10SThomas Chou 
482d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
483d52ebf10SThomas Chou 
484d52ebf10SThomas Chou 		if (err)
485d52ebf10SThomas Chou 			return err;
486a626c8d4SAndrew Gabbasov 
487a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
488d52ebf10SThomas Chou 	}
489d52ebf10SThomas Chou 
490272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
491272cc70bSAndy Fleming 
492272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
493def816a2SStephen Warren 	mmc->rca = 1;
494272cc70bSAndy Fleming 
495272cc70bSAndy Fleming 	return 0;
496272cc70bSAndy Fleming }
497272cc70bSAndy Fleming 
498272cc70bSAndy Fleming 
499fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
500272cc70bSAndy Fleming {
501272cc70bSAndy Fleming 	struct mmc_cmd cmd;
502272cc70bSAndy Fleming 	struct mmc_data data;
503272cc70bSAndy Fleming 	int err;
504272cc70bSAndy Fleming 
505272cc70bSAndy Fleming 	/* Get the Card Status Register */
506272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
507272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
508272cc70bSAndy Fleming 	cmd.cmdarg = 0;
509272cc70bSAndy Fleming 
510cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
511272cc70bSAndy Fleming 	data.blocks = 1;
5128bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
513272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
514272cc70bSAndy Fleming 
515272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
516272cc70bSAndy Fleming 
517272cc70bSAndy Fleming 	return err;
518272cc70bSAndy Fleming }
519272cc70bSAndy Fleming 
520c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
521272cc70bSAndy Fleming {
522272cc70bSAndy Fleming 	struct mmc_cmd cmd;
5235d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
524a9003dc6SMaxime Ripard 	int retries = 3;
5255d4fc8d9SRaffaele Recalcati 	int ret;
526272cc70bSAndy Fleming 
527272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
528272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
529272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
530272cc70bSAndy Fleming 				 (index << 16) |
531272cc70bSAndy Fleming 				 (value << 8);
532272cc70bSAndy Fleming 
533a9003dc6SMaxime Ripard 	while (retries > 0) {
5345d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
5355d4fc8d9SRaffaele Recalcati 
5365d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
537a9003dc6SMaxime Ripard 		if (!ret) {
53893ad0d18SJan Kloetzke 			ret = mmc_send_status(mmc, timeout);
539a9003dc6SMaxime Ripard 			return ret;
540a9003dc6SMaxime Ripard 		}
541a9003dc6SMaxime Ripard 
542a9003dc6SMaxime Ripard 		retries--;
543a9003dc6SMaxime Ripard 	}
5445d4fc8d9SRaffaele Recalcati 
5455d4fc8d9SRaffaele Recalcati 	return ret;
5465d4fc8d9SRaffaele Recalcati 
547272cc70bSAndy Fleming }
548272cc70bSAndy Fleming 
549fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
550272cc70bSAndy Fleming {
5518bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
552272cc70bSAndy Fleming 	char cardtype;
553272cc70bSAndy Fleming 	int err;
554272cc70bSAndy Fleming 
555fc5b32fbSAndrew Gabbasov 	mmc->card_caps = 0;
556272cc70bSAndy Fleming 
557d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
558d52ebf10SThomas Chou 		return 0;
559d52ebf10SThomas Chou 
560272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
561272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
562272cc70bSAndy Fleming 		return 0;
563272cc70bSAndy Fleming 
564fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
565fc5b32fbSAndrew Gabbasov 
566272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
567272cc70bSAndy Fleming 
568272cc70bSAndy Fleming 	if (err)
569272cc70bSAndy Fleming 		return err;
570272cc70bSAndy Fleming 
5710560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
572272cc70bSAndy Fleming 
573272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
574272cc70bSAndy Fleming 
575272cc70bSAndy Fleming 	if (err)
576a5e27b41SHeiko Schocher 		return err;
577272cc70bSAndy Fleming 
578272cc70bSAndy Fleming 	/* Now check to see that it worked */
579272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
580272cc70bSAndy Fleming 
581272cc70bSAndy Fleming 	if (err)
582272cc70bSAndy Fleming 		return err;
583272cc70bSAndy Fleming 
584272cc70bSAndy Fleming 	/* No high-speed support */
5850560db18SLei Wen 	if (!ext_csd[EXT_CSD_HS_TIMING])
586272cc70bSAndy Fleming 		return 0;
587272cc70bSAndy Fleming 
588272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
589d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
590201d5ac4SAndrew Gabbasov 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
591d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
592272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
593d22e3d46SJaehoon Chung 	} else {
594272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
595d22e3d46SJaehoon Chung 	}
596272cc70bSAndy Fleming 
597272cc70bSAndy Fleming 	return 0;
598272cc70bSAndy Fleming }
599272cc70bSAndy Fleming 
600f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
601f866a46dSStephen Warren {
602f866a46dSStephen Warren 	switch (part_num) {
603f866a46dSStephen Warren 	case 0:
604f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
605f866a46dSStephen Warren 		break;
606f866a46dSStephen Warren 	case 1:
607f866a46dSStephen Warren 	case 2:
608f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
609f866a46dSStephen Warren 		break;
610f866a46dSStephen Warren 	case 3:
611f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
612f866a46dSStephen Warren 		break;
613f866a46dSStephen Warren 	case 4:
614f866a46dSStephen Warren 	case 5:
615f866a46dSStephen Warren 	case 6:
616f866a46dSStephen Warren 	case 7:
617f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
618f866a46dSStephen Warren 		break;
619f866a46dSStephen Warren 	default:
620f866a46dSStephen Warren 		return -1;
621f866a46dSStephen Warren 	}
622f866a46dSStephen Warren 
623c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
624f866a46dSStephen Warren 
625f866a46dSStephen Warren 	return 0;
626f866a46dSStephen Warren }
627f866a46dSStephen Warren 
6287dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
629bc897b1dSLei Wen {
630f866a46dSStephen Warren 	int ret;
631bc897b1dSLei Wen 
632f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
633bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
634bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
635f866a46dSStephen Warren 
6366dc93e70SPeter Bigot 	/*
6376dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
6386dc93e70SPeter Bigot 	 * to return to representing the raw device.
6396dc93e70SPeter Bigot 	 */
640873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
6416dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
642fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
643873cc1d7SStephen Warren 	}
6446dc93e70SPeter Bigot 
6456dc93e70SPeter Bigot 	return ret;
646bc897b1dSLei Wen }
647bc897b1dSLei Wen 
648ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
649ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
650ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
651ac9da0e0SDiego Santa Cruz {
652ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
653ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
654ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
655ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
656ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
657ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
6588dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
659ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
660ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
661ac9da0e0SDiego Santa Cruz 
662ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
663ac9da0e0SDiego Santa Cruz 		return -EINVAL;
664ac9da0e0SDiego Santa Cruz 
665ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
666ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
667ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
668ac9da0e0SDiego Santa Cruz 	}
669ac9da0e0SDiego Santa Cruz 
670ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
671ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
672ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
673ac9da0e0SDiego Santa Cruz 	}
674ac9da0e0SDiego Santa Cruz 
675ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
676ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
677ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
678ac9da0e0SDiego Santa Cruz 	}
679ac9da0e0SDiego Santa Cruz 
680ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
681ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
682ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
683ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
684ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
685ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
686ac9da0e0SDiego Santa Cruz 			return -EINVAL;
687ac9da0e0SDiego Santa Cruz 		}
688ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
689ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
690ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
691ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
692ac9da0e0SDiego Santa Cruz 		} else {
693ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
694ac9da0e0SDiego Santa Cruz 		}
695ac9da0e0SDiego Santa Cruz 	} else {
696ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
697ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
698ac9da0e0SDiego Santa Cruz 	}
699ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
700ac9da0e0SDiego Santa Cruz 
701ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
702ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
703ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
704ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
705ac9da0e0SDiego Santa Cruz 			return -EINVAL;
706ac9da0e0SDiego Santa Cruz 		}
707ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
708ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
709ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
710ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
711ac9da0e0SDiego Santa Cruz 		}
712ac9da0e0SDiego Santa Cruz 	}
713ac9da0e0SDiego Santa Cruz 
714ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
715ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
716ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
717ac9da0e0SDiego Santa Cruz 	}
718ac9da0e0SDiego Santa Cruz 
719ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
720ac9da0e0SDiego Santa Cruz 	if (err)
721ac9da0e0SDiego Santa Cruz 		return err;
722ac9da0e0SDiego Santa Cruz 
723ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
724ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
725ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
726ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
727ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
728ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
729ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
730ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
731ac9da0e0SDiego Santa Cruz 	}
732ac9da0e0SDiego Santa Cruz 
7338dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
7348dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
7358dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
7368dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
7378dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
7388dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
7398dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
7408dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
7418dda5b0eSDiego Santa Cruz 		else
7428dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
7438dda5b0eSDiego Santa Cruz 	}
7448dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
7458dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
7468dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
7478dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
7488dda5b0eSDiego Santa Cruz 			else
7498dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
7508dda5b0eSDiego Santa Cruz 		}
7518dda5b0eSDiego Santa Cruz 	}
7528dda5b0eSDiego Santa Cruz 
7538dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
7548dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
7558dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
7568dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
7578dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
7588dda5b0eSDiego Santa Cruz 	}
7598dda5b0eSDiego Santa Cruz 
760ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
761ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
762ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
763ac9da0e0SDiego Santa Cruz 		return -EPERM;
764ac9da0e0SDiego Santa Cruz 	}
765ac9da0e0SDiego Santa Cruz 
766ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
767ac9da0e0SDiego Santa Cruz 		return 0;
768ac9da0e0SDiego Santa Cruz 
769ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
770ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
771ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
772ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
773ac9da0e0SDiego Santa Cruz 
774ac9da0e0SDiego Santa Cruz 		if (err)
775ac9da0e0SDiego Santa Cruz 			return err;
776ac9da0e0SDiego Santa Cruz 
777ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
778ac9da0e0SDiego Santa Cruz 
779ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
780ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
781ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
782ac9da0e0SDiego Santa Cruz 
783ac9da0e0SDiego Santa Cruz 	}
784ac9da0e0SDiego Santa Cruz 
785ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
786ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
787ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
788ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
789ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
790ac9da0e0SDiego Santa Cruz 		if (err)
791ac9da0e0SDiego Santa Cruz 			return err;
792ac9da0e0SDiego Santa Cruz 	}
793ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
794ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
795ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
796ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
797ac9da0e0SDiego Santa Cruz 		if (err)
798ac9da0e0SDiego Santa Cruz 			return err;
799ac9da0e0SDiego Santa Cruz 	}
800ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
801ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
802ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
803ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
804ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
805ac9da0e0SDiego Santa Cruz 			if (err)
806ac9da0e0SDiego Santa Cruz 				return err;
807ac9da0e0SDiego Santa Cruz 		}
808ac9da0e0SDiego Santa Cruz 	}
809ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
810ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
811ac9da0e0SDiego Santa Cruz 	if (err)
812ac9da0e0SDiego Santa Cruz 		return err;
813ac9da0e0SDiego Santa Cruz 
814ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
815ac9da0e0SDiego Santa Cruz 		return 0;
816ac9da0e0SDiego Santa Cruz 
8178dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
8188dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
8198dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
8208dda5b0eSDiego Santa Cruz 	 * partitioning. */
8218dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
8228dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
8238dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
8248dda5b0eSDiego Santa Cruz 		if (err)
8258dda5b0eSDiego Santa Cruz 			return err;
8268dda5b0eSDiego Santa Cruz 	}
8278dda5b0eSDiego Santa Cruz 
828ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
829ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
830ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
831ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
832ac9da0e0SDiego Santa Cruz 
833ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
834ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
835ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
836ac9da0e0SDiego Santa Cruz 	if (err)
837ac9da0e0SDiego Santa Cruz 		return err;
838ac9da0e0SDiego Santa Cruz 
839ac9da0e0SDiego Santa Cruz 	return 0;
840ac9da0e0SDiego Santa Cruz }
841ac9da0e0SDiego Santa Cruz 
842e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
84348972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
84448972d90SThierry Reding {
84548972d90SThierry Reding 	int cd;
84648972d90SThierry Reding 
84748972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
84848972d90SThierry Reding 
849d4e1da4eSPeter Korsgaard 	if (cd < 0) {
85093bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
85193bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
852d4e1da4eSPeter Korsgaard 		else
853d4e1da4eSPeter Korsgaard 			cd = 1;
854d4e1da4eSPeter Korsgaard 	}
85548972d90SThierry Reding 
85648972d90SThierry Reding 	return cd;
85748972d90SThierry Reding }
8588ca51e51SSimon Glass #endif
85948972d90SThierry Reding 
860fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
861272cc70bSAndy Fleming {
862272cc70bSAndy Fleming 	struct mmc_cmd cmd;
863272cc70bSAndy Fleming 	struct mmc_data data;
864272cc70bSAndy Fleming 
865272cc70bSAndy Fleming 	/* Switch the frequency */
866272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
867272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
868272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
869272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
870272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
871272cc70bSAndy Fleming 
872272cc70bSAndy Fleming 	data.dest = (char *)resp;
873272cc70bSAndy Fleming 	data.blocksize = 64;
874272cc70bSAndy Fleming 	data.blocks = 1;
875272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
876272cc70bSAndy Fleming 
877272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
878272cc70bSAndy Fleming }
879272cc70bSAndy Fleming 
880272cc70bSAndy Fleming 
881fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
882272cc70bSAndy Fleming {
883272cc70bSAndy Fleming 	int err;
884272cc70bSAndy Fleming 	struct mmc_cmd cmd;
88518e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
88618e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
887272cc70bSAndy Fleming 	struct mmc_data data;
888272cc70bSAndy Fleming 	int timeout;
889272cc70bSAndy Fleming 
890272cc70bSAndy Fleming 	mmc->card_caps = 0;
891272cc70bSAndy Fleming 
892d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
893d52ebf10SThomas Chou 		return 0;
894d52ebf10SThomas Chou 
895272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
896272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
897272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
898272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
899272cc70bSAndy Fleming 
900272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
901272cc70bSAndy Fleming 
902272cc70bSAndy Fleming 	if (err)
903272cc70bSAndy Fleming 		return err;
904272cc70bSAndy Fleming 
905272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
906272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
907272cc70bSAndy Fleming 	cmd.cmdarg = 0;
908272cc70bSAndy Fleming 
909272cc70bSAndy Fleming 	timeout = 3;
910272cc70bSAndy Fleming 
911272cc70bSAndy Fleming retry_scr:
912f781dd38SAnton staaf 	data.dest = (char *)scr;
913272cc70bSAndy Fleming 	data.blocksize = 8;
914272cc70bSAndy Fleming 	data.blocks = 1;
915272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
916272cc70bSAndy Fleming 
917272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
918272cc70bSAndy Fleming 
919272cc70bSAndy Fleming 	if (err) {
920272cc70bSAndy Fleming 		if (timeout--)
921272cc70bSAndy Fleming 			goto retry_scr;
922272cc70bSAndy Fleming 
923272cc70bSAndy Fleming 		return err;
924272cc70bSAndy Fleming 	}
925272cc70bSAndy Fleming 
9264e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
9274e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
928272cc70bSAndy Fleming 
929272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
930272cc70bSAndy Fleming 	case 0:
931272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
932272cc70bSAndy Fleming 		break;
933272cc70bSAndy Fleming 	case 1:
934272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
935272cc70bSAndy Fleming 		break;
936272cc70bSAndy Fleming 	case 2:
937272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
9381741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
9391741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
940272cc70bSAndy Fleming 		break;
941272cc70bSAndy Fleming 	default:
942272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
943272cc70bSAndy Fleming 		break;
944272cc70bSAndy Fleming 	}
945272cc70bSAndy Fleming 
946b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
947b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
948b44c7083SAlagu Sankar 
949272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
950272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
951272cc70bSAndy Fleming 		return 0;
952272cc70bSAndy Fleming 
953272cc70bSAndy Fleming 	timeout = 4;
954272cc70bSAndy Fleming 	while (timeout--) {
955272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
956f781dd38SAnton staaf 				(u8 *)switch_status);
957272cc70bSAndy Fleming 
958272cc70bSAndy Fleming 		if (err)
959272cc70bSAndy Fleming 			return err;
960272cc70bSAndy Fleming 
961272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
9624e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
963272cc70bSAndy Fleming 			break;
964272cc70bSAndy Fleming 	}
965272cc70bSAndy Fleming 
966272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
9674e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
968272cc70bSAndy Fleming 		return 0;
969272cc70bSAndy Fleming 
9702c3fbf4cSMacpaul Lin 	/*
9712c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
9722c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
9732c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
9742c3fbf4cSMacpaul Lin 	 * mode between the host.
9752c3fbf4cSMacpaul Lin 	 */
97693bfd616SPantelis Antoniou 	if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
97793bfd616SPantelis Antoniou 		(mmc->cfg->host_caps & MMC_MODE_HS)))
9782c3fbf4cSMacpaul Lin 		return 0;
9792c3fbf4cSMacpaul Lin 
980f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
981272cc70bSAndy Fleming 
982272cc70bSAndy Fleming 	if (err)
983272cc70bSAndy Fleming 		return err;
984272cc70bSAndy Fleming 
9854e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
986272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
987272cc70bSAndy Fleming 
988272cc70bSAndy Fleming 	return 0;
989272cc70bSAndy Fleming }
990272cc70bSAndy Fleming 
9913697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
9923697e599SPeng Fan {
9933697e599SPeng Fan 	int err, i;
9943697e599SPeng Fan 	struct mmc_cmd cmd;
9953697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
9963697e599SPeng Fan 	struct mmc_data data;
9973697e599SPeng Fan 	int timeout = 3;
9983697e599SPeng Fan 	unsigned int au, eo, et, es;
9993697e599SPeng Fan 
10003697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
10013697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
10023697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
10033697e599SPeng Fan 
10043697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
10053697e599SPeng Fan 	if (err)
10063697e599SPeng Fan 		return err;
10073697e599SPeng Fan 
10083697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
10093697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
10103697e599SPeng Fan 	cmd.cmdarg = 0;
10113697e599SPeng Fan 
10123697e599SPeng Fan retry_ssr:
10133697e599SPeng Fan 	data.dest = (char *)ssr;
10143697e599SPeng Fan 	data.blocksize = 64;
10153697e599SPeng Fan 	data.blocks = 1;
10163697e599SPeng Fan 	data.flags = MMC_DATA_READ;
10173697e599SPeng Fan 
10183697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
10193697e599SPeng Fan 	if (err) {
10203697e599SPeng Fan 		if (timeout--)
10213697e599SPeng Fan 			goto retry_ssr;
10223697e599SPeng Fan 
10233697e599SPeng Fan 		return err;
10243697e599SPeng Fan 	}
10253697e599SPeng Fan 
10263697e599SPeng Fan 	for (i = 0; i < 16; i++)
10273697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
10283697e599SPeng Fan 
10293697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
10303697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
10313697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
10323697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
10333697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
10343697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
10353697e599SPeng Fan 		if (es && et) {
10363697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
10373697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
10383697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
10393697e599SPeng Fan 		}
10403697e599SPeng Fan 	} else {
10413697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
10423697e599SPeng Fan 	}
10433697e599SPeng Fan 
10443697e599SPeng Fan 	return 0;
10453697e599SPeng Fan }
10463697e599SPeng Fan 
1047272cc70bSAndy Fleming /* frequency bases */
1048272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
10495f837c2cSMike Frysinger static const int fbase[] = {
1050272cc70bSAndy Fleming 	10000,
1051272cc70bSAndy Fleming 	100000,
1052272cc70bSAndy Fleming 	1000000,
1053272cc70bSAndy Fleming 	10000000,
1054272cc70bSAndy Fleming };
1055272cc70bSAndy Fleming 
1056272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1057272cc70bSAndy Fleming  * to platforms without floating point.
1058272cc70bSAndy Fleming  */
105961fe076fSSimon Glass static const u8 multipliers[] = {
1060272cc70bSAndy Fleming 	0,	/* reserved */
1061272cc70bSAndy Fleming 	10,
1062272cc70bSAndy Fleming 	12,
1063272cc70bSAndy Fleming 	13,
1064272cc70bSAndy Fleming 	15,
1065272cc70bSAndy Fleming 	20,
1066272cc70bSAndy Fleming 	25,
1067272cc70bSAndy Fleming 	30,
1068272cc70bSAndy Fleming 	35,
1069272cc70bSAndy Fleming 	40,
1070272cc70bSAndy Fleming 	45,
1071272cc70bSAndy Fleming 	50,
1072272cc70bSAndy Fleming 	55,
1073272cc70bSAndy Fleming 	60,
1074272cc70bSAndy Fleming 	70,
1075272cc70bSAndy Fleming 	80,
1076272cc70bSAndy Fleming };
1077272cc70bSAndy Fleming 
1078e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1079fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
1080272cc70bSAndy Fleming {
108193bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
108293bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
1083272cc70bSAndy Fleming }
10848ca51e51SSimon Glass #endif
1085272cc70bSAndy Fleming 
1086272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
1087272cc70bSAndy Fleming {
108893bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
108993bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1090272cc70bSAndy Fleming 
109193bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
109293bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1093272cc70bSAndy Fleming 
1094272cc70bSAndy Fleming 	mmc->clock = clock;
1095272cc70bSAndy Fleming 
1096272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1097272cc70bSAndy Fleming }
1098272cc70bSAndy Fleming 
1099fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width)
1100272cc70bSAndy Fleming {
1101272cc70bSAndy Fleming 	mmc->bus_width = width;
1102272cc70bSAndy Fleming 
1103272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1104272cc70bSAndy Fleming }
1105272cc70bSAndy Fleming 
11068ac8a263SJean-Jacques Hiblot static int sd_select_bus_freq_width(struct mmc *mmc)
11078ac8a263SJean-Jacques Hiblot {
11088ac8a263SJean-Jacques Hiblot 	int err;
11098ac8a263SJean-Jacques Hiblot 	struct mmc_cmd cmd;
11108ac8a263SJean-Jacques Hiblot 
11118ac8a263SJean-Jacques Hiblot 	err = sd_change_freq(mmc);
11128ac8a263SJean-Jacques Hiblot 	if (err)
11138ac8a263SJean-Jacques Hiblot 		return err;
11148ac8a263SJean-Jacques Hiblot 
11158ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
11168ac8a263SJean-Jacques Hiblot 	mmc->card_caps &= mmc->cfg->host_caps;
11178ac8a263SJean-Jacques Hiblot 
11188ac8a263SJean-Jacques Hiblot 	if (mmc->card_caps & MMC_MODE_4BIT) {
11198ac8a263SJean-Jacques Hiblot 		cmd.cmdidx = MMC_CMD_APP_CMD;
11208ac8a263SJean-Jacques Hiblot 		cmd.resp_type = MMC_RSP_R1;
11218ac8a263SJean-Jacques Hiblot 		cmd.cmdarg = mmc->rca << 16;
11228ac8a263SJean-Jacques Hiblot 
11238ac8a263SJean-Jacques Hiblot 		err = mmc_send_cmd(mmc, &cmd, NULL);
11248ac8a263SJean-Jacques Hiblot 		if (err)
11258ac8a263SJean-Jacques Hiblot 			return err;
11268ac8a263SJean-Jacques Hiblot 
11278ac8a263SJean-Jacques Hiblot 		cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
11288ac8a263SJean-Jacques Hiblot 		cmd.resp_type = MMC_RSP_R1;
11298ac8a263SJean-Jacques Hiblot 		cmd.cmdarg = 2;
11308ac8a263SJean-Jacques Hiblot 		err = mmc_send_cmd(mmc, &cmd, NULL);
11318ac8a263SJean-Jacques Hiblot 		if (err)
11328ac8a263SJean-Jacques Hiblot 			return err;
11338ac8a263SJean-Jacques Hiblot 
11348ac8a263SJean-Jacques Hiblot 		mmc_set_bus_width(mmc, 4);
11358ac8a263SJean-Jacques Hiblot 	}
11368ac8a263SJean-Jacques Hiblot 
11378ac8a263SJean-Jacques Hiblot 	err = sd_read_ssr(mmc);
11388ac8a263SJean-Jacques Hiblot 	if (err)
11398ac8a263SJean-Jacques Hiblot 		return err;
11408ac8a263SJean-Jacques Hiblot 
11418ac8a263SJean-Jacques Hiblot 	if (mmc->card_caps & MMC_MODE_HS)
11428ac8a263SJean-Jacques Hiblot 		mmc->tran_speed = 50000000;
11438ac8a263SJean-Jacques Hiblot 	else
11448ac8a263SJean-Jacques Hiblot 		mmc->tran_speed = 25000000;
11458ac8a263SJean-Jacques Hiblot 
11468ac8a263SJean-Jacques Hiblot 	return 0;
11478ac8a263SJean-Jacques Hiblot }
11488ac8a263SJean-Jacques Hiblot 
1149*7382e691SJean-Jacques Hiblot /*
1150*7382e691SJean-Jacques Hiblot  * read the compare the part of ext csd that is constant.
1151*7382e691SJean-Jacques Hiblot  * This can be used to check that the transfer is working
1152*7382e691SJean-Jacques Hiblot  * as expected.
1153*7382e691SJean-Jacques Hiblot  */
1154*7382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
1155*7382e691SJean-Jacques Hiblot {
1156*7382e691SJean-Jacques Hiblot 	int err;
1157*7382e691SJean-Jacques Hiblot 	const u8 *ext_csd = mmc->ext_csd;
1158*7382e691SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
1159*7382e691SJean-Jacques Hiblot 
1160*7382e691SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, test_csd);
1161*7382e691SJean-Jacques Hiblot 	if (err)
1162*7382e691SJean-Jacques Hiblot 		return err;
1163*7382e691SJean-Jacques Hiblot 
1164*7382e691SJean-Jacques Hiblot 	/* Only compare read only fields */
1165*7382e691SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
1166*7382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
1167*7382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
1168*7382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
1169*7382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_REV]
1170*7382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_REV] &&
1171*7382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1172*7382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
1173*7382e691SJean-Jacques Hiblot 	    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
1174*7382e691SJean-Jacques Hiblot 		   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
1175*7382e691SJean-Jacques Hiblot 		return 0;
1176*7382e691SJean-Jacques Hiblot 
1177*7382e691SJean-Jacques Hiblot 	return -EBADMSG;
1178*7382e691SJean-Jacques Hiblot }
1179*7382e691SJean-Jacques Hiblot 
1180dfda9d88SJean-Jacques Hiblot static int mmc_select_bus_freq_width(struct mmc *mmc)
11818ac8a263SJean-Jacques Hiblot {
11828ac8a263SJean-Jacques Hiblot 	/* An array of possible bus widths in order of preference */
11838ac8a263SJean-Jacques Hiblot 	static const unsigned int ext_csd_bits[] = {
11848ac8a263SJean-Jacques Hiblot 		EXT_CSD_DDR_BUS_WIDTH_8,
11858ac8a263SJean-Jacques Hiblot 		EXT_CSD_DDR_BUS_WIDTH_4,
11868ac8a263SJean-Jacques Hiblot 		EXT_CSD_BUS_WIDTH_8,
11878ac8a263SJean-Jacques Hiblot 		EXT_CSD_BUS_WIDTH_4,
11888ac8a263SJean-Jacques Hiblot 		EXT_CSD_BUS_WIDTH_1,
11898ac8a263SJean-Jacques Hiblot 	};
11908ac8a263SJean-Jacques Hiblot 	/* An array to map CSD bus widths to host cap bits */
11918ac8a263SJean-Jacques Hiblot 	static const unsigned int ext_to_hostcaps[] = {
11928ac8a263SJean-Jacques Hiblot 		[EXT_CSD_DDR_BUS_WIDTH_4] =
11938ac8a263SJean-Jacques Hiblot 			MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
11948ac8a263SJean-Jacques Hiblot 		[EXT_CSD_DDR_BUS_WIDTH_8] =
11958ac8a263SJean-Jacques Hiblot 			MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
11968ac8a263SJean-Jacques Hiblot 		[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
11978ac8a263SJean-Jacques Hiblot 		[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
11988ac8a263SJean-Jacques Hiblot 	};
11998ac8a263SJean-Jacques Hiblot 	/* An array to map chosen bus width to an integer */
12008ac8a263SJean-Jacques Hiblot 	static const unsigned int widths[] = {
12018ac8a263SJean-Jacques Hiblot 		8, 4, 8, 4, 1,
12028ac8a263SJean-Jacques Hiblot 	};
12038ac8a263SJean-Jacques Hiblot 	int err;
12048ac8a263SJean-Jacques Hiblot 	int idx;
12058ac8a263SJean-Jacques Hiblot 
12068ac8a263SJean-Jacques Hiblot 	err = mmc_change_freq(mmc);
12078ac8a263SJean-Jacques Hiblot 	if (err)
12088ac8a263SJean-Jacques Hiblot 		return err;
12098ac8a263SJean-Jacques Hiblot 
12108ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
12118ac8a263SJean-Jacques Hiblot 	mmc->card_caps &= mmc->cfg->host_caps;
12128ac8a263SJean-Jacques Hiblot 
12138ac8a263SJean-Jacques Hiblot 	/* Only version 4 of MMC supports wider bus widths */
12148ac8a263SJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
12158ac8a263SJean-Jacques Hiblot 		return 0;
12168ac8a263SJean-Jacques Hiblot 
1217dfda9d88SJean-Jacques Hiblot 	if (!mmc->ext_csd) {
1218dfda9d88SJean-Jacques Hiblot 		debug("No ext_csd found!\n"); /* this should enver happen */
1219dfda9d88SJean-Jacques Hiblot 		return -ENOTSUPP;
1220dfda9d88SJean-Jacques Hiblot 	}
1221dfda9d88SJean-Jacques Hiblot 
12228ac8a263SJean-Jacques Hiblot 	for (idx = 0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
12238ac8a263SJean-Jacques Hiblot 		unsigned int extw = ext_csd_bits[idx];
12248ac8a263SJean-Jacques Hiblot 		unsigned int caps = ext_to_hostcaps[extw];
12258ac8a263SJean-Jacques Hiblot 		/*
12268ac8a263SJean-Jacques Hiblot 		 * If the bus width is still not changed,
12278ac8a263SJean-Jacques Hiblot 		 * don't try to set the default again.
12288ac8a263SJean-Jacques Hiblot 		 * Otherwise, recover from switch attempts
12298ac8a263SJean-Jacques Hiblot 		 * by switching to 1-bit bus width.
12308ac8a263SJean-Jacques Hiblot 		 */
12318ac8a263SJean-Jacques Hiblot 		if (extw == EXT_CSD_BUS_WIDTH_1 &&
12328ac8a263SJean-Jacques Hiblot 		    mmc->bus_width == 1) {
12338ac8a263SJean-Jacques Hiblot 			err = 0;
12348ac8a263SJean-Jacques Hiblot 			break;
12358ac8a263SJean-Jacques Hiblot 		}
12368ac8a263SJean-Jacques Hiblot 
12378ac8a263SJean-Jacques Hiblot 		/*
12388ac8a263SJean-Jacques Hiblot 		 * Check to make sure the card and controller support
12398ac8a263SJean-Jacques Hiblot 		 * these capabilities
12408ac8a263SJean-Jacques Hiblot 		 */
12418ac8a263SJean-Jacques Hiblot 		if ((mmc->card_caps & caps) != caps)
12428ac8a263SJean-Jacques Hiblot 			continue;
12438ac8a263SJean-Jacques Hiblot 
12448ac8a263SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
12458ac8a263SJean-Jacques Hiblot 				 EXT_CSD_BUS_WIDTH, extw);
12468ac8a263SJean-Jacques Hiblot 
12478ac8a263SJean-Jacques Hiblot 		if (err)
12488ac8a263SJean-Jacques Hiblot 			continue;
12498ac8a263SJean-Jacques Hiblot 
12508ac8a263SJean-Jacques Hiblot 		mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
12518ac8a263SJean-Jacques Hiblot 		mmc_set_bus_width(mmc, widths[idx]);
12528ac8a263SJean-Jacques Hiblot 
1253*7382e691SJean-Jacques Hiblot 		err = mmc_read_and_compare_ext_csd(mmc);
1254*7382e691SJean-Jacques Hiblot 		if (!err)
12558ac8a263SJean-Jacques Hiblot 			break;
12568ac8a263SJean-Jacques Hiblot 	}
12578ac8a263SJean-Jacques Hiblot 
12588ac8a263SJean-Jacques Hiblot 	if (err)
12598ac8a263SJean-Jacques Hiblot 		return err;
12608ac8a263SJean-Jacques Hiblot 
12618ac8a263SJean-Jacques Hiblot 	if (mmc->card_caps & MMC_MODE_HS) {
12628ac8a263SJean-Jacques Hiblot 		if (mmc->card_caps & MMC_MODE_HS_52MHz)
12638ac8a263SJean-Jacques Hiblot 			mmc->tran_speed = 52000000;
12648ac8a263SJean-Jacques Hiblot 		else
12658ac8a263SJean-Jacques Hiblot 			mmc->tran_speed = 26000000;
12668ac8a263SJean-Jacques Hiblot 	}
12678ac8a263SJean-Jacques Hiblot 
12688ac8a263SJean-Jacques Hiblot 	return err;
12698ac8a263SJean-Jacques Hiblot }
12708ac8a263SJean-Jacques Hiblot 
1271dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
1272c744b6f6SJean-Jacques Hiblot {
1273c744b6f6SJean-Jacques Hiblot 	int err, i;
1274c744b6f6SJean-Jacques Hiblot 	u64 capacity;
1275c744b6f6SJean-Jacques Hiblot 	bool has_parts = false;
1276c744b6f6SJean-Jacques Hiblot 	bool part_completed;
1277dfda9d88SJean-Jacques Hiblot 	u8 *ext_csd;
1278c744b6f6SJean-Jacques Hiblot 
1279c744b6f6SJean-Jacques Hiblot 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
1280c744b6f6SJean-Jacques Hiblot 		return 0;
1281c744b6f6SJean-Jacques Hiblot 
1282dfda9d88SJean-Jacques Hiblot 	ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN);
1283dfda9d88SJean-Jacques Hiblot 	if (!ext_csd)
1284dfda9d88SJean-Jacques Hiblot 		return -ENOMEM;
1285dfda9d88SJean-Jacques Hiblot 
1286dfda9d88SJean-Jacques Hiblot 	mmc->ext_csd = ext_csd;
1287dfda9d88SJean-Jacques Hiblot 
1288c744b6f6SJean-Jacques Hiblot 	/* check  ext_csd version and capacity */
1289c744b6f6SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, ext_csd);
1290c744b6f6SJean-Jacques Hiblot 	if (err)
1291c744b6f6SJean-Jacques Hiblot 		return err;
1292c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_REV] >= 2) {
1293c744b6f6SJean-Jacques Hiblot 		/*
1294c744b6f6SJean-Jacques Hiblot 		 * According to the JEDEC Standard, the value of
1295c744b6f6SJean-Jacques Hiblot 		 * ext_csd's capacity is valid if the value is more
1296c744b6f6SJean-Jacques Hiblot 		 * than 2GB
1297c744b6f6SJean-Jacques Hiblot 		 */
1298c744b6f6SJean-Jacques Hiblot 		capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
1299c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
1300c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
1301c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1302c744b6f6SJean-Jacques Hiblot 		capacity *= MMC_MAX_BLOCK_LEN;
1303c744b6f6SJean-Jacques Hiblot 		if ((capacity >> 20) > 2 * 1024)
1304c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1305c744b6f6SJean-Jacques Hiblot 	}
1306c744b6f6SJean-Jacques Hiblot 
1307c744b6f6SJean-Jacques Hiblot 	switch (ext_csd[EXT_CSD_REV]) {
1308c744b6f6SJean-Jacques Hiblot 	case 1:
1309c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_1;
1310c744b6f6SJean-Jacques Hiblot 		break;
1311c744b6f6SJean-Jacques Hiblot 	case 2:
1312c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_2;
1313c744b6f6SJean-Jacques Hiblot 		break;
1314c744b6f6SJean-Jacques Hiblot 	case 3:
1315c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_3;
1316c744b6f6SJean-Jacques Hiblot 		break;
1317c744b6f6SJean-Jacques Hiblot 	case 5:
1318c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_41;
1319c744b6f6SJean-Jacques Hiblot 		break;
1320c744b6f6SJean-Jacques Hiblot 	case 6:
1321c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_5;
1322c744b6f6SJean-Jacques Hiblot 		break;
1323c744b6f6SJean-Jacques Hiblot 	case 7:
1324c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_0;
1325c744b6f6SJean-Jacques Hiblot 		break;
1326c744b6f6SJean-Jacques Hiblot 	case 8:
1327c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_1;
1328c744b6f6SJean-Jacques Hiblot 		break;
1329c744b6f6SJean-Jacques Hiblot 	}
1330c744b6f6SJean-Jacques Hiblot 
1331c744b6f6SJean-Jacques Hiblot 	/* The partition data may be non-zero but it is only
1332c744b6f6SJean-Jacques Hiblot 	 * effective if PARTITION_SETTING_COMPLETED is set in
1333c744b6f6SJean-Jacques Hiblot 	 * EXT_CSD, so ignore any data if this bit is not set,
1334c744b6f6SJean-Jacques Hiblot 	 * except for enabling the high-capacity group size
1335c744b6f6SJean-Jacques Hiblot 	 * definition (see below).
1336c744b6f6SJean-Jacques Hiblot 	 */
1337c744b6f6SJean-Jacques Hiblot 	part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
1338c744b6f6SJean-Jacques Hiblot 			    EXT_CSD_PARTITION_SETTING_COMPLETED);
1339c744b6f6SJean-Jacques Hiblot 
1340c744b6f6SJean-Jacques Hiblot 	/* store the partition info of emmc */
1341c744b6f6SJean-Jacques Hiblot 	mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
1342c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
1343c744b6f6SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_BOOT_MULT])
1344c744b6f6SJean-Jacques Hiblot 		mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
1345c744b6f6SJean-Jacques Hiblot 	if (part_completed &&
1346c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
1347c744b6f6SJean-Jacques Hiblot 		mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
1348c744b6f6SJean-Jacques Hiblot 
1349c744b6f6SJean-Jacques Hiblot 	mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
1350c744b6f6SJean-Jacques Hiblot 
1351c744b6f6SJean-Jacques Hiblot 	mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
1352c744b6f6SJean-Jacques Hiblot 
1353c744b6f6SJean-Jacques Hiblot 	for (i = 0; i < 4; i++) {
1354c744b6f6SJean-Jacques Hiblot 		int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
1355c744b6f6SJean-Jacques Hiblot 		uint mult = (ext_csd[idx + 2] << 16) +
1356c744b6f6SJean-Jacques Hiblot 			(ext_csd[idx + 1] << 8) + ext_csd[idx];
1357c744b6f6SJean-Jacques Hiblot 		if (mult)
1358c744b6f6SJean-Jacques Hiblot 			has_parts = true;
1359c744b6f6SJean-Jacques Hiblot 		if (!part_completed)
1360c744b6f6SJean-Jacques Hiblot 			continue;
1361c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] = mult;
1362c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *=
1363c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1364c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1365c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] <<= 19;
1366c744b6f6SJean-Jacques Hiblot 	}
1367c744b6f6SJean-Jacques Hiblot 
1368c744b6f6SJean-Jacques Hiblot 	if (part_completed) {
1369c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size =
1370c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
1371c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
1372c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_SIZE_MULT];
1373c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1374c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1375c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size <<= 19;
1376c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_start =
1377c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
1378c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
1379c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
1380c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_START_ADDR];
1381c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity)
1382c744b6f6SJean-Jacques Hiblot 			mmc->enh_user_start <<= 9;
1383c744b6f6SJean-Jacques Hiblot 	}
1384c744b6f6SJean-Jacques Hiblot 
1385c744b6f6SJean-Jacques Hiblot 	/*
1386c744b6f6SJean-Jacques Hiblot 	 * Host needs to enable ERASE_GRP_DEF bit if device is
1387c744b6f6SJean-Jacques Hiblot 	 * partitioned. This bit will be lost every time after a reset
1388c744b6f6SJean-Jacques Hiblot 	 * or power off. This will affect erase size.
1389c744b6f6SJean-Jacques Hiblot 	 */
1390c744b6f6SJean-Jacques Hiblot 	if (part_completed)
1391c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1392c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
1393c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
1394c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1395c744b6f6SJean-Jacques Hiblot 	if (has_parts) {
1396c744b6f6SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1397c744b6f6SJean-Jacques Hiblot 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1398c744b6f6SJean-Jacques Hiblot 
1399c744b6f6SJean-Jacques Hiblot 		if (err)
1400c744b6f6SJean-Jacques Hiblot 			return err;
1401c744b6f6SJean-Jacques Hiblot 
1402c744b6f6SJean-Jacques Hiblot 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1403c744b6f6SJean-Jacques Hiblot 	}
1404c744b6f6SJean-Jacques Hiblot 
1405c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
1406c744b6f6SJean-Jacques Hiblot 		/* Read out group size from ext_csd */
1407c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size =
1408c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1409c744b6f6SJean-Jacques Hiblot 		/*
1410c744b6f6SJean-Jacques Hiblot 		 * if high capacity and partition setting completed
1411c744b6f6SJean-Jacques Hiblot 		 * SEC_COUNT is valid even if it is smaller than 2 GiB
1412c744b6f6SJean-Jacques Hiblot 		 * JEDEC Standard JESD84-B45, 6.2.4
1413c744b6f6SJean-Jacques Hiblot 		 */
1414c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity && part_completed) {
1415c744b6f6SJean-Jacques Hiblot 			capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1416c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1417c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1418c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1419c744b6f6SJean-Jacques Hiblot 			capacity *= MMC_MAX_BLOCK_LEN;
1420c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1421c744b6f6SJean-Jacques Hiblot 		}
1422c744b6f6SJean-Jacques Hiblot 	} else {
1423c744b6f6SJean-Jacques Hiblot 		/* Calculate the group size from the csd value. */
1424c744b6f6SJean-Jacques Hiblot 		int erase_gsz, erase_gmul;
1425c744b6f6SJean-Jacques Hiblot 
1426c744b6f6SJean-Jacques Hiblot 		erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1427c744b6f6SJean-Jacques Hiblot 		erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1428c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size = (erase_gsz + 1)
1429c744b6f6SJean-Jacques Hiblot 			* (erase_gmul + 1);
1430c744b6f6SJean-Jacques Hiblot 	}
1431c744b6f6SJean-Jacques Hiblot 
1432c744b6f6SJean-Jacques Hiblot 	mmc->hc_wp_grp_size = 1024
1433c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1434c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1435c744b6f6SJean-Jacques Hiblot 
1436c744b6f6SJean-Jacques Hiblot 	mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1437c744b6f6SJean-Jacques Hiblot 
1438c744b6f6SJean-Jacques Hiblot 	return 0;
1439c744b6f6SJean-Jacques Hiblot }
1440c744b6f6SJean-Jacques Hiblot 
1441fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1442272cc70bSAndy Fleming {
1443f866a46dSStephen Warren 	int err, i;
1444272cc70bSAndy Fleming 	uint mult, freq;
1445c744b6f6SJean-Jacques Hiblot 	u64 cmult, csize;
1446272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1447c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1448272cc70bSAndy Fleming 
1449d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1450d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1451d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1452d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1453d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1454d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1455d52ebf10SThomas Chou 
1456d52ebf10SThomas Chou 		if (err)
1457d52ebf10SThomas Chou 			return err;
1458d52ebf10SThomas Chou 	}
1459d52ebf10SThomas Chou #endif
1460d52ebf10SThomas Chou 
1461272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1462d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1463d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1464272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1465272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1466272cc70bSAndy Fleming 
1467272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1468272cc70bSAndy Fleming 
1469272cc70bSAndy Fleming 	if (err)
1470272cc70bSAndy Fleming 		return err;
1471272cc70bSAndy Fleming 
1472272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1473272cc70bSAndy Fleming 
1474272cc70bSAndy Fleming 	/*
1475272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1476272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1477272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1478272cc70bSAndy Fleming 	 */
1479d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1480272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1481272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1482272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1483272cc70bSAndy Fleming 
1484272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1485272cc70bSAndy Fleming 
1486272cc70bSAndy Fleming 		if (err)
1487272cc70bSAndy Fleming 			return err;
1488272cc70bSAndy Fleming 
1489272cc70bSAndy Fleming 		if (IS_SD(mmc))
1490998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1491d52ebf10SThomas Chou 	}
1492272cc70bSAndy Fleming 
1493272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1494272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1495272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1496272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1497272cc70bSAndy Fleming 
1498272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1499272cc70bSAndy Fleming 
1500272cc70bSAndy Fleming 	if (err)
1501272cc70bSAndy Fleming 		return err;
1502272cc70bSAndy Fleming 
1503998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1504998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1505998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1506998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1507272cc70bSAndy Fleming 
1508272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
15090b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1510272cc70bSAndy Fleming 
1511272cc70bSAndy Fleming 		switch (version) {
1512272cc70bSAndy Fleming 		case 0:
1513272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1514272cc70bSAndy Fleming 			break;
1515272cc70bSAndy Fleming 		case 1:
1516272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1517272cc70bSAndy Fleming 			break;
1518272cc70bSAndy Fleming 		case 2:
1519272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1520272cc70bSAndy Fleming 			break;
1521272cc70bSAndy Fleming 		case 3:
1522272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1523272cc70bSAndy Fleming 			break;
1524272cc70bSAndy Fleming 		case 4:
1525272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1526272cc70bSAndy Fleming 			break;
1527272cc70bSAndy Fleming 		default:
1528272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1529272cc70bSAndy Fleming 			break;
1530272cc70bSAndy Fleming 		}
1531272cc70bSAndy Fleming 	}
1532272cc70bSAndy Fleming 
1533272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
15340b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
15350b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1536272cc70bSAndy Fleming 
1537272cc70bSAndy Fleming 	mmc->tran_speed = freq * mult;
1538272cc70bSAndy Fleming 
1539ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1540998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1541272cc70bSAndy Fleming 
1542272cc70bSAndy Fleming 	if (IS_SD(mmc))
1543272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1544272cc70bSAndy Fleming 	else
1545998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1546272cc70bSAndy Fleming 
1547272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1548272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1549272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1550272cc70bSAndy Fleming 		cmult = 8;
1551272cc70bSAndy Fleming 	} else {
1552272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1553272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1554272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1555272cc70bSAndy Fleming 	}
1556272cc70bSAndy Fleming 
1557f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1558f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1559f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1560f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1561f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1562f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1563272cc70bSAndy Fleming 
15648bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
15658bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1566272cc70bSAndy Fleming 
15678bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
15688bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1569272cc70bSAndy Fleming 
1570ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1571ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1572ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1573ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1574ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1575ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1576ab71188cSMarkus Niebel 	}
1577ab71188cSMarkus Niebel 
1578272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1579d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1580272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1581fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1582272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1583272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1584272cc70bSAndy Fleming 
1585272cc70bSAndy Fleming 		if (err)
1586272cc70bSAndy Fleming 			return err;
1587d52ebf10SThomas Chou 	}
1588272cc70bSAndy Fleming 
1589e6f99a56SLei Wen 	/*
1590e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1591e6f99a56SLei Wen 	 */
1592e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1593bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1594c744b6f6SJean-Jacques Hiblot 
1595dfda9d88SJean-Jacques Hiblot 	err = mmc_startup_v4(mmc);
15969cf199ebSDiego Santa Cruz 	if (err)
15979cf199ebSDiego Santa Cruz 		return err;
1598f866a46dSStephen Warren 
1599c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
1600f866a46dSStephen Warren 	if (err)
1601f866a46dSStephen Warren 		return err;
1602d23e2c09SSukumar Ghorai 
1603272cc70bSAndy Fleming 	if (IS_SD(mmc))
16048ac8a263SJean-Jacques Hiblot 		err = sd_select_bus_freq_width(mmc);
1605272cc70bSAndy Fleming 	else
1606dfda9d88SJean-Jacques Hiblot 		err = mmc_select_bus_freq_width(mmc);
1607272cc70bSAndy Fleming 
1608272cc70bSAndy Fleming 	if (err)
1609272cc70bSAndy Fleming 		return err;
1610272cc70bSAndy Fleming 
1611ad5fd922SJaehoon Chung 	mmc_set_clock(mmc, mmc->tran_speed);
1612272cc70bSAndy Fleming 
16135af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
16145af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
16155af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
16165af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
16175af8f45cSAndrew Gabbasov 	}
16185af8f45cSAndrew Gabbasov 
1619272cc70bSAndy Fleming 	/* fill in device description */
1620c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1621c40fdca6SSimon Glass 	bdesc->lun = 0;
1622c40fdca6SSimon Glass 	bdesc->hwpart = 0;
1623c40fdca6SSimon Glass 	bdesc->type = 0;
1624c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
1625c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
1626c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1627fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1628fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1629fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1630c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
1631babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1632babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1633c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
16340b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1635babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1636babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1637c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1638babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
163956196826SPaul Burton #else
1640c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
1641c40fdca6SSimon Glass 	bdesc->product[0] = 0;
1642c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
164356196826SPaul Burton #endif
1644122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1645c40fdca6SSimon Glass 	part_init(bdesc);
1646122efd43SMikhail Kshevetskiy #endif
1647272cc70bSAndy Fleming 
1648272cc70bSAndy Fleming 	return 0;
1649272cc70bSAndy Fleming }
1650272cc70bSAndy Fleming 
1651fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1652272cc70bSAndy Fleming {
1653272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1654272cc70bSAndy Fleming 	int err;
1655272cc70bSAndy Fleming 
1656272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1657272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
165893bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1659272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1660272cc70bSAndy Fleming 
1661272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1662272cc70bSAndy Fleming 
1663272cc70bSAndy Fleming 	if (err)
1664272cc70bSAndy Fleming 		return err;
1665272cc70bSAndy Fleming 
1666998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1667915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
1668272cc70bSAndy Fleming 	else
1669272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1670272cc70bSAndy Fleming 
1671272cc70bSAndy Fleming 	return 0;
1672272cc70bSAndy Fleming }
1673272cc70bSAndy Fleming 
1674c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
167595de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
167695de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
167795de9ab2SPaul Kocialkowski {
167895de9ab2SPaul Kocialkowski }
167905cbeb7cSSimon Glass #endif
168095de9ab2SPaul Kocialkowski 
16812051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
16822051aefeSPeng Fan {
1683c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
168406ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
16852051aefeSPeng Fan 	int ret;
16862051aefeSPeng Fan 
16872051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
168806ec045fSJean-Jacques Hiblot 					  &mmc->vmmc_supply);
168906ec045fSJean-Jacques Hiblot 	if (ret)
1690288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
16912051aefeSPeng Fan 
169206ec045fSJean-Jacques Hiblot 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
169306ec045fSJean-Jacques Hiblot 					  &mmc->vqmmc_supply);
169406ec045fSJean-Jacques Hiblot 	if (ret)
169506ec045fSJean-Jacques Hiblot 		debug("%s: No vqmmc supply\n", mmc->dev->name);
169606ec045fSJean-Jacques Hiblot 
169706ec045fSJean-Jacques Hiblot 	if (mmc->vmmc_supply) {
169806ec045fSJean-Jacques Hiblot 		ret = regulator_set_enable(mmc->vmmc_supply, true);
16992051aefeSPeng Fan 		if (ret) {
17002051aefeSPeng Fan 			puts("Error enabling VMMC supply\n");
17012051aefeSPeng Fan 			return ret;
17022051aefeSPeng Fan 		}
170306ec045fSJean-Jacques Hiblot 	}
17042051aefeSPeng Fan #endif
170505cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
170605cbeb7cSSimon Glass 	/*
170705cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
170805cbeb7cSSimon Glass 	 * out to board code.
170905cbeb7cSSimon Glass 	 */
171005cbeb7cSSimon Glass 	board_mmc_power_init();
171105cbeb7cSSimon Glass #endif
17122051aefeSPeng Fan 	return 0;
17132051aefeSPeng Fan }
17142051aefeSPeng Fan 
1715e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1716272cc70bSAndy Fleming {
17178ca51e51SSimon Glass 	bool no_card;
1718afd5932bSMacpaul Lin 	int err;
1719272cc70bSAndy Fleming 
1720ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
17218ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
1722e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
17238ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
17248ca51e51SSimon Glass #endif
17258ca51e51SSimon Glass 	if (no_card) {
172648972d90SThierry Reding 		mmc->has_init = 0;
172756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
172848972d90SThierry Reding 		printf("MMC: no card present\n");
172956196826SPaul Burton #endif
1730915ffa52SJaehoon Chung 		return -ENOMEDIUM;
173148972d90SThierry Reding 	}
173248972d90SThierry Reding 
1733bc897b1dSLei Wen 	if (mmc->has_init)
1734bc897b1dSLei Wen 		return 0;
1735bc897b1dSLei Wen 
17365a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
17375a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
17385a8dbdc6SYangbo Lu #endif
17392051aefeSPeng Fan 	err = mmc_power_init(mmc);
17402051aefeSPeng Fan 	if (err)
17412051aefeSPeng Fan 		return err;
174295de9ab2SPaul Kocialkowski 
1743e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
17448ca51e51SSimon Glass 	/* The device has already been probed ready for use */
17458ca51e51SSimon Glass #else
1746ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
174793bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
1748272cc70bSAndy Fleming 	if (err)
1749272cc70bSAndy Fleming 		return err;
17508ca51e51SSimon Glass #endif
1751786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
1752b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1753b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1754b86b85e2SIlya Yanok 
1755272cc70bSAndy Fleming 	/* Reset the Card */
1756272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1757272cc70bSAndy Fleming 
1758272cc70bSAndy Fleming 	if (err)
1759272cc70bSAndy Fleming 		return err;
1760272cc70bSAndy Fleming 
1761bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1762c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
1763bc897b1dSLei Wen 
1764272cc70bSAndy Fleming 	/* Test for SD version 2 */
1765272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1766272cc70bSAndy Fleming 
1767272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1768272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1769272cc70bSAndy Fleming 
1770272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1771915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
1772272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1773272cc70bSAndy Fleming 
1774bd47c135SAndrew Gabbasov 		if (err) {
177556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1776272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
177756196826SPaul Burton #endif
1778915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
1779272cc70bSAndy Fleming 		}
1780272cc70bSAndy Fleming 	}
1781272cc70bSAndy Fleming 
1782bd47c135SAndrew Gabbasov 	if (!err)
1783e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
1784e9550449SChe-Liang Chiou 
1785e9550449SChe-Liang Chiou 	return err;
1786e9550449SChe-Liang Chiou }
1787e9550449SChe-Liang Chiou 
1788e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
1789e9550449SChe-Liang Chiou {
1790e9550449SChe-Liang Chiou 	int err = 0;
1791e9550449SChe-Liang Chiou 
1792bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
1793e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
1794e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
1795e9550449SChe-Liang Chiou 
1796e9550449SChe-Liang Chiou 	if (!err)
1797bc897b1dSLei Wen 		err = mmc_startup(mmc);
1798bc897b1dSLei Wen 	if (err)
1799bc897b1dSLei Wen 		mmc->has_init = 0;
1800bc897b1dSLei Wen 	else
1801bc897b1dSLei Wen 		mmc->has_init = 1;
1802e9550449SChe-Liang Chiou 	return err;
1803e9550449SChe-Liang Chiou }
1804e9550449SChe-Liang Chiou 
1805e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
1806e9550449SChe-Liang Chiou {
1807bd47c135SAndrew Gabbasov 	int err = 0;
1808ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
1809c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
181033fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
1811e9550449SChe-Liang Chiou 
181233fb211dSSimon Glass 	upriv->mmc = mmc;
181333fb211dSSimon Glass #endif
1814e9550449SChe-Liang Chiou 	if (mmc->has_init)
1815e9550449SChe-Liang Chiou 		return 0;
1816d803fea5SMateusz Zalega 
1817d803fea5SMateusz Zalega 	start = get_timer(0);
1818d803fea5SMateusz Zalega 
1819e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
1820e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
1821e9550449SChe-Liang Chiou 
1822bd47c135SAndrew Gabbasov 	if (!err)
1823e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
1824919b4858SJagan Teki 	if (err)
1825919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
1826919b4858SJagan Teki 
1827bc897b1dSLei Wen 	return err;
1828272cc70bSAndy Fleming }
1829272cc70bSAndy Fleming 
1830ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
1831ab71188cSMarkus Niebel {
1832ab71188cSMarkus Niebel 	mmc->dsr = val;
1833ab71188cSMarkus Niebel 	return 0;
1834ab71188cSMarkus Niebel }
1835ab71188cSMarkus Niebel 
1836cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
1837cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
1838272cc70bSAndy Fleming {
1839272cc70bSAndy Fleming 	return -1;
1840272cc70bSAndy Fleming }
1841272cc70bSAndy Fleming 
1842cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
1843cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
1844cee9ab7cSJeroen Hofstee {
1845cee9ab7cSJeroen Hofstee 	return -1;
1846cee9ab7cSJeroen Hofstee }
1847272cc70bSAndy Fleming 
1848e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
1849e9550449SChe-Liang Chiou {
1850e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
1851e9550449SChe-Liang Chiou }
1852e9550449SChe-Liang Chiou 
1853c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
18548e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
18558e3332e2SSjoerd Simons {
18568e3332e2SSjoerd Simons 	return 0;
18578e3332e2SSjoerd Simons }
1858c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
18598e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
18608e3332e2SSjoerd Simons {
18614a1db6d8SSimon Glass 	int ret, i;
18628e3332e2SSjoerd Simons 	struct uclass *uc;
18634a1db6d8SSimon Glass 	struct udevice *dev;
18648e3332e2SSjoerd Simons 
18658e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
18668e3332e2SSjoerd Simons 	if (ret)
18678e3332e2SSjoerd Simons 		return ret;
18688e3332e2SSjoerd Simons 
18694a1db6d8SSimon Glass 	/*
18704a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
18714a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
18724a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
18734a1db6d8SSimon Glass 	 */
18744a1db6d8SSimon Glass 	for (i = 0; ; i++) {
18754a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
18764a1db6d8SSimon Glass 		if (ret == -ENODEV)
18774a1db6d8SSimon Glass 			break;
18784a1db6d8SSimon Glass 	}
18794a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
18804a1db6d8SSimon Glass 		ret = device_probe(dev);
18818e3332e2SSjoerd Simons 		if (ret)
18824a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
18838e3332e2SSjoerd Simons 	}
18848e3332e2SSjoerd Simons 
18858e3332e2SSjoerd Simons 	return 0;
18868e3332e2SSjoerd Simons }
18878e3332e2SSjoerd Simons #else
18888e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
18898e3332e2SSjoerd Simons {
18908e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
18918e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
18928e3332e2SSjoerd Simons 
18938e3332e2SSjoerd Simons 	return 0;
18948e3332e2SSjoerd Simons }
18958e3332e2SSjoerd Simons #endif
1896e9550449SChe-Liang Chiou 
1897272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1898272cc70bSAndy Fleming {
18991b26bab1SDaniel Kochmański 	static int initialized = 0;
19008e3332e2SSjoerd Simons 	int ret;
19011b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
19021b26bab1SDaniel Kochmański 		return 0;
19031b26bab1SDaniel Kochmański 	initialized = 1;
19041b26bab1SDaniel Kochmański 
1905c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
1906b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
1907c40fdca6SSimon Glass 	mmc_list_init();
1908c40fdca6SSimon Glass #endif
1909b5b838f1SMarek Vasut #endif
19108e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
19118e3332e2SSjoerd Simons 	if (ret)
19128e3332e2SSjoerd Simons 		return ret;
1913272cc70bSAndy Fleming 
1914bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
1915272cc70bSAndy Fleming 	print_mmc_devices(',');
1916bb0dc108SYing Zhang #endif
1917272cc70bSAndy Fleming 
1918c40fdca6SSimon Glass 	mmc_do_preinit();
1919272cc70bSAndy Fleming 	return 0;
1920272cc70bSAndy Fleming }
1921cd3d4880STomas Melin 
1922cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
1923cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
1924cd3d4880STomas Melin {
1925cd3d4880STomas Melin 	int err;
1926cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
1927cd3d4880STomas Melin 
1928cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
1929cd3d4880STomas Melin 	if (err) {
1930cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
1931cd3d4880STomas Melin 		return err;
1932cd3d4880STomas Melin 	}
1933cd3d4880STomas Melin 
1934cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
1935cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
1936cd3d4880STomas Melin 		return -EMEDIUMTYPE;
1937cd3d4880STomas Melin 	}
1938cd3d4880STomas Melin 
1939cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
1940cd3d4880STomas Melin 		puts("Background operations already enabled\n");
1941cd3d4880STomas Melin 		return 0;
1942cd3d4880STomas Melin 	}
1943cd3d4880STomas Melin 
1944cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
1945cd3d4880STomas Melin 	if (err) {
1946cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
1947cd3d4880STomas Melin 		return err;
1948cd3d4880STomas Melin 	}
1949cd3d4880STomas Melin 
1950cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
1951cd3d4880STomas Melin 
1952cd3d4880STomas Melin 	return 0;
1953cd3d4880STomas Melin }
1954cd3d4880STomas Melin #endif
1955