xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision c40fdca6b7db469d3982cc44fd68a269adb41b25)
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>
18272cc70bSAndy Fleming #include <malloc.h>
19cf92e05cSSimon Glass #include <memalign.h>
20272cc70bSAndy Fleming #include <linux/list.h>
219b1f942cSRabin Vincent #include <div64.h>
22da61fa5fSPaul Burton #include "mmc_private.h"
23272cc70bSAndy Fleming 
24750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
25d23d8d7eSNikita Kiryanov {
26d23d8d7eSNikita Kiryanov 	return -1;
27d23d8d7eSNikita Kiryanov }
28d23d8d7eSNikita Kiryanov 
29d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
30d23d8d7eSNikita Kiryanov {
31d23d8d7eSNikita Kiryanov 	int wp;
32d23d8d7eSNikita Kiryanov 
33d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
34d23d8d7eSNikita Kiryanov 
35d4e1da4eSPeter Korsgaard 	if (wp < 0) {
3693bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
3793bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
38d4e1da4eSPeter Korsgaard 		else
39d4e1da4eSPeter Korsgaard 			wp = 0;
40d4e1da4eSPeter Korsgaard 	}
41d23d8d7eSNikita Kiryanov 
42d23d8d7eSNikita Kiryanov 	return wp;
43d23d8d7eSNikita Kiryanov }
44d23d8d7eSNikita Kiryanov 
45cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc)
46cee9ab7cSJeroen Hofstee {
4711fdade2SStefano Babic 	return -1;
4811fdade2SStefano Babic }
4911fdade2SStefano Babic 
50da61fa5fSPaul Burton int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
51272cc70bSAndy Fleming {
525db2fe3aSRaffaele Recalcati 	int ret;
538635ff9eSMarek Vasut 
548635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
555db2fe3aSRaffaele Recalcati 	int i;
565db2fe3aSRaffaele Recalcati 	u8 *ptr;
575db2fe3aSRaffaele Recalcati 
585db2fe3aSRaffaele Recalcati 	printf("CMD_SEND:%d\n", cmd->cmdidx);
595db2fe3aSRaffaele Recalcati 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
6093bfd616SPantelis Antoniou 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
617863ce58SBin Meng 	if (ret) {
627863ce58SBin Meng 		printf("\t\tRET\t\t\t %d\n", ret);
637863ce58SBin Meng 	} else {
645db2fe3aSRaffaele Recalcati 		switch (cmd->resp_type) {
655db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
665db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
675db2fe3aSRaffaele Recalcati 			break;
685db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
695db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
705db2fe3aSRaffaele Recalcati 				cmd->response[0]);
715db2fe3aSRaffaele Recalcati 			break;
725db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
735db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
745db2fe3aSRaffaele Recalcati 				cmd->response[0]);
755db2fe3aSRaffaele Recalcati 			break;
765db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
775db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
785db2fe3aSRaffaele Recalcati 				cmd->response[0]);
795db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
805db2fe3aSRaffaele Recalcati 				cmd->response[1]);
815db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
825db2fe3aSRaffaele Recalcati 				cmd->response[2]);
835db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
845db2fe3aSRaffaele Recalcati 				cmd->response[3]);
855db2fe3aSRaffaele Recalcati 			printf("\n");
865db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
875db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
885db2fe3aSRaffaele Recalcati 				int j;
895db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
90146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
915db2fe3aSRaffaele Recalcati 				ptr += 3;
925db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
935db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
945db2fe3aSRaffaele Recalcati 				printf("\n");
955db2fe3aSRaffaele Recalcati 			}
965db2fe3aSRaffaele Recalcati 			break;
975db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
985db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
995db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1005db2fe3aSRaffaele Recalcati 			break;
1015db2fe3aSRaffaele Recalcati 		default:
1025db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1035db2fe3aSRaffaele Recalcati 			break;
1045db2fe3aSRaffaele Recalcati 		}
1057863ce58SBin Meng 	}
1065db2fe3aSRaffaele Recalcati #else
10793bfd616SPantelis Antoniou 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
1085db2fe3aSRaffaele Recalcati #endif
1098635ff9eSMarek Vasut 	return ret;
110272cc70bSAndy Fleming }
111272cc70bSAndy Fleming 
112da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
1135d4fc8d9SRaffaele Recalcati {
1145d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
115d617c426SJan Kloetzke 	int err, retries = 5;
1165d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
1175d4fc8d9SRaffaele Recalcati 	int status;
1185d4fc8d9SRaffaele Recalcati #endif
1195d4fc8d9SRaffaele Recalcati 
1205d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
1215d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
122aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
123aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
1245d4fc8d9SRaffaele Recalcati 
1251677eef4SAndrew Gabbasov 	while (1) {
1265d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
127d617c426SJan Kloetzke 		if (!err) {
128d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
129d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
130d617c426SJan Kloetzke 			     MMC_STATE_PRG)
1315d4fc8d9SRaffaele Recalcati 				break;
132d617c426SJan Kloetzke 			else if (cmd.response[0] & MMC_STATUS_MASK) {
13356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
134d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
135d617c426SJan Kloetzke 					cmd.response[0]);
13656196826SPaul Burton #endif
137d617c426SJan Kloetzke 				return COMM_ERR;
138d617c426SJan Kloetzke 			}
139d617c426SJan Kloetzke 		} else if (--retries < 0)
140d617c426SJan Kloetzke 			return err;
1415d4fc8d9SRaffaele Recalcati 
1421677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
1431677eef4SAndrew Gabbasov 			break;
1445d4fc8d9SRaffaele Recalcati 
1451677eef4SAndrew Gabbasov 		udelay(1000);
1461677eef4SAndrew Gabbasov 	}
1475d4fc8d9SRaffaele Recalcati 
1485db2fe3aSRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
1495db2fe3aSRaffaele Recalcati 	status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9;
1505db2fe3aSRaffaele Recalcati 	printf("CURR STATE:%d\n", status);
1515db2fe3aSRaffaele Recalcati #endif
1525b0c942fSJongman Heo 	if (timeout <= 0) {
15356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1545d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
15556196826SPaul Burton #endif
1565d4fc8d9SRaffaele Recalcati 		return TIMEOUT;
1575d4fc8d9SRaffaele Recalcati 	}
1586b2221b0SAndrew Gabbasov 	if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR)
1596b2221b0SAndrew Gabbasov 		return SWITCH_ERR;
1605d4fc8d9SRaffaele Recalcati 
1615d4fc8d9SRaffaele Recalcati 	return 0;
1625d4fc8d9SRaffaele Recalcati }
1635d4fc8d9SRaffaele Recalcati 
164da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
165272cc70bSAndy Fleming {
166272cc70bSAndy Fleming 	struct mmc_cmd cmd;
167272cc70bSAndy Fleming 
168786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
169d22e3d46SJaehoon Chung 		return 0;
170d22e3d46SJaehoon Chung 
171272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
172272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
173272cc70bSAndy Fleming 	cmd.cmdarg = len;
174272cc70bSAndy Fleming 
175272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
176272cc70bSAndy Fleming }
177272cc70bSAndy Fleming 
178ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
179fdbb873eSKim Phillips 			   lbaint_t blkcnt)
180272cc70bSAndy Fleming {
181272cc70bSAndy Fleming 	struct mmc_cmd cmd;
182272cc70bSAndy Fleming 	struct mmc_data data;
183272cc70bSAndy Fleming 
1844a1a06bcSAlagu Sankar 	if (blkcnt > 1)
1854a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
1864a1a06bcSAlagu Sankar 	else
187272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
188272cc70bSAndy Fleming 
189272cc70bSAndy Fleming 	if (mmc->high_capacity)
1904a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
191272cc70bSAndy Fleming 	else
1924a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
193272cc70bSAndy Fleming 
194272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
195272cc70bSAndy Fleming 
196272cc70bSAndy Fleming 	data.dest = dst;
1974a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
198272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
199272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
200272cc70bSAndy Fleming 
2014a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
2024a1a06bcSAlagu Sankar 		return 0;
2034a1a06bcSAlagu Sankar 
2044a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
2054a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
2064a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
2074a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
2084a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
20956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2104a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
21156196826SPaul Burton #endif
2124a1a06bcSAlagu Sankar 			return 0;
2134a1a06bcSAlagu Sankar 		}
214272cc70bSAndy Fleming 	}
215272cc70bSAndy Fleming 
2164a1a06bcSAlagu Sankar 	return blkcnt;
217272cc70bSAndy Fleming }
218272cc70bSAndy Fleming 
2194101f687SSimon Glass static ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start,
2207c4213f6SStephen Warren 		       lbaint_t blkcnt, void *dst)
221272cc70bSAndy Fleming {
222bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
223873cc1d7SStephen Warren 	int err;
2244a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
225272cc70bSAndy Fleming 
2264a1a06bcSAlagu Sankar 	if (blkcnt == 0)
2274a1a06bcSAlagu Sankar 		return 0;
2284a1a06bcSAlagu Sankar 
2294a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
230272cc70bSAndy Fleming 	if (!mmc)
231272cc70bSAndy Fleming 		return 0;
232272cc70bSAndy Fleming 
23369f45cd5SSimon Glass 	err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
234873cc1d7SStephen Warren 	if (err < 0)
235873cc1d7SStephen Warren 		return 0;
236873cc1d7SStephen Warren 
237*c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
23856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
239ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
240*c40fdca6SSimon Glass 			start + blkcnt, block_dev->lba);
24156196826SPaul Burton #endif
242d2bf29e3SLei Wen 		return 0;
243d2bf29e3SLei Wen 	}
244272cc70bSAndy Fleming 
24511692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
24611692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
247272cc70bSAndy Fleming 		return 0;
24811692991SSimon Glass 	}
249272cc70bSAndy Fleming 
2504a1a06bcSAlagu Sankar 	do {
25193bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
25293bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
25311692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
25411692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
2554a1a06bcSAlagu Sankar 			return 0;
25611692991SSimon Glass 		}
2574a1a06bcSAlagu Sankar 		blocks_todo -= cur;
2584a1a06bcSAlagu Sankar 		start += cur;
2594a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
2604a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
261272cc70bSAndy Fleming 
262272cc70bSAndy Fleming 	return blkcnt;
263272cc70bSAndy Fleming }
264272cc70bSAndy Fleming 
265fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
266272cc70bSAndy Fleming {
267272cc70bSAndy Fleming 	struct mmc_cmd cmd;
268272cc70bSAndy Fleming 	int err;
269272cc70bSAndy Fleming 
270272cc70bSAndy Fleming 	udelay(1000);
271272cc70bSAndy Fleming 
272272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
273272cc70bSAndy Fleming 	cmd.cmdarg = 0;
274272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
275272cc70bSAndy Fleming 
276272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
277272cc70bSAndy Fleming 
278272cc70bSAndy Fleming 	if (err)
279272cc70bSAndy Fleming 		return err;
280272cc70bSAndy Fleming 
281272cc70bSAndy Fleming 	udelay(2000);
282272cc70bSAndy Fleming 
283272cc70bSAndy Fleming 	return 0;
284272cc70bSAndy Fleming }
285272cc70bSAndy Fleming 
286fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
287272cc70bSAndy Fleming {
288272cc70bSAndy Fleming 	int timeout = 1000;
289272cc70bSAndy Fleming 	int err;
290272cc70bSAndy Fleming 	struct mmc_cmd cmd;
291272cc70bSAndy Fleming 
2921677eef4SAndrew Gabbasov 	while (1) {
293272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
294272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
295272cc70bSAndy Fleming 		cmd.cmdarg = 0;
296272cc70bSAndy Fleming 
297272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
298272cc70bSAndy Fleming 
299272cc70bSAndy Fleming 		if (err)
300272cc70bSAndy Fleming 			return err;
301272cc70bSAndy Fleming 
302272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
303272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
304250de12bSStefano Babic 
305250de12bSStefano Babic 		/*
306250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
307250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
308250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
309250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
310250de12bSStefano Babic 		 * specified.
311250de12bSStefano Babic 		 */
312d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
31393bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
314272cc70bSAndy Fleming 
315272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
316272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
317272cc70bSAndy Fleming 
318272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
319272cc70bSAndy Fleming 
320272cc70bSAndy Fleming 		if (err)
321272cc70bSAndy Fleming 			return err;
322272cc70bSAndy Fleming 
3231677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
3241677eef4SAndrew Gabbasov 			break;
325272cc70bSAndy Fleming 
3261677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
327272cc70bSAndy Fleming 			return UNUSABLE_ERR;
328272cc70bSAndy Fleming 
3291677eef4SAndrew Gabbasov 		udelay(1000);
3301677eef4SAndrew Gabbasov 	}
3311677eef4SAndrew Gabbasov 
332272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
333272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
334272cc70bSAndy Fleming 
335d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
336d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
337d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
338d52ebf10SThomas Chou 		cmd.cmdarg = 0;
339d52ebf10SThomas Chou 
340d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
341d52ebf10SThomas Chou 
342d52ebf10SThomas Chou 		if (err)
343d52ebf10SThomas Chou 			return err;
344d52ebf10SThomas Chou 	}
345d52ebf10SThomas Chou 
346998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
347272cc70bSAndy Fleming 
348272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
349272cc70bSAndy Fleming 	mmc->rca = 0;
350272cc70bSAndy Fleming 
351272cc70bSAndy Fleming 	return 0;
352272cc70bSAndy Fleming }
353272cc70bSAndy Fleming 
3545289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
355272cc70bSAndy Fleming {
3565289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
357272cc70bSAndy Fleming 	int err;
358272cc70bSAndy Fleming 
3595289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
3605289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
3615289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
3625a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
3635a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
36493bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
365a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
366a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
367e9550449SChe-Liang Chiou 
3685289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
369e9550449SChe-Liang Chiou 	if (err)
370e9550449SChe-Liang Chiou 		return err;
3715289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
372e9550449SChe-Liang Chiou 	return 0;
373e9550449SChe-Liang Chiou }
374e9550449SChe-Liang Chiou 
375750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
376e9550449SChe-Liang Chiou {
377e9550449SChe-Liang Chiou 	int err, i;
378e9550449SChe-Liang Chiou 
379272cc70bSAndy Fleming 	/* Some cards seem to need this */
380272cc70bSAndy Fleming 	mmc_go_idle(mmc);
381272cc70bSAndy Fleming 
38231cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
383e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
3845289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
38531cacbabSRaffaele Recalcati 		if (err)
38631cacbabSRaffaele Recalcati 			return err;
38731cacbabSRaffaele Recalcati 
388e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
389a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
390bd47c135SAndrew Gabbasov 			break;
391e9550449SChe-Liang Chiou 	}
392bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
393bd47c135SAndrew Gabbasov 	return 0;
394e9550449SChe-Liang Chiou }
39531cacbabSRaffaele Recalcati 
396750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
397e9550449SChe-Liang Chiou {
398e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
399e9550449SChe-Liang Chiou 	int timeout = 1000;
400e9550449SChe-Liang Chiou 	uint start;
401e9550449SChe-Liang Chiou 	int err;
402e9550449SChe-Liang Chiou 
403e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
404cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
405e9550449SChe-Liang Chiou 		start = get_timer(0);
4061677eef4SAndrew Gabbasov 		while (1) {
4075289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
408272cc70bSAndy Fleming 			if (err)
409272cc70bSAndy Fleming 				return err;
4101677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
4111677eef4SAndrew Gabbasov 				break;
412e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
413272cc70bSAndy Fleming 				return UNUSABLE_ERR;
414e9550449SChe-Liang Chiou 			udelay(100);
4151677eef4SAndrew Gabbasov 		}
416cc17c01fSAndrew Gabbasov 	}
417272cc70bSAndy Fleming 
418d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
419d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
420d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
421d52ebf10SThomas Chou 		cmd.cmdarg = 0;
422d52ebf10SThomas Chou 
423d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
424d52ebf10SThomas Chou 
425d52ebf10SThomas Chou 		if (err)
426d52ebf10SThomas Chou 			return err;
427a626c8d4SAndrew Gabbasov 
428a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
429d52ebf10SThomas Chou 	}
430d52ebf10SThomas Chou 
431272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
432272cc70bSAndy Fleming 
433272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
434def816a2SStephen Warren 	mmc->rca = 1;
435272cc70bSAndy Fleming 
436272cc70bSAndy Fleming 	return 0;
437272cc70bSAndy Fleming }
438272cc70bSAndy Fleming 
439272cc70bSAndy Fleming 
440fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
441272cc70bSAndy Fleming {
442272cc70bSAndy Fleming 	struct mmc_cmd cmd;
443272cc70bSAndy Fleming 	struct mmc_data data;
444272cc70bSAndy Fleming 	int err;
445272cc70bSAndy Fleming 
446272cc70bSAndy Fleming 	/* Get the Card Status Register */
447272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
448272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
449272cc70bSAndy Fleming 	cmd.cmdarg = 0;
450272cc70bSAndy Fleming 
451cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
452272cc70bSAndy Fleming 	data.blocks = 1;
4538bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
454272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
455272cc70bSAndy Fleming 
456272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
457272cc70bSAndy Fleming 
458272cc70bSAndy Fleming 	return err;
459272cc70bSAndy Fleming }
460272cc70bSAndy Fleming 
461272cc70bSAndy Fleming 
462fdbb873eSKim Phillips static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
463272cc70bSAndy Fleming {
464272cc70bSAndy Fleming 	struct mmc_cmd cmd;
4655d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
4665d4fc8d9SRaffaele Recalcati 	int ret;
467272cc70bSAndy Fleming 
468272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
469272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
470272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
471272cc70bSAndy Fleming 				 (index << 16) |
472272cc70bSAndy Fleming 				 (value << 8);
473272cc70bSAndy Fleming 
4745d4fc8d9SRaffaele Recalcati 	ret = mmc_send_cmd(mmc, &cmd, NULL);
4755d4fc8d9SRaffaele Recalcati 
4765d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
47793ad0d18SJan Kloetzke 	if (!ret)
47893ad0d18SJan Kloetzke 		ret = mmc_send_status(mmc, timeout);
4795d4fc8d9SRaffaele Recalcati 
4805d4fc8d9SRaffaele Recalcati 	return ret;
4815d4fc8d9SRaffaele Recalcati 
482272cc70bSAndy Fleming }
483272cc70bSAndy Fleming 
484fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
485272cc70bSAndy Fleming {
4868bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
487272cc70bSAndy Fleming 	char cardtype;
488272cc70bSAndy Fleming 	int err;
489272cc70bSAndy Fleming 
490fc5b32fbSAndrew Gabbasov 	mmc->card_caps = 0;
491272cc70bSAndy Fleming 
492d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
493d52ebf10SThomas Chou 		return 0;
494d52ebf10SThomas Chou 
495272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
496272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
497272cc70bSAndy Fleming 		return 0;
498272cc70bSAndy Fleming 
499fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
500fc5b32fbSAndrew Gabbasov 
501272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
502272cc70bSAndy Fleming 
503272cc70bSAndy Fleming 	if (err)
504272cc70bSAndy Fleming 		return err;
505272cc70bSAndy Fleming 
5060560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
507272cc70bSAndy Fleming 
508272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
509272cc70bSAndy Fleming 
510272cc70bSAndy Fleming 	if (err)
5116b2221b0SAndrew Gabbasov 		return err == SWITCH_ERR ? 0 : err;
512272cc70bSAndy Fleming 
513272cc70bSAndy Fleming 	/* Now check to see that it worked */
514272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
515272cc70bSAndy Fleming 
516272cc70bSAndy Fleming 	if (err)
517272cc70bSAndy Fleming 		return err;
518272cc70bSAndy Fleming 
519272cc70bSAndy Fleming 	/* No high-speed support */
5200560db18SLei Wen 	if (!ext_csd[EXT_CSD_HS_TIMING])
521272cc70bSAndy Fleming 		return 0;
522272cc70bSAndy Fleming 
523272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
524d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
525201d5ac4SAndrew Gabbasov 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
526d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
527272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
528d22e3d46SJaehoon Chung 	} else {
529272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
530d22e3d46SJaehoon Chung 	}
531272cc70bSAndy Fleming 
532272cc70bSAndy Fleming 	return 0;
533272cc70bSAndy Fleming }
534272cc70bSAndy Fleming 
535f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
536f866a46dSStephen Warren {
537f866a46dSStephen Warren 	switch (part_num) {
538f866a46dSStephen Warren 	case 0:
539f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
540f866a46dSStephen Warren 		break;
541f866a46dSStephen Warren 	case 1:
542f866a46dSStephen Warren 	case 2:
543f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
544f866a46dSStephen Warren 		break;
545f866a46dSStephen Warren 	case 3:
546f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
547f866a46dSStephen Warren 		break;
548f866a46dSStephen Warren 	case 4:
549f866a46dSStephen Warren 	case 5:
550f866a46dSStephen Warren 	case 6:
551f866a46dSStephen Warren 	case 7:
552f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
553f866a46dSStephen Warren 		break;
554f866a46dSStephen Warren 	default:
555f866a46dSStephen Warren 		return -1;
556f866a46dSStephen Warren 	}
557f866a46dSStephen Warren 
558*c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
559f866a46dSStephen Warren 
560f866a46dSStephen Warren 	return 0;
561f866a46dSStephen Warren }
562f866a46dSStephen Warren 
563bc897b1dSLei Wen int mmc_switch_part(int dev_num, unsigned int part_num)
564bc897b1dSLei Wen {
565bc897b1dSLei Wen 	struct mmc *mmc = find_mmc_device(dev_num);
566f866a46dSStephen Warren 	int ret;
567bc897b1dSLei Wen 
568bc897b1dSLei Wen 	if (!mmc)
569bc897b1dSLei Wen 		return -1;
570bc897b1dSLei Wen 
571f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
572bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
573bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
574f866a46dSStephen Warren 
5756dc93e70SPeter Bigot 	/*
5766dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
5776dc93e70SPeter Bigot 	 * to return to representing the raw device.
5786dc93e70SPeter Bigot 	 */
579873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
5806dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
581873cc1d7SStephen Warren 		mmc->block_dev.hwpart = part_num;
582873cc1d7SStephen Warren 	}
5836dc93e70SPeter Bigot 
5846dc93e70SPeter Bigot 	return ret;
585bc897b1dSLei Wen }
586bc897b1dSLei Wen 
587e17d1143SSimon Glass static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart)
588e17d1143SSimon Glass {
589e17d1143SSimon Glass 	struct mmc *mmc = find_mmc_device(desc->devnum);
590e17d1143SSimon Glass 	int ret;
591e17d1143SSimon Glass 
592e17d1143SSimon Glass 	if (!mmc)
593e17d1143SSimon Glass 		return -ENODEV;
594e17d1143SSimon Glass 
595e17d1143SSimon Glass 	if (mmc->block_dev.hwpart == hwpart)
596e17d1143SSimon Glass 		return 0;
597e17d1143SSimon Glass 
598e17d1143SSimon Glass 	if (mmc->part_config == MMCPART_NOAVAILABLE)
599e17d1143SSimon Glass 		return -EMEDIUMTYPE;
600e17d1143SSimon Glass 
601e17d1143SSimon Glass 	ret = mmc_switch_part(desc->devnum, hwpart);
602e17d1143SSimon Glass 	if (ret)
603e17d1143SSimon Glass 		return ret;
604e17d1143SSimon Glass 
605e17d1143SSimon Glass 	return 0;
606e17d1143SSimon Glass }
607e17d1143SSimon Glass 
608ff3882acSSimon Glass int mmc_select_hwpart(int dev_num, int hwpart)
609ff3882acSSimon Glass {
610ff3882acSSimon Glass 	struct mmc *mmc = find_mmc_device(dev_num);
611ff3882acSSimon Glass 	int ret;
612ff3882acSSimon Glass 
613ff3882acSSimon Glass 	if (!mmc)
614ff3882acSSimon Glass 		return -ENODEV;
615ff3882acSSimon Glass 
616ff3882acSSimon Glass 	if (mmc->block_dev.hwpart == hwpart)
617ff3882acSSimon Glass 		return 0;
618ff3882acSSimon Glass 
619ff3882acSSimon Glass 	if (mmc->part_config == MMCPART_NOAVAILABLE)
620ff3882acSSimon Glass 		return -EMEDIUMTYPE;
621ff3882acSSimon Glass 
622ff3882acSSimon Glass 	ret = mmc_switch_part(dev_num, hwpart);
623ff3882acSSimon Glass 	if (ret)
624ff3882acSSimon Glass 		return ret;
625ff3882acSSimon Glass 
626ff3882acSSimon Glass 	return 0;
627ff3882acSSimon Glass }
628ff3882acSSimon Glass 
629ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
630ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
631ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
632ac9da0e0SDiego Santa Cruz {
633ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
634ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
635ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
636ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
637ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
638ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
6398dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
640ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
641ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
642ac9da0e0SDiego Santa Cruz 
643ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
644ac9da0e0SDiego Santa Cruz 		return -EINVAL;
645ac9da0e0SDiego Santa Cruz 
646ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
647ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
648ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
649ac9da0e0SDiego Santa Cruz 	}
650ac9da0e0SDiego Santa Cruz 
651ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
652ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
653ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
654ac9da0e0SDiego Santa Cruz 	}
655ac9da0e0SDiego Santa Cruz 
656ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
657ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
658ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
659ac9da0e0SDiego Santa Cruz 	}
660ac9da0e0SDiego Santa Cruz 
661ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
662ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
663ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
664ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
665ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
666ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
667ac9da0e0SDiego Santa Cruz 			return -EINVAL;
668ac9da0e0SDiego Santa Cruz 		}
669ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
670ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
671ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
672ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
673ac9da0e0SDiego Santa Cruz 		} else {
674ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
675ac9da0e0SDiego Santa Cruz 		}
676ac9da0e0SDiego Santa Cruz 	} else {
677ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
678ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
679ac9da0e0SDiego Santa Cruz 	}
680ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
681ac9da0e0SDiego Santa Cruz 
682ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
683ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
684ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
685ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
686ac9da0e0SDiego Santa Cruz 			return -EINVAL;
687ac9da0e0SDiego Santa Cruz 		}
688ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
689ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
690ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
691ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
692ac9da0e0SDiego Santa Cruz 		}
693ac9da0e0SDiego Santa Cruz 	}
694ac9da0e0SDiego Santa Cruz 
695ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
696ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
697ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
698ac9da0e0SDiego Santa Cruz 	}
699ac9da0e0SDiego Santa Cruz 
700ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
701ac9da0e0SDiego Santa Cruz 	if (err)
702ac9da0e0SDiego Santa Cruz 		return err;
703ac9da0e0SDiego Santa Cruz 
704ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
705ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
706ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
707ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
708ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
709ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
710ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
711ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
712ac9da0e0SDiego Santa Cruz 	}
713ac9da0e0SDiego Santa Cruz 
7148dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
7158dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
7168dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
7178dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
7188dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
7198dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
7208dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
7218dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
7228dda5b0eSDiego Santa Cruz 		else
7238dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
7248dda5b0eSDiego Santa Cruz 	}
7258dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
7268dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
7278dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
7288dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
7298dda5b0eSDiego Santa Cruz 			else
7308dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
7318dda5b0eSDiego Santa Cruz 		}
7328dda5b0eSDiego Santa Cruz 	}
7338dda5b0eSDiego Santa Cruz 
7348dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
7358dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
7368dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
7378dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
7388dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
7398dda5b0eSDiego Santa Cruz 	}
7408dda5b0eSDiego Santa Cruz 
741ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
742ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
743ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
744ac9da0e0SDiego Santa Cruz 		return -EPERM;
745ac9da0e0SDiego Santa Cruz 	}
746ac9da0e0SDiego Santa Cruz 
747ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
748ac9da0e0SDiego Santa Cruz 		return 0;
749ac9da0e0SDiego Santa Cruz 
750ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
751ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
752ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
753ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
754ac9da0e0SDiego Santa Cruz 
755ac9da0e0SDiego Santa Cruz 		if (err)
756ac9da0e0SDiego Santa Cruz 			return err;
757ac9da0e0SDiego Santa Cruz 
758ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
759ac9da0e0SDiego Santa Cruz 
760ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
761ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
762ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
763ac9da0e0SDiego Santa Cruz 
764ac9da0e0SDiego Santa Cruz 	}
765ac9da0e0SDiego Santa Cruz 
766ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
767ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
768ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
769ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
770ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
771ac9da0e0SDiego Santa Cruz 		if (err)
772ac9da0e0SDiego Santa Cruz 			return err;
773ac9da0e0SDiego Santa Cruz 	}
774ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
775ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
776ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
777ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
778ac9da0e0SDiego Santa Cruz 		if (err)
779ac9da0e0SDiego Santa Cruz 			return err;
780ac9da0e0SDiego Santa Cruz 	}
781ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
782ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
783ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
784ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
785ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
786ac9da0e0SDiego Santa Cruz 			if (err)
787ac9da0e0SDiego Santa Cruz 				return err;
788ac9da0e0SDiego Santa Cruz 		}
789ac9da0e0SDiego Santa Cruz 	}
790ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
791ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
792ac9da0e0SDiego Santa Cruz 	if (err)
793ac9da0e0SDiego Santa Cruz 		return err;
794ac9da0e0SDiego Santa Cruz 
795ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
796ac9da0e0SDiego Santa Cruz 		return 0;
797ac9da0e0SDiego Santa Cruz 
7988dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
7998dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
8008dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
8018dda5b0eSDiego Santa Cruz 	 * partitioning. */
8028dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
8038dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
8048dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
8058dda5b0eSDiego Santa Cruz 		if (err)
8068dda5b0eSDiego Santa Cruz 			return err;
8078dda5b0eSDiego Santa Cruz 	}
8088dda5b0eSDiego Santa Cruz 
809ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
810ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
811ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
812ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
813ac9da0e0SDiego Santa Cruz 
814ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
815ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
816ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
817ac9da0e0SDiego Santa Cruz 	if (err)
818ac9da0e0SDiego Santa Cruz 		return err;
819ac9da0e0SDiego Santa Cruz 
820ac9da0e0SDiego Santa Cruz 	return 0;
821ac9da0e0SDiego Santa Cruz }
822ac9da0e0SDiego Santa Cruz 
82348972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
82448972d90SThierry Reding {
82548972d90SThierry Reding 	int cd;
82648972d90SThierry Reding 
82748972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
82848972d90SThierry Reding 
829d4e1da4eSPeter Korsgaard 	if (cd < 0) {
83093bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
83193bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
832d4e1da4eSPeter Korsgaard 		else
833d4e1da4eSPeter Korsgaard 			cd = 1;
834d4e1da4eSPeter Korsgaard 	}
83548972d90SThierry Reding 
83648972d90SThierry Reding 	return cd;
83748972d90SThierry Reding }
83848972d90SThierry Reding 
839fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
840272cc70bSAndy Fleming {
841272cc70bSAndy Fleming 	struct mmc_cmd cmd;
842272cc70bSAndy Fleming 	struct mmc_data data;
843272cc70bSAndy Fleming 
844272cc70bSAndy Fleming 	/* Switch the frequency */
845272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
846272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
847272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
848272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
849272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
850272cc70bSAndy Fleming 
851272cc70bSAndy Fleming 	data.dest = (char *)resp;
852272cc70bSAndy Fleming 	data.blocksize = 64;
853272cc70bSAndy Fleming 	data.blocks = 1;
854272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
855272cc70bSAndy Fleming 
856272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
857272cc70bSAndy Fleming }
858272cc70bSAndy Fleming 
859272cc70bSAndy Fleming 
860fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
861272cc70bSAndy Fleming {
862272cc70bSAndy Fleming 	int err;
863272cc70bSAndy Fleming 	struct mmc_cmd cmd;
864f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
865f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
866272cc70bSAndy Fleming 	struct mmc_data data;
867272cc70bSAndy Fleming 	int timeout;
868272cc70bSAndy Fleming 
869272cc70bSAndy Fleming 	mmc->card_caps = 0;
870272cc70bSAndy Fleming 
871d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
872d52ebf10SThomas Chou 		return 0;
873d52ebf10SThomas Chou 
874272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
875272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
876272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
877272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
878272cc70bSAndy Fleming 
879272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
880272cc70bSAndy Fleming 
881272cc70bSAndy Fleming 	if (err)
882272cc70bSAndy Fleming 		return err;
883272cc70bSAndy Fleming 
884272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
885272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
886272cc70bSAndy Fleming 	cmd.cmdarg = 0;
887272cc70bSAndy Fleming 
888272cc70bSAndy Fleming 	timeout = 3;
889272cc70bSAndy Fleming 
890272cc70bSAndy Fleming retry_scr:
891f781dd38SAnton staaf 	data.dest = (char *)scr;
892272cc70bSAndy Fleming 	data.blocksize = 8;
893272cc70bSAndy Fleming 	data.blocks = 1;
894272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
895272cc70bSAndy Fleming 
896272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
897272cc70bSAndy Fleming 
898272cc70bSAndy Fleming 	if (err) {
899272cc70bSAndy Fleming 		if (timeout--)
900272cc70bSAndy Fleming 			goto retry_scr;
901272cc70bSAndy Fleming 
902272cc70bSAndy Fleming 		return err;
903272cc70bSAndy Fleming 	}
904272cc70bSAndy Fleming 
9054e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
9064e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
907272cc70bSAndy Fleming 
908272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
909272cc70bSAndy Fleming 	case 0:
910272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
911272cc70bSAndy Fleming 		break;
912272cc70bSAndy Fleming 	case 1:
913272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
914272cc70bSAndy Fleming 		break;
915272cc70bSAndy Fleming 	case 2:
916272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
9171741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
9181741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
919272cc70bSAndy Fleming 		break;
920272cc70bSAndy Fleming 	default:
921272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
922272cc70bSAndy Fleming 		break;
923272cc70bSAndy Fleming 	}
924272cc70bSAndy Fleming 
925b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
926b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
927b44c7083SAlagu Sankar 
928272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
929272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
930272cc70bSAndy Fleming 		return 0;
931272cc70bSAndy Fleming 
932272cc70bSAndy Fleming 	timeout = 4;
933272cc70bSAndy Fleming 	while (timeout--) {
934272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
935f781dd38SAnton staaf 				(u8 *)switch_status);
936272cc70bSAndy Fleming 
937272cc70bSAndy Fleming 		if (err)
938272cc70bSAndy Fleming 			return err;
939272cc70bSAndy Fleming 
940272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
9414e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
942272cc70bSAndy Fleming 			break;
943272cc70bSAndy Fleming 	}
944272cc70bSAndy Fleming 
945272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
9464e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
947272cc70bSAndy Fleming 		return 0;
948272cc70bSAndy Fleming 
9492c3fbf4cSMacpaul Lin 	/*
9502c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
9512c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
9522c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
9532c3fbf4cSMacpaul Lin 	 * mode between the host.
9542c3fbf4cSMacpaul Lin 	 */
95593bfd616SPantelis Antoniou 	if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
95693bfd616SPantelis Antoniou 		(mmc->cfg->host_caps & MMC_MODE_HS)))
9572c3fbf4cSMacpaul Lin 		return 0;
9582c3fbf4cSMacpaul Lin 
959f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
960272cc70bSAndy Fleming 
961272cc70bSAndy Fleming 	if (err)
962272cc70bSAndy Fleming 		return err;
963272cc70bSAndy Fleming 
9644e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
965272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
966272cc70bSAndy Fleming 
967272cc70bSAndy Fleming 	return 0;
968272cc70bSAndy Fleming }
969272cc70bSAndy Fleming 
970272cc70bSAndy Fleming /* frequency bases */
971272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
9725f837c2cSMike Frysinger static const int fbase[] = {
973272cc70bSAndy Fleming 	10000,
974272cc70bSAndy Fleming 	100000,
975272cc70bSAndy Fleming 	1000000,
976272cc70bSAndy Fleming 	10000000,
977272cc70bSAndy Fleming };
978272cc70bSAndy Fleming 
979272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
980272cc70bSAndy Fleming  * to platforms without floating point.
981272cc70bSAndy Fleming  */
9825f837c2cSMike Frysinger static const int multipliers[] = {
983272cc70bSAndy Fleming 	0,	/* reserved */
984272cc70bSAndy Fleming 	10,
985272cc70bSAndy Fleming 	12,
986272cc70bSAndy Fleming 	13,
987272cc70bSAndy Fleming 	15,
988272cc70bSAndy Fleming 	20,
989272cc70bSAndy Fleming 	25,
990272cc70bSAndy Fleming 	30,
991272cc70bSAndy Fleming 	35,
992272cc70bSAndy Fleming 	40,
993272cc70bSAndy Fleming 	45,
994272cc70bSAndy Fleming 	50,
995272cc70bSAndy Fleming 	55,
996272cc70bSAndy Fleming 	60,
997272cc70bSAndy Fleming 	70,
998272cc70bSAndy Fleming 	80,
999272cc70bSAndy Fleming };
1000272cc70bSAndy Fleming 
1001fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
1002272cc70bSAndy Fleming {
100393bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
100493bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
1005272cc70bSAndy Fleming }
1006272cc70bSAndy Fleming 
1007272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
1008272cc70bSAndy Fleming {
100993bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
101093bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1011272cc70bSAndy Fleming 
101293bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
101393bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1014272cc70bSAndy Fleming 
1015272cc70bSAndy Fleming 	mmc->clock = clock;
1016272cc70bSAndy Fleming 
1017272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1018272cc70bSAndy Fleming }
1019272cc70bSAndy Fleming 
1020fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width)
1021272cc70bSAndy Fleming {
1022272cc70bSAndy Fleming 	mmc->bus_width = width;
1023272cc70bSAndy Fleming 
1024272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1025272cc70bSAndy Fleming }
1026272cc70bSAndy Fleming 
1027fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1028272cc70bSAndy Fleming {
1029f866a46dSStephen Warren 	int err, i;
1030272cc70bSAndy Fleming 	uint mult, freq;
1031639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
1032272cc70bSAndy Fleming 	struct mmc_cmd cmd;
10338bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
10348bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
10355d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
10360c453bb7SDiego Santa Cruz 	bool has_parts = false;
10378a0cf490SDiego Santa Cruz 	bool part_completed;
1038*c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1039272cc70bSAndy Fleming 
1040d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1041d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1042d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1043d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1044d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1045d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1046d52ebf10SThomas Chou 
1047d52ebf10SThomas Chou 		if (err)
1048d52ebf10SThomas Chou 			return err;
1049d52ebf10SThomas Chou 	}
1050d52ebf10SThomas Chou #endif
1051d52ebf10SThomas Chou 
1052272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1053d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1054d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1055272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1056272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1057272cc70bSAndy Fleming 
1058272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1059272cc70bSAndy Fleming 
1060272cc70bSAndy Fleming 	if (err)
1061272cc70bSAndy Fleming 		return err;
1062272cc70bSAndy Fleming 
1063272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1064272cc70bSAndy Fleming 
1065272cc70bSAndy Fleming 	/*
1066272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1067272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1068272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1069272cc70bSAndy Fleming 	 */
1070d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1071272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1072272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1073272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1074272cc70bSAndy Fleming 
1075272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1076272cc70bSAndy Fleming 
1077272cc70bSAndy Fleming 		if (err)
1078272cc70bSAndy Fleming 			return err;
1079272cc70bSAndy Fleming 
1080272cc70bSAndy Fleming 		if (IS_SD(mmc))
1081998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1082d52ebf10SThomas Chou 	}
1083272cc70bSAndy Fleming 
1084272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1085272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1086272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1087272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1088272cc70bSAndy Fleming 
1089272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1090272cc70bSAndy Fleming 
10915d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
10925d4fc8d9SRaffaele Recalcati 	mmc_send_status(mmc, timeout);
10935d4fc8d9SRaffaele Recalcati 
1094272cc70bSAndy Fleming 	if (err)
1095272cc70bSAndy Fleming 		return err;
1096272cc70bSAndy Fleming 
1097998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1098998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1099998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1100998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1101272cc70bSAndy Fleming 
1102272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
11030b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1104272cc70bSAndy Fleming 
1105272cc70bSAndy Fleming 		switch (version) {
1106272cc70bSAndy Fleming 		case 0:
1107272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1108272cc70bSAndy Fleming 			break;
1109272cc70bSAndy Fleming 		case 1:
1110272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1111272cc70bSAndy Fleming 			break;
1112272cc70bSAndy Fleming 		case 2:
1113272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1114272cc70bSAndy Fleming 			break;
1115272cc70bSAndy Fleming 		case 3:
1116272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1117272cc70bSAndy Fleming 			break;
1118272cc70bSAndy Fleming 		case 4:
1119272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1120272cc70bSAndy Fleming 			break;
1121272cc70bSAndy Fleming 		default:
1122272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1123272cc70bSAndy Fleming 			break;
1124272cc70bSAndy Fleming 		}
1125272cc70bSAndy Fleming 	}
1126272cc70bSAndy Fleming 
1127272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
11280b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
11290b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1130272cc70bSAndy Fleming 
1131272cc70bSAndy Fleming 	mmc->tran_speed = freq * mult;
1132272cc70bSAndy Fleming 
1133ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1134998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1135272cc70bSAndy Fleming 
1136272cc70bSAndy Fleming 	if (IS_SD(mmc))
1137272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1138272cc70bSAndy Fleming 	else
1139998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1140272cc70bSAndy Fleming 
1141272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1142272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1143272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1144272cc70bSAndy Fleming 		cmult = 8;
1145272cc70bSAndy Fleming 	} else {
1146272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1147272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1148272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1149272cc70bSAndy Fleming 	}
1150272cc70bSAndy Fleming 
1151f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1152f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1153f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1154f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1155f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1156f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1157272cc70bSAndy Fleming 
11588bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
11598bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1160272cc70bSAndy Fleming 
11618bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
11628bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1163272cc70bSAndy Fleming 
1164ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1165ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1166ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1167ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1168ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1169ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1170ab71188cSMarkus Niebel 	}
1171ab71188cSMarkus Niebel 
1172272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1173d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1174272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1175fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1176272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1177272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1178272cc70bSAndy Fleming 
1179272cc70bSAndy Fleming 		if (err)
1180272cc70bSAndy Fleming 			return err;
1181d52ebf10SThomas Chou 	}
1182272cc70bSAndy Fleming 
1183e6f99a56SLei Wen 	/*
1184e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1185e6f99a56SLei Wen 	 */
1186e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1187bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1188d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
1189d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
1190d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
11919cf199ebSDiego Santa Cruz 		if (err)
11929cf199ebSDiego Santa Cruz 			return err;
11939cf199ebSDiego Santa Cruz 		if (ext_csd[EXT_CSD_REV] >= 2) {
1194639b7827SYoshihiro Shimoda 			/*
1195639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
1196639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
1197639b7827SYoshihiro Shimoda 			 * than 2GB
1198639b7827SYoshihiro Shimoda 			 */
11990560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
12000560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
12010560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
12020560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
12038bfa195eSSimon Glass 			capacity *= MMC_MAX_BLOCK_LEN;
1204b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
1205f866a46dSStephen Warren 				mmc->capacity_user = capacity;
1206d23e2c09SSukumar Ghorai 		}
1207bc897b1dSLei Wen 
120864f4a619SJaehoon Chung 		switch (ext_csd[EXT_CSD_REV]) {
120964f4a619SJaehoon Chung 		case 1:
121064f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_1;
121164f4a619SJaehoon Chung 			break;
121264f4a619SJaehoon Chung 		case 2:
121364f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_2;
121464f4a619SJaehoon Chung 			break;
121564f4a619SJaehoon Chung 		case 3:
121664f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_3;
121764f4a619SJaehoon Chung 			break;
121864f4a619SJaehoon Chung 		case 5:
121964f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_41;
122064f4a619SJaehoon Chung 			break;
122164f4a619SJaehoon Chung 		case 6:
122264f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_5;
122364f4a619SJaehoon Chung 			break;
1224edab723bSMarkus Niebel 		case 7:
1225edab723bSMarkus Niebel 			mmc->version = MMC_VERSION_5_0;
1226edab723bSMarkus Niebel 			break;
122764f4a619SJaehoon Chung 		}
122864f4a619SJaehoon Chung 
12298a0cf490SDiego Santa Cruz 		/* The partition data may be non-zero but it is only
12308a0cf490SDiego Santa Cruz 		 * effective if PARTITION_SETTING_COMPLETED is set in
12318a0cf490SDiego Santa Cruz 		 * EXT_CSD, so ignore any data if this bit is not set,
12328a0cf490SDiego Santa Cruz 		 * except for enabling the high-capacity group size
12338a0cf490SDiego Santa Cruz 		 * definition (see below). */
12348a0cf490SDiego Santa Cruz 		part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
12358a0cf490SDiego Santa Cruz 				    EXT_CSD_PARTITION_SETTING_COMPLETED);
12368a0cf490SDiego Santa Cruz 
12370c453bb7SDiego Santa Cruz 		/* store the partition info of emmc */
12380c453bb7SDiego Santa Cruz 		mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
12390c453bb7SDiego Santa Cruz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
12400c453bb7SDiego Santa Cruz 		    ext_csd[EXT_CSD_BOOT_MULT])
12410c453bb7SDiego Santa Cruz 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
12428a0cf490SDiego Santa Cruz 		if (part_completed &&
12438a0cf490SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
12440c453bb7SDiego Santa Cruz 			mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
12450c453bb7SDiego Santa Cruz 
12460c453bb7SDiego Santa Cruz 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
12470c453bb7SDiego Santa Cruz 
12480c453bb7SDiego Santa Cruz 		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
12490c453bb7SDiego Santa Cruz 
12500c453bb7SDiego Santa Cruz 		for (i = 0; i < 4; i++) {
12510c453bb7SDiego Santa Cruz 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
12528a0cf490SDiego Santa Cruz 			uint mult = (ext_csd[idx + 2] << 16) +
12530c453bb7SDiego Santa Cruz 				(ext_csd[idx + 1] << 8) + ext_csd[idx];
12548a0cf490SDiego Santa Cruz 			if (mult)
12558a0cf490SDiego Santa Cruz 				has_parts = true;
12568a0cf490SDiego Santa Cruz 			if (!part_completed)
12578a0cf490SDiego Santa Cruz 				continue;
12588a0cf490SDiego Santa Cruz 			mmc->capacity_gp[i] = mult;
12590c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *=
12600c453bb7SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
12610c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1262f8e89d67SDiego Santa Cruz 			mmc->capacity_gp[i] <<= 19;
12630c453bb7SDiego Santa Cruz 		}
12640c453bb7SDiego Santa Cruz 
12658a0cf490SDiego Santa Cruz 		if (part_completed) {
1266a7f852b6SDiego Santa Cruz 			mmc->enh_user_size =
1267a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
1268a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
1269a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_SIZE_MULT];
1270a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1271a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1272a7f852b6SDiego Santa Cruz 			mmc->enh_user_size <<= 19;
1273a7f852b6SDiego Santa Cruz 			mmc->enh_user_start =
1274a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
1275a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
1276a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
1277a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_START_ADDR];
1278a7f852b6SDiego Santa Cruz 			if (mmc->high_capacity)
1279a7f852b6SDiego Santa Cruz 				mmc->enh_user_start <<= 9;
12808a0cf490SDiego Santa Cruz 		}
1281a7f852b6SDiego Santa Cruz 
1282e6f99a56SLei Wen 		/*
12831937e5aaSOliver Metz 		 * Host needs to enable ERASE_GRP_DEF bit if device is
12841937e5aaSOliver Metz 		 * partitioned. This bit will be lost every time after a reset
12851937e5aaSOliver Metz 		 * or power off. This will affect erase size.
1286e6f99a56SLei Wen 		 */
12878a0cf490SDiego Santa Cruz 		if (part_completed)
12880c453bb7SDiego Santa Cruz 			has_parts = true;
12891937e5aaSOliver Metz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
12900c453bb7SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
12910c453bb7SDiego Santa Cruz 			has_parts = true;
12920c453bb7SDiego Santa Cruz 		if (has_parts) {
12931937e5aaSOliver Metz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
12941937e5aaSOliver Metz 				EXT_CSD_ERASE_GROUP_DEF, 1);
12951937e5aaSOliver Metz 
12961937e5aaSOliver Metz 			if (err)
12971937e5aaSOliver Metz 				return err;
1298021a8055SHannes Petermaier 			else
1299021a8055SHannes Petermaier 				ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1300037dc0abSDiego Santa Cruz 		}
13011937e5aaSOliver Metz 
1302037dc0abSDiego Santa Cruz 		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
13031937e5aaSOliver Metz 			/* Read out group size from ext_csd */
13040560db18SLei Wen 			mmc->erase_grp_size =
1305a4ff9f83SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1306d7b29129SMarkus Niebel 			/*
1307d7b29129SMarkus Niebel 			 * if high capacity and partition setting completed
1308d7b29129SMarkus Niebel 			 * SEC_COUNT is valid even if it is smaller than 2 GiB
1309d7b29129SMarkus Niebel 			 * JEDEC Standard JESD84-B45, 6.2.4
1310d7b29129SMarkus Niebel 			 */
13118a0cf490SDiego Santa Cruz 			if (mmc->high_capacity && part_completed) {
1312d7b29129SMarkus Niebel 				capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1313d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1314d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1315d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1316d7b29129SMarkus Niebel 				capacity *= MMC_MAX_BLOCK_LEN;
1317d7b29129SMarkus Niebel 				mmc->capacity_user = capacity;
1318d7b29129SMarkus Niebel 			}
13198bfa195eSSimon Glass 		} else {
13201937e5aaSOliver Metz 			/* Calculate the group size from the csd value. */
1321e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
1322e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1323e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1324e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
1325e6f99a56SLei Wen 				* (erase_gmul + 1);
1326e6f99a56SLei Wen 		}
1327037dc0abSDiego Santa Cruz 
1328037dc0abSDiego Santa Cruz 		mmc->hc_wp_grp_size = 1024
1329037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1330037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
13319e41a00bSDiego Santa Cruz 
13329e41a00bSDiego Santa Cruz 		mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1333f866a46dSStephen Warren 	}
1334f866a46dSStephen Warren 
1335*c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
1336f866a46dSStephen Warren 	if (err)
1337f866a46dSStephen Warren 		return err;
1338d23e2c09SSukumar Ghorai 
1339272cc70bSAndy Fleming 	if (IS_SD(mmc))
1340272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1341272cc70bSAndy Fleming 	else
1342272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1343272cc70bSAndy Fleming 
1344272cc70bSAndy Fleming 	if (err)
1345272cc70bSAndy Fleming 		return err;
1346272cc70bSAndy Fleming 
1347272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
134893bfd616SPantelis Antoniou 	mmc->card_caps &= mmc->cfg->host_caps;
1349272cc70bSAndy Fleming 
1350272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1351272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1352272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1353272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1354272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1355272cc70bSAndy Fleming 
1356272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1357272cc70bSAndy Fleming 			if (err)
1358272cc70bSAndy Fleming 				return err;
1359272cc70bSAndy Fleming 
1360272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1361272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1362272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1363272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1364272cc70bSAndy Fleming 			if (err)
1365272cc70bSAndy Fleming 				return err;
1366272cc70bSAndy Fleming 
1367272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1368272cc70bSAndy Fleming 		}
1369272cc70bSAndy Fleming 
1370272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
1371ad5fd922SJaehoon Chung 			mmc->tran_speed = 50000000;
1372272cc70bSAndy Fleming 		else
1373ad5fd922SJaehoon Chung 			mmc->tran_speed = 25000000;
1374fc5b32fbSAndrew Gabbasov 	} else if (mmc->version >= MMC_VERSION_4) {
1375fc5b32fbSAndrew Gabbasov 		/* Only version 4 of MMC supports wider bus widths */
13767798f6dbSAndy Fleming 		int idx;
13777798f6dbSAndy Fleming 
13787798f6dbSAndy Fleming 		/* An array of possible bus widths in order of preference */
13797798f6dbSAndy Fleming 		static unsigned ext_csd_bits[] = {
1380d22e3d46SJaehoon Chung 			EXT_CSD_DDR_BUS_WIDTH_8,
1381d22e3d46SJaehoon Chung 			EXT_CSD_DDR_BUS_WIDTH_4,
13827798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_8,
13837798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_4,
13847798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_1,
13857798f6dbSAndy Fleming 		};
13867798f6dbSAndy Fleming 
13877798f6dbSAndy Fleming 		/* An array to map CSD bus widths to host cap bits */
13887798f6dbSAndy Fleming 		static unsigned ext_to_hostcaps[] = {
1389786e8f81SAndrew Gabbasov 			[EXT_CSD_DDR_BUS_WIDTH_4] =
1390786e8f81SAndrew Gabbasov 				MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
1391786e8f81SAndrew Gabbasov 			[EXT_CSD_DDR_BUS_WIDTH_8] =
1392786e8f81SAndrew Gabbasov 				MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
13937798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
13947798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
13957798f6dbSAndy Fleming 		};
13967798f6dbSAndy Fleming 
13977798f6dbSAndy Fleming 		/* An array to map chosen bus width to an integer */
13987798f6dbSAndy Fleming 		static unsigned widths[] = {
1399d22e3d46SJaehoon Chung 			8, 4, 8, 4, 1,
14007798f6dbSAndy Fleming 		};
14017798f6dbSAndy Fleming 
14027798f6dbSAndy Fleming 		for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
14037798f6dbSAndy Fleming 			unsigned int extw = ext_csd_bits[idx];
1404786e8f81SAndrew Gabbasov 			unsigned int caps = ext_to_hostcaps[extw];
14057798f6dbSAndy Fleming 
14067798f6dbSAndy Fleming 			/*
1407bf477073SAndrew Gabbasov 			 * If the bus width is still not changed,
1408bf477073SAndrew Gabbasov 			 * don't try to set the default again.
1409bf477073SAndrew Gabbasov 			 * Otherwise, recover from switch attempts
1410bf477073SAndrew Gabbasov 			 * by switching to 1-bit bus width.
1411bf477073SAndrew Gabbasov 			 */
1412bf477073SAndrew Gabbasov 			if (extw == EXT_CSD_BUS_WIDTH_1 &&
1413bf477073SAndrew Gabbasov 					mmc->bus_width == 1) {
1414bf477073SAndrew Gabbasov 				err = 0;
1415bf477073SAndrew Gabbasov 				break;
1416bf477073SAndrew Gabbasov 			}
1417bf477073SAndrew Gabbasov 
1418bf477073SAndrew Gabbasov 			/*
1419786e8f81SAndrew Gabbasov 			 * Check to make sure the card and controller support
1420786e8f81SAndrew Gabbasov 			 * these capabilities
14217798f6dbSAndy Fleming 			 */
1422786e8f81SAndrew Gabbasov 			if ((mmc->card_caps & caps) != caps)
14237798f6dbSAndy Fleming 				continue;
14247798f6dbSAndy Fleming 
1425272cc70bSAndy Fleming 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
14267798f6dbSAndy Fleming 					EXT_CSD_BUS_WIDTH, extw);
1427272cc70bSAndy Fleming 
1428272cc70bSAndy Fleming 			if (err)
14294137894eSLei Wen 				continue;
1430272cc70bSAndy Fleming 
1431786e8f81SAndrew Gabbasov 			mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
14327798f6dbSAndy Fleming 			mmc_set_bus_width(mmc, widths[idx]);
1433272cc70bSAndy Fleming 
14344137894eSLei Wen 			err = mmc_send_ext_csd(mmc, test_csd);
1435272cc70bSAndy Fleming 
1436786e8f81SAndrew Gabbasov 			if (err)
1437786e8f81SAndrew Gabbasov 				continue;
1438786e8f81SAndrew Gabbasov 
1439786e8f81SAndrew Gabbasov 			/* Only compare read only fields */
1440786e8f81SAndrew Gabbasov 			if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
1441786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
1442786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
1443786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
1444786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_REV]
1445786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_REV] &&
1446786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1447786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
1448786e8f81SAndrew Gabbasov 			    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
1449786e8f81SAndrew Gabbasov 				   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
14504137894eSLei Wen 				break;
1451786e8f81SAndrew Gabbasov 			else
1452786e8f81SAndrew Gabbasov 				err = SWITCH_ERR;
14534137894eSLei Wen 		}
1454786e8f81SAndrew Gabbasov 
1455786e8f81SAndrew Gabbasov 		if (err)
1456786e8f81SAndrew Gabbasov 			return err;
1457272cc70bSAndy Fleming 
1458272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS) {
1459272cc70bSAndy Fleming 			if (mmc->card_caps & MMC_MODE_HS_52MHz)
1460ad5fd922SJaehoon Chung 				mmc->tran_speed = 52000000;
1461272cc70bSAndy Fleming 			else
1462ad5fd922SJaehoon Chung 				mmc->tran_speed = 26000000;
1463272cc70bSAndy Fleming 		}
1464ad5fd922SJaehoon Chung 	}
1465ad5fd922SJaehoon Chung 
1466ad5fd922SJaehoon Chung 	mmc_set_clock(mmc, mmc->tran_speed);
1467272cc70bSAndy Fleming 
14685af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
14695af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
14705af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
14715af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
14725af8f45cSAndrew Gabbasov 	}
14735af8f45cSAndrew Gabbasov 
1474272cc70bSAndy Fleming 	/* fill in device description */
1475*c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1476*c40fdca6SSimon Glass 	bdesc->lun = 0;
1477*c40fdca6SSimon Glass 	bdesc->hwpart = 0;
1478*c40fdca6SSimon Glass 	bdesc->type = 0;
1479*c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
1480*c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
1481*c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1482fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1483fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1484fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1485*c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
1486babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1487babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1488*c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
14890b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1490babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1491babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1492*c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1493babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
149456196826SPaul Burton #else
1495*c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
1496*c40fdca6SSimon Glass 	bdesc->product[0] = 0;
1497*c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
149856196826SPaul Burton #endif
1499122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1500*c40fdca6SSimon Glass 	part_init(bdesc);
1501122efd43SMikhail Kshevetskiy #endif
1502272cc70bSAndy Fleming 
1503272cc70bSAndy Fleming 	return 0;
1504272cc70bSAndy Fleming }
1505272cc70bSAndy Fleming 
1506fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1507272cc70bSAndy Fleming {
1508272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1509272cc70bSAndy Fleming 	int err;
1510272cc70bSAndy Fleming 
1511272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1512272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
151393bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1514272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1515272cc70bSAndy Fleming 
1516272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1517272cc70bSAndy Fleming 
1518272cc70bSAndy Fleming 	if (err)
1519272cc70bSAndy Fleming 		return err;
1520272cc70bSAndy Fleming 
1521998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1522272cc70bSAndy Fleming 		return UNUSABLE_ERR;
1523272cc70bSAndy Fleming 	else
1524272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1525272cc70bSAndy Fleming 
1526272cc70bSAndy Fleming 	return 0;
1527272cc70bSAndy Fleming }
1528272cc70bSAndy Fleming 
152993bfd616SPantelis Antoniou /* not used any more */
153093bfd616SPantelis Antoniou int __deprecated mmc_register(struct mmc *mmc)
1531272cc70bSAndy Fleming {
153293bfd616SPantelis Antoniou #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
153393bfd616SPantelis Antoniou 	printf("%s is deprecated! use mmc_create() instead.\n", __func__);
153493bfd616SPantelis Antoniou #endif
153593bfd616SPantelis Antoniou 	return -1;
153693bfd616SPantelis Antoniou }
153793bfd616SPantelis Antoniou 
153893bfd616SPantelis Antoniou struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
153993bfd616SPantelis Antoniou {
1540*c40fdca6SSimon Glass 	struct blk_desc *bdesc;
154193bfd616SPantelis Antoniou 	struct mmc *mmc;
154293bfd616SPantelis Antoniou 
154393bfd616SPantelis Antoniou 	/* quick validation */
154493bfd616SPantelis Antoniou 	if (cfg == NULL || cfg->ops == NULL || cfg->ops->send_cmd == NULL ||
154593bfd616SPantelis Antoniou 			cfg->f_min == 0 || cfg->f_max == 0 || cfg->b_max == 0)
154693bfd616SPantelis Antoniou 		return NULL;
154793bfd616SPantelis Antoniou 
154893bfd616SPantelis Antoniou 	mmc = calloc(1, sizeof(*mmc));
154993bfd616SPantelis Antoniou 	if (mmc == NULL)
155093bfd616SPantelis Antoniou 		return NULL;
155193bfd616SPantelis Antoniou 
155293bfd616SPantelis Antoniou 	mmc->cfg = cfg;
155393bfd616SPantelis Antoniou 	mmc->priv = priv;
155493bfd616SPantelis Antoniou 
155593bfd616SPantelis Antoniou 	/* the following chunk was mmc_register() */
155693bfd616SPantelis Antoniou 
1557ab71188cSMarkus Niebel 	/* Setup dsr related values */
1558ab71188cSMarkus Niebel 	mmc->dsr_imp = 0;
1559ab71188cSMarkus Niebel 	mmc->dsr = 0xffffffff;
1560272cc70bSAndy Fleming 	/* Setup the universal parts of the block interface just once */
1561*c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1562*c40fdca6SSimon Glass 	bdesc->if_type = IF_TYPE_MMC;
1563*c40fdca6SSimon Glass 	bdesc->removable = 1;
1564*c40fdca6SSimon Glass 	bdesc->devnum = mmc_get_next_devnum();
1565*c40fdca6SSimon Glass 	bdesc->block_read = mmc_bread;
1566*c40fdca6SSimon Glass 	bdesc->block_write = mmc_bwrite;
1567*c40fdca6SSimon Glass 	bdesc->block_erase = mmc_berase;
156893bfd616SPantelis Antoniou 
156993bfd616SPantelis Antoniou 	/* setup initial part type */
1570*c40fdca6SSimon Glass 	bdesc->part_type = mmc->cfg->part_type;
1571*c40fdca6SSimon Glass 	mmc_list_add(mmc);
1572272cc70bSAndy Fleming 
157393bfd616SPantelis Antoniou 	return mmc;
157493bfd616SPantelis Antoniou }
157593bfd616SPantelis Antoniou 
157693bfd616SPantelis Antoniou void mmc_destroy(struct mmc *mmc)
157793bfd616SPantelis Antoniou {
157893bfd616SPantelis Antoniou 	/* only freeing memory for now */
157993bfd616SPantelis Antoniou 	free(mmc);
1580272cc70bSAndy Fleming }
1581272cc70bSAndy Fleming 
15823c457f4dSSimon Glass static int mmc_get_dev(int dev, struct blk_desc **descp)
1583663acabdSSimon Glass {
1584663acabdSSimon Glass 	struct mmc *mmc = find_mmc_device(dev);
1585663acabdSSimon Glass 	int ret;
1586663acabdSSimon Glass 
1587663acabdSSimon Glass 	if (!mmc)
1588663acabdSSimon Glass 		return -ENODEV;
1589663acabdSSimon Glass 	ret = mmc_init(mmc);
1590663acabdSSimon Glass 	if (ret)
1591663acabdSSimon Glass 		return ret;
1592663acabdSSimon Glass 
1593663acabdSSimon Glass 	*descp = &mmc->block_dev;
1594663acabdSSimon Glass 
1595663acabdSSimon Glass 	return 0;
1596663acabdSSimon Glass }
1597663acabdSSimon Glass 
159895de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
159995de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
160095de9ab2SPaul Kocialkowski {
160195de9ab2SPaul Kocialkowski }
160295de9ab2SPaul Kocialkowski 
1603e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1604272cc70bSAndy Fleming {
1605afd5932bSMacpaul Lin 	int err;
1606272cc70bSAndy Fleming 
1607ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
160893bfd616SPantelis Antoniou 	if (mmc_getcd(mmc) == 0 || mmc->cfg->ops->init == NULL) {
160948972d90SThierry Reding 		mmc->has_init = 0;
161056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
161148972d90SThierry Reding 		printf("MMC: no card present\n");
161256196826SPaul Burton #endif
161348972d90SThierry Reding 		return NO_CARD_ERR;
161448972d90SThierry Reding 	}
161548972d90SThierry Reding 
1616bc897b1dSLei Wen 	if (mmc->has_init)
1617bc897b1dSLei Wen 		return 0;
1618bc897b1dSLei Wen 
16195a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
16205a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
16215a8dbdc6SYangbo Lu #endif
162295de9ab2SPaul Kocialkowski 	board_mmc_power_init();
162395de9ab2SPaul Kocialkowski 
1624ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
162593bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
1626272cc70bSAndy Fleming 
1627272cc70bSAndy Fleming 	if (err)
1628272cc70bSAndy Fleming 		return err;
1629272cc70bSAndy Fleming 
1630786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
1631b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1632b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1633b86b85e2SIlya Yanok 
1634272cc70bSAndy Fleming 	/* Reset the Card */
1635272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1636272cc70bSAndy Fleming 
1637272cc70bSAndy Fleming 	if (err)
1638272cc70bSAndy Fleming 		return err;
1639272cc70bSAndy Fleming 
1640bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1641*c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
1642bc897b1dSLei Wen 
1643272cc70bSAndy Fleming 	/* Test for SD version 2 */
1644272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1645272cc70bSAndy Fleming 
1646272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1647272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1648272cc70bSAndy Fleming 
1649272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1650272cc70bSAndy Fleming 	if (err == TIMEOUT) {
1651272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1652272cc70bSAndy Fleming 
1653bd47c135SAndrew Gabbasov 		if (err) {
165456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1655272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
165656196826SPaul Burton #endif
1657272cc70bSAndy Fleming 			return UNUSABLE_ERR;
1658272cc70bSAndy Fleming 		}
1659272cc70bSAndy Fleming 	}
1660272cc70bSAndy Fleming 
1661bd47c135SAndrew Gabbasov 	if (!err)
1662e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
1663e9550449SChe-Liang Chiou 
1664e9550449SChe-Liang Chiou 	return err;
1665e9550449SChe-Liang Chiou }
1666e9550449SChe-Liang Chiou 
1667e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
1668e9550449SChe-Liang Chiou {
1669e9550449SChe-Liang Chiou 	int err = 0;
1670e9550449SChe-Liang Chiou 
1671bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
1672e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
1673e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
1674e9550449SChe-Liang Chiou 
1675e9550449SChe-Liang Chiou 	if (!err)
1676bc897b1dSLei Wen 		err = mmc_startup(mmc);
1677bc897b1dSLei Wen 	if (err)
1678bc897b1dSLei Wen 		mmc->has_init = 0;
1679bc897b1dSLei Wen 	else
1680bc897b1dSLei Wen 		mmc->has_init = 1;
1681e9550449SChe-Liang Chiou 	return err;
1682e9550449SChe-Liang Chiou }
1683e9550449SChe-Liang Chiou 
1684e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
1685e9550449SChe-Liang Chiou {
1686bd47c135SAndrew Gabbasov 	int err = 0;
1687d803fea5SMateusz Zalega 	unsigned start;
1688e9550449SChe-Liang Chiou 
1689e9550449SChe-Liang Chiou 	if (mmc->has_init)
1690e9550449SChe-Liang Chiou 		return 0;
1691d803fea5SMateusz Zalega 
1692d803fea5SMateusz Zalega 	start = get_timer(0);
1693d803fea5SMateusz Zalega 
1694e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
1695e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
1696e9550449SChe-Liang Chiou 
1697bd47c135SAndrew Gabbasov 	if (!err)
1698e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
1699e9550449SChe-Liang Chiou 	debug("%s: %d, time %lu\n", __func__, err, get_timer(start));
1700bc897b1dSLei Wen 	return err;
1701272cc70bSAndy Fleming }
1702272cc70bSAndy Fleming 
1703ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
1704ab71188cSMarkus Niebel {
1705ab71188cSMarkus Niebel 	mmc->dsr = val;
1706ab71188cSMarkus Niebel 	return 0;
1707ab71188cSMarkus Niebel }
1708ab71188cSMarkus Niebel 
1709cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
1710cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
1711272cc70bSAndy Fleming {
1712272cc70bSAndy Fleming 	return -1;
1713272cc70bSAndy Fleming }
1714272cc70bSAndy Fleming 
1715cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
1716cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
1717cee9ab7cSJeroen Hofstee {
1718cee9ab7cSJeroen Hofstee 	return -1;
1719cee9ab7cSJeroen Hofstee }
1720272cc70bSAndy Fleming 
1721e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
1722e9550449SChe-Liang Chiou {
1723e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
1724e9550449SChe-Liang Chiou }
1725e9550449SChe-Liang Chiou 
17268e3332e2SSjoerd Simons #if defined(CONFIG_DM_MMC) && defined(CONFIG_SPL_BUILD)
17278e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
17288e3332e2SSjoerd Simons {
17298e3332e2SSjoerd Simons 	return 0;
17308e3332e2SSjoerd Simons }
17318e3332e2SSjoerd Simons #elif defined(CONFIG_DM_MMC)
17328e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
17338e3332e2SSjoerd Simons {
17344a1db6d8SSimon Glass 	int ret, i;
17358e3332e2SSjoerd Simons 	struct uclass *uc;
17364a1db6d8SSimon Glass 	struct udevice *dev;
17378e3332e2SSjoerd Simons 
17388e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
17398e3332e2SSjoerd Simons 	if (ret)
17408e3332e2SSjoerd Simons 		return ret;
17418e3332e2SSjoerd Simons 
17424a1db6d8SSimon Glass 	/*
17434a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
17444a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
17454a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
17464a1db6d8SSimon Glass 	 */
17474a1db6d8SSimon Glass 	for (i = 0; ; i++) {
17484a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
17494a1db6d8SSimon Glass 		if (ret == -ENODEV)
17504a1db6d8SSimon Glass 			break;
17514a1db6d8SSimon Glass 	}
17524a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
17534a1db6d8SSimon Glass 		ret = device_probe(dev);
17548e3332e2SSjoerd Simons 		if (ret)
17554a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
17568e3332e2SSjoerd Simons 	}
17578e3332e2SSjoerd Simons 
17588e3332e2SSjoerd Simons 	return 0;
17598e3332e2SSjoerd Simons }
17608e3332e2SSjoerd Simons #else
17618e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
17628e3332e2SSjoerd Simons {
17638e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
17648e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
17658e3332e2SSjoerd Simons 
17668e3332e2SSjoerd Simons 	return 0;
17678e3332e2SSjoerd Simons }
17688e3332e2SSjoerd Simons #endif
1769e9550449SChe-Liang Chiou 
1770272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1771272cc70bSAndy Fleming {
17721b26bab1SDaniel Kochmański 	static int initialized = 0;
17738e3332e2SSjoerd Simons 	int ret;
17741b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
17751b26bab1SDaniel Kochmański 		return 0;
17761b26bab1SDaniel Kochmański 	initialized = 1;
17771b26bab1SDaniel Kochmański 
1778*c40fdca6SSimon Glass #ifndef CONFIG_BLK
1779*c40fdca6SSimon Glass 	mmc_list_init();
1780*c40fdca6SSimon Glass #endif
17818e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
17828e3332e2SSjoerd Simons 	if (ret)
17838e3332e2SSjoerd Simons 		return ret;
1784272cc70bSAndy Fleming 
1785bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
1786272cc70bSAndy Fleming 	print_mmc_devices(',');
1787bb0dc108SYing Zhang #endif
1788272cc70bSAndy Fleming 
1789*c40fdca6SSimon Glass 	mmc_do_preinit();
1790272cc70bSAndy Fleming 	return 0;
1791272cc70bSAndy Fleming }
17923690d6d6SAmar 
17933690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT
17943690d6d6SAmar /*
17953690d6d6SAmar  * This function changes the size of boot partition and the size of rpmb
17963690d6d6SAmar  * partition present on EMMC devices.
17973690d6d6SAmar  *
17983690d6d6SAmar  * Input Parameters:
17993690d6d6SAmar  * struct *mmc: pointer for the mmc device strcuture
18003690d6d6SAmar  * bootsize: size of boot partition
18013690d6d6SAmar  * rpmbsize: size of rpmb partition
18023690d6d6SAmar  *
18033690d6d6SAmar  * Returns 0 on success.
18043690d6d6SAmar  */
18053690d6d6SAmar 
18063690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
18073690d6d6SAmar 				unsigned long rpmbsize)
18083690d6d6SAmar {
18093690d6d6SAmar 	int err;
18103690d6d6SAmar 	struct mmc_cmd cmd;
18113690d6d6SAmar 
18123690d6d6SAmar 	/* Only use this command for raw EMMC moviNAND. Enter backdoor mode */
18133690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18143690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18153690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG1;
18163690d6d6SAmar 
18173690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18183690d6d6SAmar 	if (err) {
18193690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error1 = %d\n", err);
18203690d6d6SAmar 		return err;
18213690d6d6SAmar 	}
18223690d6d6SAmar 
18233690d6d6SAmar 	/* Boot partition changing mode */
18243690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18253690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18263690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG2;
18273690d6d6SAmar 
18283690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18293690d6d6SAmar 	if (err) {
18303690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error2 = %d\n", err);
18313690d6d6SAmar 		return err;
18323690d6d6SAmar 	}
18333690d6d6SAmar 	/* boot partition size is multiple of 128KB */
18343690d6d6SAmar 	bootsize = (bootsize * 1024) / 128;
18353690d6d6SAmar 
18363690d6d6SAmar 	/* Arg: boot partition size */
18373690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18383690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18393690d6d6SAmar 	cmd.cmdarg = bootsize;
18403690d6d6SAmar 
18413690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18423690d6d6SAmar 	if (err) {
18433690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error3 = %d\n", err);
18443690d6d6SAmar 		return err;
18453690d6d6SAmar 	}
18463690d6d6SAmar 	/* RPMB partition size is multiple of 128KB */
18473690d6d6SAmar 	rpmbsize = (rpmbsize * 1024) / 128;
18483690d6d6SAmar 	/* Arg: RPMB partition size */
18493690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18503690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18513690d6d6SAmar 	cmd.cmdarg = rpmbsize;
18523690d6d6SAmar 
18533690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18543690d6d6SAmar 	if (err) {
18553690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error4 = %d\n", err);
18563690d6d6SAmar 		return err;
18573690d6d6SAmar 	}
18583690d6d6SAmar 	return 0;
18593690d6d6SAmar }
18603690d6d6SAmar 
18613690d6d6SAmar /*
18625a99b9deSTom Rini  * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH
18635a99b9deSTom Rini  * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH
18645a99b9deSTom Rini  * and BOOT_MODE.
18655a99b9deSTom Rini  *
18665a99b9deSTom Rini  * Returns 0 on success.
18675a99b9deSTom Rini  */
18685a99b9deSTom Rini int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode)
18695a99b9deSTom Rini {
18705a99b9deSTom Rini 	int err;
18715a99b9deSTom Rini 
18725a99b9deSTom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH,
18735a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) |
18745a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) |
18755a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width));
18765a99b9deSTom Rini 
18775a99b9deSTom Rini 	if (err)
18785a99b9deSTom Rini 		return err;
18795a99b9deSTom Rini 	return 0;
18805a99b9deSTom Rini }
18815a99b9deSTom Rini 
18825a99b9deSTom Rini /*
1883792970b0STom Rini  * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG)
1884792970b0STom Rini  * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and
1885792970b0STom Rini  * PARTITION_ACCESS.
1886792970b0STom Rini  *
1887792970b0STom Rini  * Returns 0 on success.
1888792970b0STom Rini  */
1889792970b0STom Rini int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access)
1890792970b0STom Rini {
1891792970b0STom Rini 	int err;
1892792970b0STom Rini 
1893792970b0STom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
1894792970b0STom Rini 			 EXT_CSD_BOOT_ACK(ack) |
1895792970b0STom Rini 			 EXT_CSD_BOOT_PART_NUM(part_num) |
1896792970b0STom Rini 			 EXT_CSD_PARTITION_ACCESS(access));
1897792970b0STom Rini 
1898792970b0STom Rini 	if (err)
1899792970b0STom Rini 		return err;
1900792970b0STom Rini 	return 0;
1901792970b0STom Rini }
190233ace362STom Rini 
190333ace362STom Rini /*
190433ace362STom Rini  * Modify EXT_CSD[162] which is RST_n_FUNCTION based on the given value
190533ace362STom Rini  * for enable.  Note that this is a write-once field for non-zero values.
190633ace362STom Rini  *
190733ace362STom Rini  * Returns 0 on success.
190833ace362STom Rini  */
190933ace362STom Rini int mmc_set_rst_n_function(struct mmc *mmc, u8 enable)
191033ace362STom Rini {
191133ace362STom Rini 	return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_RST_N_FUNCTION,
191233ace362STom Rini 			  enable);
191333ace362STom Rini }
19143690d6d6SAmar #endif
1915663acabdSSimon Glass 
1916663acabdSSimon Glass U_BOOT_LEGACY_BLK(mmc) = {
1917663acabdSSimon Glass 	.if_typename	= "mmc",
1918663acabdSSimon Glass 	.if_type	= IF_TYPE_MMC,
1919663acabdSSimon Glass 	.max_devs	= -1,
19203c457f4dSSimon Glass 	.get_dev	= mmc_get_dev,
1921e17d1143SSimon Glass 	.select_hwpart	= mmc_select_hwpartp,
1922663acabdSSimon Glass };
1923