xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision ad27dd5e13436b554f0f3cb9cd3e79634494072d)
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 
237c40fdca6SSimon 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",
240c40fdca6SSimon 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 
558c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
559f866a46dSStephen Warren 
560f866a46dSStephen Warren 	return 0;
561f866a46dSStephen Warren }
562f866a46dSStephen Warren 
563fdbb139fSSimon Glass static int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
564bc897b1dSLei Wen {
565f866a46dSStephen Warren 	int ret;
566bc897b1dSLei Wen 
567f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
568bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
569bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
570f866a46dSStephen Warren 
5716dc93e70SPeter Bigot 	/*
5726dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
5736dc93e70SPeter Bigot 	 * to return to representing the raw device.
5746dc93e70SPeter Bigot 	 */
575873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
5766dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
577fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
578873cc1d7SStephen Warren 	}
5796dc93e70SPeter Bigot 
5806dc93e70SPeter Bigot 	return ret;
581bc897b1dSLei Wen }
582bc897b1dSLei Wen 
583e17d1143SSimon Glass static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart)
584e17d1143SSimon Glass {
585e17d1143SSimon Glass 	struct mmc *mmc = find_mmc_device(desc->devnum);
586e17d1143SSimon Glass 	int ret;
587e17d1143SSimon Glass 
588e17d1143SSimon Glass 	if (!mmc)
589e17d1143SSimon Glass 		return -ENODEV;
590e17d1143SSimon Glass 
591e17d1143SSimon Glass 	if (mmc->block_dev.hwpart == hwpart)
592e17d1143SSimon Glass 		return 0;
593e17d1143SSimon Glass 
594e17d1143SSimon Glass 	if (mmc->part_config == MMCPART_NOAVAILABLE)
595e17d1143SSimon Glass 		return -EMEDIUMTYPE;
596e17d1143SSimon Glass 
597fdbb139fSSimon Glass 	ret = mmc_switch_part(mmc, hwpart);
598e17d1143SSimon Glass 	if (ret)
599e17d1143SSimon Glass 		return ret;
600e17d1143SSimon Glass 
601e17d1143SSimon Glass 	return 0;
602e17d1143SSimon Glass }
603e17d1143SSimon Glass 
604ff3882acSSimon Glass int mmc_select_hwpart(int dev_num, int hwpart)
605ff3882acSSimon Glass {
606ff3882acSSimon Glass 	struct mmc *mmc = find_mmc_device(dev_num);
607ff3882acSSimon Glass 	int ret;
608ff3882acSSimon Glass 
609ff3882acSSimon Glass 	if (!mmc)
610ff3882acSSimon Glass 		return -ENODEV;
611ff3882acSSimon Glass 
612ff3882acSSimon Glass 	if (mmc->block_dev.hwpart == hwpart)
613ff3882acSSimon Glass 		return 0;
614ff3882acSSimon Glass 
615ff3882acSSimon Glass 	if (mmc->part_config == MMCPART_NOAVAILABLE)
616ff3882acSSimon Glass 		return -EMEDIUMTYPE;
617ff3882acSSimon Glass 
618fdbb139fSSimon Glass 	ret = mmc_switch_part(mmc, hwpart);
619ff3882acSSimon Glass 	if (ret)
620ff3882acSSimon Glass 		return ret;
621ff3882acSSimon Glass 
622ff3882acSSimon Glass 	return 0;
623ff3882acSSimon Glass }
624ff3882acSSimon Glass 
625ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
626ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
627ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
628ac9da0e0SDiego Santa Cruz {
629ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
630ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
631ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
632ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
633ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
634ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
6358dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
636ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
637ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
638ac9da0e0SDiego Santa Cruz 
639ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
640ac9da0e0SDiego Santa Cruz 		return -EINVAL;
641ac9da0e0SDiego Santa Cruz 
642ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
643ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
644ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
645ac9da0e0SDiego Santa Cruz 	}
646ac9da0e0SDiego Santa Cruz 
647ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
648ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
649ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
650ac9da0e0SDiego Santa Cruz 	}
651ac9da0e0SDiego Santa Cruz 
652ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
653ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
654ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
655ac9da0e0SDiego Santa Cruz 	}
656ac9da0e0SDiego Santa Cruz 
657ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
658ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
659ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
660ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
661ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
662ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
663ac9da0e0SDiego Santa Cruz 			return -EINVAL;
664ac9da0e0SDiego Santa Cruz 		}
665ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
666ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
667ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
668ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
669ac9da0e0SDiego Santa Cruz 		} else {
670ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
671ac9da0e0SDiego Santa Cruz 		}
672ac9da0e0SDiego Santa Cruz 	} else {
673ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
674ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
675ac9da0e0SDiego Santa Cruz 	}
676ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
677ac9da0e0SDiego Santa Cruz 
678ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
679ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
680ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
681ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
682ac9da0e0SDiego Santa Cruz 			return -EINVAL;
683ac9da0e0SDiego Santa Cruz 		}
684ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
685ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
686ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
687ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
688ac9da0e0SDiego Santa Cruz 		}
689ac9da0e0SDiego Santa Cruz 	}
690ac9da0e0SDiego Santa Cruz 
691ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
692ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
693ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
694ac9da0e0SDiego Santa Cruz 	}
695ac9da0e0SDiego Santa Cruz 
696ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
697ac9da0e0SDiego Santa Cruz 	if (err)
698ac9da0e0SDiego Santa Cruz 		return err;
699ac9da0e0SDiego Santa Cruz 
700ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
701ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
702ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
703ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
704ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
705ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
706ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
707ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
708ac9da0e0SDiego Santa Cruz 	}
709ac9da0e0SDiego Santa Cruz 
7108dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
7118dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
7128dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
7138dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
7148dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
7158dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
7168dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
7178dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
7188dda5b0eSDiego Santa Cruz 		else
7198dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
7208dda5b0eSDiego Santa Cruz 	}
7218dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
7228dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
7238dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
7248dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
7258dda5b0eSDiego Santa Cruz 			else
7268dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
7278dda5b0eSDiego Santa Cruz 		}
7288dda5b0eSDiego Santa Cruz 	}
7298dda5b0eSDiego Santa Cruz 
7308dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
7318dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
7328dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
7338dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
7348dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
7358dda5b0eSDiego Santa Cruz 	}
7368dda5b0eSDiego Santa Cruz 
737ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
738ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
739ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
740ac9da0e0SDiego Santa Cruz 		return -EPERM;
741ac9da0e0SDiego Santa Cruz 	}
742ac9da0e0SDiego Santa Cruz 
743ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
744ac9da0e0SDiego Santa Cruz 		return 0;
745ac9da0e0SDiego Santa Cruz 
746ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
747ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
748ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
749ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
750ac9da0e0SDiego Santa Cruz 
751ac9da0e0SDiego Santa Cruz 		if (err)
752ac9da0e0SDiego Santa Cruz 			return err;
753ac9da0e0SDiego Santa Cruz 
754ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
755ac9da0e0SDiego Santa Cruz 
756ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
757ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
758ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
759ac9da0e0SDiego Santa Cruz 
760ac9da0e0SDiego Santa Cruz 	}
761ac9da0e0SDiego Santa Cruz 
762ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
763ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
764ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
765ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
766ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
767ac9da0e0SDiego Santa Cruz 		if (err)
768ac9da0e0SDiego Santa Cruz 			return err;
769ac9da0e0SDiego Santa Cruz 	}
770ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
771ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
772ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
773ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
774ac9da0e0SDiego Santa Cruz 		if (err)
775ac9da0e0SDiego Santa Cruz 			return err;
776ac9da0e0SDiego Santa Cruz 	}
777ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
778ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
779ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
780ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
781ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
782ac9da0e0SDiego Santa Cruz 			if (err)
783ac9da0e0SDiego Santa Cruz 				return err;
784ac9da0e0SDiego Santa Cruz 		}
785ac9da0e0SDiego Santa Cruz 	}
786ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
787ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
788ac9da0e0SDiego Santa Cruz 	if (err)
789ac9da0e0SDiego Santa Cruz 		return err;
790ac9da0e0SDiego Santa Cruz 
791ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
792ac9da0e0SDiego Santa Cruz 		return 0;
793ac9da0e0SDiego Santa Cruz 
7948dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
7958dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
7968dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
7978dda5b0eSDiego Santa Cruz 	 * partitioning. */
7988dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
7998dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
8008dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
8018dda5b0eSDiego Santa Cruz 		if (err)
8028dda5b0eSDiego Santa Cruz 			return err;
8038dda5b0eSDiego Santa Cruz 	}
8048dda5b0eSDiego Santa Cruz 
805ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
806ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
807ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
808ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
809ac9da0e0SDiego Santa Cruz 
810ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
811ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
812ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
813ac9da0e0SDiego Santa Cruz 	if (err)
814ac9da0e0SDiego Santa Cruz 		return err;
815ac9da0e0SDiego Santa Cruz 
816ac9da0e0SDiego Santa Cruz 	return 0;
817ac9da0e0SDiego Santa Cruz }
818ac9da0e0SDiego Santa Cruz 
81948972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
82048972d90SThierry Reding {
82148972d90SThierry Reding 	int cd;
82248972d90SThierry Reding 
82348972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
82448972d90SThierry Reding 
825d4e1da4eSPeter Korsgaard 	if (cd < 0) {
82693bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
82793bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
828d4e1da4eSPeter Korsgaard 		else
829d4e1da4eSPeter Korsgaard 			cd = 1;
830d4e1da4eSPeter Korsgaard 	}
83148972d90SThierry Reding 
83248972d90SThierry Reding 	return cd;
83348972d90SThierry Reding }
83448972d90SThierry Reding 
835fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
836272cc70bSAndy Fleming {
837272cc70bSAndy Fleming 	struct mmc_cmd cmd;
838272cc70bSAndy Fleming 	struct mmc_data data;
839272cc70bSAndy Fleming 
840272cc70bSAndy Fleming 	/* Switch the frequency */
841272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
842272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
843272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
844272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
845272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
846272cc70bSAndy Fleming 
847272cc70bSAndy Fleming 	data.dest = (char *)resp;
848272cc70bSAndy Fleming 	data.blocksize = 64;
849272cc70bSAndy Fleming 	data.blocks = 1;
850272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
851272cc70bSAndy Fleming 
852272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
853272cc70bSAndy Fleming }
854272cc70bSAndy Fleming 
855272cc70bSAndy Fleming 
856fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
857272cc70bSAndy Fleming {
858272cc70bSAndy Fleming 	int err;
859272cc70bSAndy Fleming 	struct mmc_cmd cmd;
860f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
861f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
862272cc70bSAndy Fleming 	struct mmc_data data;
863272cc70bSAndy Fleming 	int timeout;
864272cc70bSAndy Fleming 
865272cc70bSAndy Fleming 	mmc->card_caps = 0;
866272cc70bSAndy Fleming 
867d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
868d52ebf10SThomas Chou 		return 0;
869d52ebf10SThomas Chou 
870272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
871272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
872272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
873272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
874272cc70bSAndy Fleming 
875272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
876272cc70bSAndy Fleming 
877272cc70bSAndy Fleming 	if (err)
878272cc70bSAndy Fleming 		return err;
879272cc70bSAndy Fleming 
880272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
881272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
882272cc70bSAndy Fleming 	cmd.cmdarg = 0;
883272cc70bSAndy Fleming 
884272cc70bSAndy Fleming 	timeout = 3;
885272cc70bSAndy Fleming 
886272cc70bSAndy Fleming retry_scr:
887f781dd38SAnton staaf 	data.dest = (char *)scr;
888272cc70bSAndy Fleming 	data.blocksize = 8;
889272cc70bSAndy Fleming 	data.blocks = 1;
890272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
891272cc70bSAndy Fleming 
892272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
893272cc70bSAndy Fleming 
894272cc70bSAndy Fleming 	if (err) {
895272cc70bSAndy Fleming 		if (timeout--)
896272cc70bSAndy Fleming 			goto retry_scr;
897272cc70bSAndy Fleming 
898272cc70bSAndy Fleming 		return err;
899272cc70bSAndy Fleming 	}
900272cc70bSAndy Fleming 
9014e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
9024e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
903272cc70bSAndy Fleming 
904272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
905272cc70bSAndy Fleming 	case 0:
906272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
907272cc70bSAndy Fleming 		break;
908272cc70bSAndy Fleming 	case 1:
909272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
910272cc70bSAndy Fleming 		break;
911272cc70bSAndy Fleming 	case 2:
912272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
9131741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
9141741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
915272cc70bSAndy Fleming 		break;
916272cc70bSAndy Fleming 	default:
917272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
918272cc70bSAndy Fleming 		break;
919272cc70bSAndy Fleming 	}
920272cc70bSAndy Fleming 
921b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
922b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
923b44c7083SAlagu Sankar 
924272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
925272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
926272cc70bSAndy Fleming 		return 0;
927272cc70bSAndy Fleming 
928272cc70bSAndy Fleming 	timeout = 4;
929272cc70bSAndy Fleming 	while (timeout--) {
930272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
931f781dd38SAnton staaf 				(u8 *)switch_status);
932272cc70bSAndy Fleming 
933272cc70bSAndy Fleming 		if (err)
934272cc70bSAndy Fleming 			return err;
935272cc70bSAndy Fleming 
936272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
9374e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
938272cc70bSAndy Fleming 			break;
939272cc70bSAndy Fleming 	}
940272cc70bSAndy Fleming 
941272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
9424e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
943272cc70bSAndy Fleming 		return 0;
944272cc70bSAndy Fleming 
9452c3fbf4cSMacpaul Lin 	/*
9462c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
9472c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
9482c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
9492c3fbf4cSMacpaul Lin 	 * mode between the host.
9502c3fbf4cSMacpaul Lin 	 */
95193bfd616SPantelis Antoniou 	if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
95293bfd616SPantelis Antoniou 		(mmc->cfg->host_caps & MMC_MODE_HS)))
9532c3fbf4cSMacpaul Lin 		return 0;
9542c3fbf4cSMacpaul Lin 
955f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
956272cc70bSAndy Fleming 
957272cc70bSAndy Fleming 	if (err)
958272cc70bSAndy Fleming 		return err;
959272cc70bSAndy Fleming 
9604e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
961272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
962272cc70bSAndy Fleming 
963272cc70bSAndy Fleming 	return 0;
964272cc70bSAndy Fleming }
965272cc70bSAndy Fleming 
966272cc70bSAndy Fleming /* frequency bases */
967272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
9685f837c2cSMike Frysinger static const int fbase[] = {
969272cc70bSAndy Fleming 	10000,
970272cc70bSAndy Fleming 	100000,
971272cc70bSAndy Fleming 	1000000,
972272cc70bSAndy Fleming 	10000000,
973272cc70bSAndy Fleming };
974272cc70bSAndy Fleming 
975272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
976272cc70bSAndy Fleming  * to platforms without floating point.
977272cc70bSAndy Fleming  */
9785f837c2cSMike Frysinger static const int multipliers[] = {
979272cc70bSAndy Fleming 	0,	/* reserved */
980272cc70bSAndy Fleming 	10,
981272cc70bSAndy Fleming 	12,
982272cc70bSAndy Fleming 	13,
983272cc70bSAndy Fleming 	15,
984272cc70bSAndy Fleming 	20,
985272cc70bSAndy Fleming 	25,
986272cc70bSAndy Fleming 	30,
987272cc70bSAndy Fleming 	35,
988272cc70bSAndy Fleming 	40,
989272cc70bSAndy Fleming 	45,
990272cc70bSAndy Fleming 	50,
991272cc70bSAndy Fleming 	55,
992272cc70bSAndy Fleming 	60,
993272cc70bSAndy Fleming 	70,
994272cc70bSAndy Fleming 	80,
995272cc70bSAndy Fleming };
996272cc70bSAndy Fleming 
997fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
998272cc70bSAndy Fleming {
99993bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
100093bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
1001272cc70bSAndy Fleming }
1002272cc70bSAndy Fleming 
1003272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
1004272cc70bSAndy Fleming {
100593bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
100693bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1007272cc70bSAndy Fleming 
100893bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
100993bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1010272cc70bSAndy Fleming 
1011272cc70bSAndy Fleming 	mmc->clock = clock;
1012272cc70bSAndy Fleming 
1013272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1014272cc70bSAndy Fleming }
1015272cc70bSAndy Fleming 
1016fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width)
1017272cc70bSAndy Fleming {
1018272cc70bSAndy Fleming 	mmc->bus_width = width;
1019272cc70bSAndy Fleming 
1020272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1021272cc70bSAndy Fleming }
1022272cc70bSAndy Fleming 
1023fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1024272cc70bSAndy Fleming {
1025f866a46dSStephen Warren 	int err, i;
1026272cc70bSAndy Fleming 	uint mult, freq;
1027639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
1028272cc70bSAndy Fleming 	struct mmc_cmd cmd;
10298bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
10308bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
10315d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
10320c453bb7SDiego Santa Cruz 	bool has_parts = false;
10338a0cf490SDiego Santa Cruz 	bool part_completed;
1034c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1035272cc70bSAndy Fleming 
1036d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1037d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1038d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1039d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1040d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1041d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1042d52ebf10SThomas Chou 
1043d52ebf10SThomas Chou 		if (err)
1044d52ebf10SThomas Chou 			return err;
1045d52ebf10SThomas Chou 	}
1046d52ebf10SThomas Chou #endif
1047d52ebf10SThomas Chou 
1048272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1049d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1050d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1051272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1052272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1053272cc70bSAndy Fleming 
1054272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1055272cc70bSAndy Fleming 
1056272cc70bSAndy Fleming 	if (err)
1057272cc70bSAndy Fleming 		return err;
1058272cc70bSAndy Fleming 
1059272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1060272cc70bSAndy Fleming 
1061272cc70bSAndy Fleming 	/*
1062272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1063272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1064272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1065272cc70bSAndy Fleming 	 */
1066d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1067272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1068272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1069272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1070272cc70bSAndy Fleming 
1071272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1072272cc70bSAndy Fleming 
1073272cc70bSAndy Fleming 		if (err)
1074272cc70bSAndy Fleming 			return err;
1075272cc70bSAndy Fleming 
1076272cc70bSAndy Fleming 		if (IS_SD(mmc))
1077998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1078d52ebf10SThomas Chou 	}
1079272cc70bSAndy Fleming 
1080272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1081272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1082272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1083272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1084272cc70bSAndy Fleming 
1085272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1086272cc70bSAndy Fleming 
10875d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
10885d4fc8d9SRaffaele Recalcati 	mmc_send_status(mmc, timeout);
10895d4fc8d9SRaffaele Recalcati 
1090272cc70bSAndy Fleming 	if (err)
1091272cc70bSAndy Fleming 		return err;
1092272cc70bSAndy Fleming 
1093998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1094998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1095998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1096998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1097272cc70bSAndy Fleming 
1098272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
10990b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1100272cc70bSAndy Fleming 
1101272cc70bSAndy Fleming 		switch (version) {
1102272cc70bSAndy Fleming 		case 0:
1103272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1104272cc70bSAndy Fleming 			break;
1105272cc70bSAndy Fleming 		case 1:
1106272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1107272cc70bSAndy Fleming 			break;
1108272cc70bSAndy Fleming 		case 2:
1109272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1110272cc70bSAndy Fleming 			break;
1111272cc70bSAndy Fleming 		case 3:
1112272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1113272cc70bSAndy Fleming 			break;
1114272cc70bSAndy Fleming 		case 4:
1115272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1116272cc70bSAndy Fleming 			break;
1117272cc70bSAndy Fleming 		default:
1118272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1119272cc70bSAndy Fleming 			break;
1120272cc70bSAndy Fleming 		}
1121272cc70bSAndy Fleming 	}
1122272cc70bSAndy Fleming 
1123272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
11240b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
11250b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1126272cc70bSAndy Fleming 
1127272cc70bSAndy Fleming 	mmc->tran_speed = freq * mult;
1128272cc70bSAndy Fleming 
1129ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1130998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1131272cc70bSAndy Fleming 
1132272cc70bSAndy Fleming 	if (IS_SD(mmc))
1133272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1134272cc70bSAndy Fleming 	else
1135998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1136272cc70bSAndy Fleming 
1137272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1138272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1139272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1140272cc70bSAndy Fleming 		cmult = 8;
1141272cc70bSAndy Fleming 	} else {
1142272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1143272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1144272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1145272cc70bSAndy Fleming 	}
1146272cc70bSAndy Fleming 
1147f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1148f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1149f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1150f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1151f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1152f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1153272cc70bSAndy Fleming 
11548bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
11558bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1156272cc70bSAndy Fleming 
11578bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
11588bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1159272cc70bSAndy Fleming 
1160ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1161ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1162ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1163ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1164ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1165ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1166ab71188cSMarkus Niebel 	}
1167ab71188cSMarkus Niebel 
1168272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1169d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1170272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1171fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1172272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1173272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1174272cc70bSAndy Fleming 
1175272cc70bSAndy Fleming 		if (err)
1176272cc70bSAndy Fleming 			return err;
1177d52ebf10SThomas Chou 	}
1178272cc70bSAndy Fleming 
1179e6f99a56SLei Wen 	/*
1180e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1181e6f99a56SLei Wen 	 */
1182e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1183bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1184d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
1185d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
1186d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
11879cf199ebSDiego Santa Cruz 		if (err)
11889cf199ebSDiego Santa Cruz 			return err;
11899cf199ebSDiego Santa Cruz 		if (ext_csd[EXT_CSD_REV] >= 2) {
1190639b7827SYoshihiro Shimoda 			/*
1191639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
1192639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
1193639b7827SYoshihiro Shimoda 			 * than 2GB
1194639b7827SYoshihiro Shimoda 			 */
11950560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
11960560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
11970560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
11980560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
11998bfa195eSSimon Glass 			capacity *= MMC_MAX_BLOCK_LEN;
1200b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
1201f866a46dSStephen Warren 				mmc->capacity_user = capacity;
1202d23e2c09SSukumar Ghorai 		}
1203bc897b1dSLei Wen 
120464f4a619SJaehoon Chung 		switch (ext_csd[EXT_CSD_REV]) {
120564f4a619SJaehoon Chung 		case 1:
120664f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_1;
120764f4a619SJaehoon Chung 			break;
120864f4a619SJaehoon Chung 		case 2:
120964f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_2;
121064f4a619SJaehoon Chung 			break;
121164f4a619SJaehoon Chung 		case 3:
121264f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_3;
121364f4a619SJaehoon Chung 			break;
121464f4a619SJaehoon Chung 		case 5:
121564f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_41;
121664f4a619SJaehoon Chung 			break;
121764f4a619SJaehoon Chung 		case 6:
121864f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_5;
121964f4a619SJaehoon Chung 			break;
1220edab723bSMarkus Niebel 		case 7:
1221edab723bSMarkus Niebel 			mmc->version = MMC_VERSION_5_0;
1222edab723bSMarkus Niebel 			break;
122364f4a619SJaehoon Chung 		}
122464f4a619SJaehoon Chung 
12258a0cf490SDiego Santa Cruz 		/* The partition data may be non-zero but it is only
12268a0cf490SDiego Santa Cruz 		 * effective if PARTITION_SETTING_COMPLETED is set in
12278a0cf490SDiego Santa Cruz 		 * EXT_CSD, so ignore any data if this bit is not set,
12288a0cf490SDiego Santa Cruz 		 * except for enabling the high-capacity group size
12298a0cf490SDiego Santa Cruz 		 * definition (see below). */
12308a0cf490SDiego Santa Cruz 		part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
12318a0cf490SDiego Santa Cruz 				    EXT_CSD_PARTITION_SETTING_COMPLETED);
12328a0cf490SDiego Santa Cruz 
12330c453bb7SDiego Santa Cruz 		/* store the partition info of emmc */
12340c453bb7SDiego Santa Cruz 		mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
12350c453bb7SDiego Santa Cruz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
12360c453bb7SDiego Santa Cruz 		    ext_csd[EXT_CSD_BOOT_MULT])
12370c453bb7SDiego Santa Cruz 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
12388a0cf490SDiego Santa Cruz 		if (part_completed &&
12398a0cf490SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
12400c453bb7SDiego Santa Cruz 			mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
12410c453bb7SDiego Santa Cruz 
12420c453bb7SDiego Santa Cruz 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
12430c453bb7SDiego Santa Cruz 
12440c453bb7SDiego Santa Cruz 		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
12450c453bb7SDiego Santa Cruz 
12460c453bb7SDiego Santa Cruz 		for (i = 0; i < 4; i++) {
12470c453bb7SDiego Santa Cruz 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
12488a0cf490SDiego Santa Cruz 			uint mult = (ext_csd[idx + 2] << 16) +
12490c453bb7SDiego Santa Cruz 				(ext_csd[idx + 1] << 8) + ext_csd[idx];
12508a0cf490SDiego Santa Cruz 			if (mult)
12518a0cf490SDiego Santa Cruz 				has_parts = true;
12528a0cf490SDiego Santa Cruz 			if (!part_completed)
12538a0cf490SDiego Santa Cruz 				continue;
12548a0cf490SDiego Santa Cruz 			mmc->capacity_gp[i] = mult;
12550c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *=
12560c453bb7SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
12570c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1258f8e89d67SDiego Santa Cruz 			mmc->capacity_gp[i] <<= 19;
12590c453bb7SDiego Santa Cruz 		}
12600c453bb7SDiego Santa Cruz 
12618a0cf490SDiego Santa Cruz 		if (part_completed) {
1262a7f852b6SDiego Santa Cruz 			mmc->enh_user_size =
1263a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
1264a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
1265a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_SIZE_MULT];
1266a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1267a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1268a7f852b6SDiego Santa Cruz 			mmc->enh_user_size <<= 19;
1269a7f852b6SDiego Santa Cruz 			mmc->enh_user_start =
1270a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
1271a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
1272a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
1273a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_START_ADDR];
1274a7f852b6SDiego Santa Cruz 			if (mmc->high_capacity)
1275a7f852b6SDiego Santa Cruz 				mmc->enh_user_start <<= 9;
12768a0cf490SDiego Santa Cruz 		}
1277a7f852b6SDiego Santa Cruz 
1278e6f99a56SLei Wen 		/*
12791937e5aaSOliver Metz 		 * Host needs to enable ERASE_GRP_DEF bit if device is
12801937e5aaSOliver Metz 		 * partitioned. This bit will be lost every time after a reset
12811937e5aaSOliver Metz 		 * or power off. This will affect erase size.
1282e6f99a56SLei Wen 		 */
12838a0cf490SDiego Santa Cruz 		if (part_completed)
12840c453bb7SDiego Santa Cruz 			has_parts = true;
12851937e5aaSOliver Metz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
12860c453bb7SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
12870c453bb7SDiego Santa Cruz 			has_parts = true;
12880c453bb7SDiego Santa Cruz 		if (has_parts) {
12891937e5aaSOliver Metz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
12901937e5aaSOliver Metz 				EXT_CSD_ERASE_GROUP_DEF, 1);
12911937e5aaSOliver Metz 
12921937e5aaSOliver Metz 			if (err)
12931937e5aaSOliver Metz 				return err;
1294021a8055SHannes Petermaier 			else
1295021a8055SHannes Petermaier 				ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1296037dc0abSDiego Santa Cruz 		}
12971937e5aaSOliver Metz 
1298037dc0abSDiego Santa Cruz 		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
12991937e5aaSOliver Metz 			/* Read out group size from ext_csd */
13000560db18SLei Wen 			mmc->erase_grp_size =
1301a4ff9f83SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1302d7b29129SMarkus Niebel 			/*
1303d7b29129SMarkus Niebel 			 * if high capacity and partition setting completed
1304d7b29129SMarkus Niebel 			 * SEC_COUNT is valid even if it is smaller than 2 GiB
1305d7b29129SMarkus Niebel 			 * JEDEC Standard JESD84-B45, 6.2.4
1306d7b29129SMarkus Niebel 			 */
13078a0cf490SDiego Santa Cruz 			if (mmc->high_capacity && part_completed) {
1308d7b29129SMarkus Niebel 				capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1309d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1310d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1311d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1312d7b29129SMarkus Niebel 				capacity *= MMC_MAX_BLOCK_LEN;
1313d7b29129SMarkus Niebel 				mmc->capacity_user = capacity;
1314d7b29129SMarkus Niebel 			}
13158bfa195eSSimon Glass 		} else {
13161937e5aaSOliver Metz 			/* Calculate the group size from the csd value. */
1317e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
1318e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1319e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1320e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
1321e6f99a56SLei Wen 				* (erase_gmul + 1);
1322e6f99a56SLei Wen 		}
1323037dc0abSDiego Santa Cruz 
1324037dc0abSDiego Santa Cruz 		mmc->hc_wp_grp_size = 1024
1325037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1326037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
13279e41a00bSDiego Santa Cruz 
13289e41a00bSDiego Santa Cruz 		mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1329f866a46dSStephen Warren 	}
1330f866a46dSStephen Warren 
1331c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
1332f866a46dSStephen Warren 	if (err)
1333f866a46dSStephen Warren 		return err;
1334d23e2c09SSukumar Ghorai 
1335272cc70bSAndy Fleming 	if (IS_SD(mmc))
1336272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1337272cc70bSAndy Fleming 	else
1338272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1339272cc70bSAndy Fleming 
1340272cc70bSAndy Fleming 	if (err)
1341272cc70bSAndy Fleming 		return err;
1342272cc70bSAndy Fleming 
1343272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
134493bfd616SPantelis Antoniou 	mmc->card_caps &= mmc->cfg->host_caps;
1345272cc70bSAndy Fleming 
1346272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1347272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1348272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1349272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1350272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1351272cc70bSAndy Fleming 
1352272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1353272cc70bSAndy Fleming 			if (err)
1354272cc70bSAndy Fleming 				return err;
1355272cc70bSAndy Fleming 
1356272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1357272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1358272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1359272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1360272cc70bSAndy Fleming 			if (err)
1361272cc70bSAndy Fleming 				return err;
1362272cc70bSAndy Fleming 
1363272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1364272cc70bSAndy Fleming 		}
1365272cc70bSAndy Fleming 
1366272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
1367ad5fd922SJaehoon Chung 			mmc->tran_speed = 50000000;
1368272cc70bSAndy Fleming 		else
1369ad5fd922SJaehoon Chung 			mmc->tran_speed = 25000000;
1370fc5b32fbSAndrew Gabbasov 	} else if (mmc->version >= MMC_VERSION_4) {
1371fc5b32fbSAndrew Gabbasov 		/* Only version 4 of MMC supports wider bus widths */
13727798f6dbSAndy Fleming 		int idx;
13737798f6dbSAndy Fleming 
13747798f6dbSAndy Fleming 		/* An array of possible bus widths in order of preference */
13757798f6dbSAndy Fleming 		static unsigned ext_csd_bits[] = {
1376d22e3d46SJaehoon Chung 			EXT_CSD_DDR_BUS_WIDTH_8,
1377d22e3d46SJaehoon Chung 			EXT_CSD_DDR_BUS_WIDTH_4,
13787798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_8,
13797798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_4,
13807798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_1,
13817798f6dbSAndy Fleming 		};
13827798f6dbSAndy Fleming 
13837798f6dbSAndy Fleming 		/* An array to map CSD bus widths to host cap bits */
13847798f6dbSAndy Fleming 		static unsigned ext_to_hostcaps[] = {
1385786e8f81SAndrew Gabbasov 			[EXT_CSD_DDR_BUS_WIDTH_4] =
1386786e8f81SAndrew Gabbasov 				MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
1387786e8f81SAndrew Gabbasov 			[EXT_CSD_DDR_BUS_WIDTH_8] =
1388786e8f81SAndrew Gabbasov 				MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
13897798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
13907798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
13917798f6dbSAndy Fleming 		};
13927798f6dbSAndy Fleming 
13937798f6dbSAndy Fleming 		/* An array to map chosen bus width to an integer */
13947798f6dbSAndy Fleming 		static unsigned widths[] = {
1395d22e3d46SJaehoon Chung 			8, 4, 8, 4, 1,
13967798f6dbSAndy Fleming 		};
13977798f6dbSAndy Fleming 
13987798f6dbSAndy Fleming 		for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
13997798f6dbSAndy Fleming 			unsigned int extw = ext_csd_bits[idx];
1400786e8f81SAndrew Gabbasov 			unsigned int caps = ext_to_hostcaps[extw];
14017798f6dbSAndy Fleming 
14027798f6dbSAndy Fleming 			/*
1403bf477073SAndrew Gabbasov 			 * If the bus width is still not changed,
1404bf477073SAndrew Gabbasov 			 * don't try to set the default again.
1405bf477073SAndrew Gabbasov 			 * Otherwise, recover from switch attempts
1406bf477073SAndrew Gabbasov 			 * by switching to 1-bit bus width.
1407bf477073SAndrew Gabbasov 			 */
1408bf477073SAndrew Gabbasov 			if (extw == EXT_CSD_BUS_WIDTH_1 &&
1409bf477073SAndrew Gabbasov 					mmc->bus_width == 1) {
1410bf477073SAndrew Gabbasov 				err = 0;
1411bf477073SAndrew Gabbasov 				break;
1412bf477073SAndrew Gabbasov 			}
1413bf477073SAndrew Gabbasov 
1414bf477073SAndrew Gabbasov 			/*
1415786e8f81SAndrew Gabbasov 			 * Check to make sure the card and controller support
1416786e8f81SAndrew Gabbasov 			 * these capabilities
14177798f6dbSAndy Fleming 			 */
1418786e8f81SAndrew Gabbasov 			if ((mmc->card_caps & caps) != caps)
14197798f6dbSAndy Fleming 				continue;
14207798f6dbSAndy Fleming 
1421272cc70bSAndy Fleming 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
14227798f6dbSAndy Fleming 					EXT_CSD_BUS_WIDTH, extw);
1423272cc70bSAndy Fleming 
1424272cc70bSAndy Fleming 			if (err)
14254137894eSLei Wen 				continue;
1426272cc70bSAndy Fleming 
1427786e8f81SAndrew Gabbasov 			mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
14287798f6dbSAndy Fleming 			mmc_set_bus_width(mmc, widths[idx]);
1429272cc70bSAndy Fleming 
14304137894eSLei Wen 			err = mmc_send_ext_csd(mmc, test_csd);
1431272cc70bSAndy Fleming 
1432786e8f81SAndrew Gabbasov 			if (err)
1433786e8f81SAndrew Gabbasov 				continue;
1434786e8f81SAndrew Gabbasov 
1435786e8f81SAndrew Gabbasov 			/* Only compare read only fields */
1436786e8f81SAndrew Gabbasov 			if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
1437786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
1438786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
1439786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
1440786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_REV]
1441786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_REV] &&
1442786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1443786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
1444786e8f81SAndrew Gabbasov 			    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
1445786e8f81SAndrew Gabbasov 				   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
14464137894eSLei Wen 				break;
1447786e8f81SAndrew Gabbasov 			else
1448786e8f81SAndrew Gabbasov 				err = SWITCH_ERR;
14494137894eSLei Wen 		}
1450786e8f81SAndrew Gabbasov 
1451786e8f81SAndrew Gabbasov 		if (err)
1452786e8f81SAndrew Gabbasov 			return err;
1453272cc70bSAndy Fleming 
1454272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS) {
1455272cc70bSAndy Fleming 			if (mmc->card_caps & MMC_MODE_HS_52MHz)
1456ad5fd922SJaehoon Chung 				mmc->tran_speed = 52000000;
1457272cc70bSAndy Fleming 			else
1458ad5fd922SJaehoon Chung 				mmc->tran_speed = 26000000;
1459272cc70bSAndy Fleming 		}
1460ad5fd922SJaehoon Chung 	}
1461ad5fd922SJaehoon Chung 
1462ad5fd922SJaehoon Chung 	mmc_set_clock(mmc, mmc->tran_speed);
1463272cc70bSAndy Fleming 
14645af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
14655af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
14665af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
14675af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
14685af8f45cSAndrew Gabbasov 	}
14695af8f45cSAndrew Gabbasov 
1470272cc70bSAndy Fleming 	/* fill in device description */
1471c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1472c40fdca6SSimon Glass 	bdesc->lun = 0;
1473c40fdca6SSimon Glass 	bdesc->hwpart = 0;
1474c40fdca6SSimon Glass 	bdesc->type = 0;
1475c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
1476c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
1477c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1478fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1479fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1480fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1481c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
1482babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1483babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1484c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
14850b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1486babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1487babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1488c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1489babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
149056196826SPaul Burton #else
1491c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
1492c40fdca6SSimon Glass 	bdesc->product[0] = 0;
1493c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
149456196826SPaul Burton #endif
1495122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1496c40fdca6SSimon Glass 	part_init(bdesc);
1497122efd43SMikhail Kshevetskiy #endif
1498272cc70bSAndy Fleming 
1499272cc70bSAndy Fleming 	return 0;
1500272cc70bSAndy Fleming }
1501272cc70bSAndy Fleming 
1502fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1503272cc70bSAndy Fleming {
1504272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1505272cc70bSAndy Fleming 	int err;
1506272cc70bSAndy Fleming 
1507272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1508272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
150993bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1510272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1511272cc70bSAndy Fleming 
1512272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1513272cc70bSAndy Fleming 
1514272cc70bSAndy Fleming 	if (err)
1515272cc70bSAndy Fleming 		return err;
1516272cc70bSAndy Fleming 
1517998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1518272cc70bSAndy Fleming 		return UNUSABLE_ERR;
1519272cc70bSAndy Fleming 	else
1520272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1521272cc70bSAndy Fleming 
1522272cc70bSAndy Fleming 	return 0;
1523272cc70bSAndy Fleming }
1524272cc70bSAndy Fleming 
152593bfd616SPantelis Antoniou /* not used any more */
152693bfd616SPantelis Antoniou int __deprecated mmc_register(struct mmc *mmc)
1527272cc70bSAndy Fleming {
152893bfd616SPantelis Antoniou #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
152993bfd616SPantelis Antoniou 	printf("%s is deprecated! use mmc_create() instead.\n", __func__);
153093bfd616SPantelis Antoniou #endif
153193bfd616SPantelis Antoniou 	return -1;
153293bfd616SPantelis Antoniou }
153393bfd616SPantelis Antoniou 
1534*ad27dd5eSSimon Glass #ifdef CONFIG_BLK
1535*ad27dd5eSSimon Glass int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg)
1536*ad27dd5eSSimon Glass {
1537*ad27dd5eSSimon Glass 	struct blk_desc *bdesc;
1538*ad27dd5eSSimon Glass 	struct udevice *bdev;
1539*ad27dd5eSSimon Glass 	int ret;
1540*ad27dd5eSSimon Glass 
1541*ad27dd5eSSimon Glass 	ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC, -1, 512,
1542*ad27dd5eSSimon Glass 				 0, &bdev);
1543*ad27dd5eSSimon Glass 	if (ret) {
1544*ad27dd5eSSimon Glass 		debug("Cannot create block device\n");
1545*ad27dd5eSSimon Glass 		return ret;
1546*ad27dd5eSSimon Glass 	}
1547*ad27dd5eSSimon Glass 	bdesc = dev_get_uclass_platdata(bdev);
1548*ad27dd5eSSimon Glass 	mmc->cfg = cfg;
1549*ad27dd5eSSimon Glass 	mmc->priv = dev;
1550*ad27dd5eSSimon Glass 
1551*ad27dd5eSSimon Glass 	/* the following chunk was from mmc_register() */
1552*ad27dd5eSSimon Glass 
1553*ad27dd5eSSimon Glass 	/* Setup dsr related values */
1554*ad27dd5eSSimon Glass 	mmc->dsr_imp = 0;
1555*ad27dd5eSSimon Glass 	mmc->dsr = 0xffffffff;
1556*ad27dd5eSSimon Glass 	/* Setup the universal parts of the block interface just once */
1557*ad27dd5eSSimon Glass 	bdesc->if_type = IF_TYPE_MMC;
1558*ad27dd5eSSimon Glass 	bdesc->removable = 1;
1559*ad27dd5eSSimon Glass 
1560*ad27dd5eSSimon Glass 	/* setup initial part type */
1561*ad27dd5eSSimon Glass 	bdesc->part_type = mmc->cfg->part_type;
1562*ad27dd5eSSimon Glass 	mmc->dev = dev;
1563*ad27dd5eSSimon Glass 
1564*ad27dd5eSSimon Glass 	return 0;
1565*ad27dd5eSSimon Glass }
1566*ad27dd5eSSimon Glass 
1567*ad27dd5eSSimon Glass int mmc_unbind(struct udevice *dev)
1568*ad27dd5eSSimon Glass {
1569*ad27dd5eSSimon Glass 	struct udevice *bdev;
1570*ad27dd5eSSimon Glass 
1571*ad27dd5eSSimon Glass 	device_find_first_child(dev, &bdev);
1572*ad27dd5eSSimon Glass 	if (bdev) {
1573*ad27dd5eSSimon Glass 		device_remove(bdev);
1574*ad27dd5eSSimon Glass 		device_unbind(bdev);
1575*ad27dd5eSSimon Glass 	}
1576*ad27dd5eSSimon Glass 
1577*ad27dd5eSSimon Glass 	return 0;
1578*ad27dd5eSSimon Glass }
1579*ad27dd5eSSimon Glass 
1580*ad27dd5eSSimon Glass #else
158193bfd616SPantelis Antoniou struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
158293bfd616SPantelis Antoniou {
1583c40fdca6SSimon Glass 	struct blk_desc *bdesc;
158493bfd616SPantelis Antoniou 	struct mmc *mmc;
158593bfd616SPantelis Antoniou 
158693bfd616SPantelis Antoniou 	/* quick validation */
158793bfd616SPantelis Antoniou 	if (cfg == NULL || cfg->ops == NULL || cfg->ops->send_cmd == NULL ||
158893bfd616SPantelis Antoniou 			cfg->f_min == 0 || cfg->f_max == 0 || cfg->b_max == 0)
158993bfd616SPantelis Antoniou 		return NULL;
159093bfd616SPantelis Antoniou 
159193bfd616SPantelis Antoniou 	mmc = calloc(1, sizeof(*mmc));
159293bfd616SPantelis Antoniou 	if (mmc == NULL)
159393bfd616SPantelis Antoniou 		return NULL;
159493bfd616SPantelis Antoniou 
159593bfd616SPantelis Antoniou 	mmc->cfg = cfg;
159693bfd616SPantelis Antoniou 	mmc->priv = priv;
159793bfd616SPantelis Antoniou 
159893bfd616SPantelis Antoniou 	/* the following chunk was mmc_register() */
159993bfd616SPantelis Antoniou 
1600ab71188cSMarkus Niebel 	/* Setup dsr related values */
1601ab71188cSMarkus Niebel 	mmc->dsr_imp = 0;
1602ab71188cSMarkus Niebel 	mmc->dsr = 0xffffffff;
1603272cc70bSAndy Fleming 	/* Setup the universal parts of the block interface just once */
1604c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1605c40fdca6SSimon Glass 	bdesc->if_type = IF_TYPE_MMC;
1606c40fdca6SSimon Glass 	bdesc->removable = 1;
1607c40fdca6SSimon Glass 	bdesc->devnum = mmc_get_next_devnum();
1608c40fdca6SSimon Glass 	bdesc->block_read = mmc_bread;
1609c40fdca6SSimon Glass 	bdesc->block_write = mmc_bwrite;
1610c40fdca6SSimon Glass 	bdesc->block_erase = mmc_berase;
161193bfd616SPantelis Antoniou 
161293bfd616SPantelis Antoniou 	/* setup initial part type */
1613c40fdca6SSimon Glass 	bdesc->part_type = mmc->cfg->part_type;
1614c40fdca6SSimon Glass 	mmc_list_add(mmc);
1615272cc70bSAndy Fleming 
161693bfd616SPantelis Antoniou 	return mmc;
161793bfd616SPantelis Antoniou }
161893bfd616SPantelis Antoniou 
161993bfd616SPantelis Antoniou void mmc_destroy(struct mmc *mmc)
162093bfd616SPantelis Antoniou {
162193bfd616SPantelis Antoniou 	/* only freeing memory for now */
162293bfd616SPantelis Antoniou 	free(mmc);
1623272cc70bSAndy Fleming }
1624*ad27dd5eSSimon Glass #endif
1625272cc70bSAndy Fleming 
16263c457f4dSSimon Glass static int mmc_get_dev(int dev, struct blk_desc **descp)
1627663acabdSSimon Glass {
1628663acabdSSimon Glass 	struct mmc *mmc = find_mmc_device(dev);
1629663acabdSSimon Glass 	int ret;
1630663acabdSSimon Glass 
1631663acabdSSimon Glass 	if (!mmc)
1632663acabdSSimon Glass 		return -ENODEV;
1633663acabdSSimon Glass 	ret = mmc_init(mmc);
1634663acabdSSimon Glass 	if (ret)
1635663acabdSSimon Glass 		return ret;
1636663acabdSSimon Glass 
1637663acabdSSimon Glass 	*descp = &mmc->block_dev;
1638663acabdSSimon Glass 
1639663acabdSSimon Glass 	return 0;
1640663acabdSSimon Glass }
1641663acabdSSimon Glass 
164295de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
164395de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
164495de9ab2SPaul Kocialkowski {
164595de9ab2SPaul Kocialkowski }
164695de9ab2SPaul Kocialkowski 
1647e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1648272cc70bSAndy Fleming {
1649afd5932bSMacpaul Lin 	int err;
1650272cc70bSAndy Fleming 
1651ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
165293bfd616SPantelis Antoniou 	if (mmc_getcd(mmc) == 0 || mmc->cfg->ops->init == NULL) {
165348972d90SThierry Reding 		mmc->has_init = 0;
165456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
165548972d90SThierry Reding 		printf("MMC: no card present\n");
165656196826SPaul Burton #endif
165748972d90SThierry Reding 		return NO_CARD_ERR;
165848972d90SThierry Reding 	}
165948972d90SThierry Reding 
1660bc897b1dSLei Wen 	if (mmc->has_init)
1661bc897b1dSLei Wen 		return 0;
1662bc897b1dSLei Wen 
16635a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
16645a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
16655a8dbdc6SYangbo Lu #endif
166695de9ab2SPaul Kocialkowski 	board_mmc_power_init();
166795de9ab2SPaul Kocialkowski 
1668ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
166993bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
1670272cc70bSAndy Fleming 
1671272cc70bSAndy Fleming 	if (err)
1672272cc70bSAndy Fleming 		return err;
1673272cc70bSAndy Fleming 
1674786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
1675b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1676b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1677b86b85e2SIlya Yanok 
1678272cc70bSAndy Fleming 	/* Reset the Card */
1679272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1680272cc70bSAndy Fleming 
1681272cc70bSAndy Fleming 	if (err)
1682272cc70bSAndy Fleming 		return err;
1683272cc70bSAndy Fleming 
1684bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1685c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
1686bc897b1dSLei Wen 
1687272cc70bSAndy Fleming 	/* Test for SD version 2 */
1688272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1689272cc70bSAndy Fleming 
1690272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1691272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1692272cc70bSAndy Fleming 
1693272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1694272cc70bSAndy Fleming 	if (err == TIMEOUT) {
1695272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1696272cc70bSAndy Fleming 
1697bd47c135SAndrew Gabbasov 		if (err) {
169856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1699272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
170056196826SPaul Burton #endif
1701272cc70bSAndy Fleming 			return UNUSABLE_ERR;
1702272cc70bSAndy Fleming 		}
1703272cc70bSAndy Fleming 	}
1704272cc70bSAndy Fleming 
1705bd47c135SAndrew Gabbasov 	if (!err)
1706e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
1707e9550449SChe-Liang Chiou 
1708e9550449SChe-Liang Chiou 	return err;
1709e9550449SChe-Liang Chiou }
1710e9550449SChe-Liang Chiou 
1711e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
1712e9550449SChe-Liang Chiou {
1713e9550449SChe-Liang Chiou 	int err = 0;
1714e9550449SChe-Liang Chiou 
1715bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
1716e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
1717e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
1718e9550449SChe-Liang Chiou 
1719e9550449SChe-Liang Chiou 	if (!err)
1720bc897b1dSLei Wen 		err = mmc_startup(mmc);
1721bc897b1dSLei Wen 	if (err)
1722bc897b1dSLei Wen 		mmc->has_init = 0;
1723bc897b1dSLei Wen 	else
1724bc897b1dSLei Wen 		mmc->has_init = 1;
1725e9550449SChe-Liang Chiou 	return err;
1726e9550449SChe-Liang Chiou }
1727e9550449SChe-Liang Chiou 
1728e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
1729e9550449SChe-Liang Chiou {
1730bd47c135SAndrew Gabbasov 	int err = 0;
1731d803fea5SMateusz Zalega 	unsigned start;
1732e9550449SChe-Liang Chiou 
1733e9550449SChe-Liang Chiou 	if (mmc->has_init)
1734e9550449SChe-Liang Chiou 		return 0;
1735d803fea5SMateusz Zalega 
1736d803fea5SMateusz Zalega 	start = get_timer(0);
1737d803fea5SMateusz Zalega 
1738e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
1739e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
1740e9550449SChe-Liang Chiou 
1741bd47c135SAndrew Gabbasov 	if (!err)
1742e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
1743e9550449SChe-Liang Chiou 	debug("%s: %d, time %lu\n", __func__, err, get_timer(start));
1744bc897b1dSLei Wen 	return err;
1745272cc70bSAndy Fleming }
1746272cc70bSAndy Fleming 
1747ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
1748ab71188cSMarkus Niebel {
1749ab71188cSMarkus Niebel 	mmc->dsr = val;
1750ab71188cSMarkus Niebel 	return 0;
1751ab71188cSMarkus Niebel }
1752ab71188cSMarkus Niebel 
1753cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
1754cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
1755272cc70bSAndy Fleming {
1756272cc70bSAndy Fleming 	return -1;
1757272cc70bSAndy Fleming }
1758272cc70bSAndy Fleming 
1759cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
1760cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
1761cee9ab7cSJeroen Hofstee {
1762cee9ab7cSJeroen Hofstee 	return -1;
1763cee9ab7cSJeroen Hofstee }
1764272cc70bSAndy Fleming 
1765e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
1766e9550449SChe-Liang Chiou {
1767e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
1768e9550449SChe-Liang Chiou }
1769e9550449SChe-Liang Chiou 
17708e3332e2SSjoerd Simons #if defined(CONFIG_DM_MMC) && defined(CONFIG_SPL_BUILD)
17718e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
17728e3332e2SSjoerd Simons {
17738e3332e2SSjoerd Simons 	return 0;
17748e3332e2SSjoerd Simons }
17758e3332e2SSjoerd Simons #elif defined(CONFIG_DM_MMC)
17768e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
17778e3332e2SSjoerd Simons {
17784a1db6d8SSimon Glass 	int ret, i;
17798e3332e2SSjoerd Simons 	struct uclass *uc;
17804a1db6d8SSimon Glass 	struct udevice *dev;
17818e3332e2SSjoerd Simons 
17828e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
17838e3332e2SSjoerd Simons 	if (ret)
17848e3332e2SSjoerd Simons 		return ret;
17858e3332e2SSjoerd Simons 
17864a1db6d8SSimon Glass 	/*
17874a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
17884a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
17894a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
17904a1db6d8SSimon Glass 	 */
17914a1db6d8SSimon Glass 	for (i = 0; ; i++) {
17924a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
17934a1db6d8SSimon Glass 		if (ret == -ENODEV)
17944a1db6d8SSimon Glass 			break;
17954a1db6d8SSimon Glass 	}
17964a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
17974a1db6d8SSimon Glass 		ret = device_probe(dev);
17988e3332e2SSjoerd Simons 		if (ret)
17994a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
18008e3332e2SSjoerd Simons 	}
18018e3332e2SSjoerd Simons 
18028e3332e2SSjoerd Simons 	return 0;
18038e3332e2SSjoerd Simons }
18048e3332e2SSjoerd Simons #else
18058e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
18068e3332e2SSjoerd Simons {
18078e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
18088e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
18098e3332e2SSjoerd Simons 
18108e3332e2SSjoerd Simons 	return 0;
18118e3332e2SSjoerd Simons }
18128e3332e2SSjoerd Simons #endif
1813e9550449SChe-Liang Chiou 
1814272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1815272cc70bSAndy Fleming {
18161b26bab1SDaniel Kochmański 	static int initialized = 0;
18178e3332e2SSjoerd Simons 	int ret;
18181b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
18191b26bab1SDaniel Kochmański 		return 0;
18201b26bab1SDaniel Kochmański 	initialized = 1;
18211b26bab1SDaniel Kochmański 
1822c40fdca6SSimon Glass #ifndef CONFIG_BLK
1823c40fdca6SSimon Glass 	mmc_list_init();
1824c40fdca6SSimon Glass #endif
18258e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
18268e3332e2SSjoerd Simons 	if (ret)
18278e3332e2SSjoerd Simons 		return ret;
1828272cc70bSAndy Fleming 
1829bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
1830272cc70bSAndy Fleming 	print_mmc_devices(',');
1831bb0dc108SYing Zhang #endif
1832272cc70bSAndy Fleming 
1833c40fdca6SSimon Glass 	mmc_do_preinit();
1834272cc70bSAndy Fleming 	return 0;
1835272cc70bSAndy Fleming }
18363690d6d6SAmar 
18373690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT
18383690d6d6SAmar /*
18393690d6d6SAmar  * This function changes the size of boot partition and the size of rpmb
18403690d6d6SAmar  * partition present on EMMC devices.
18413690d6d6SAmar  *
18423690d6d6SAmar  * Input Parameters:
18433690d6d6SAmar  * struct *mmc: pointer for the mmc device strcuture
18443690d6d6SAmar  * bootsize: size of boot partition
18453690d6d6SAmar  * rpmbsize: size of rpmb partition
18463690d6d6SAmar  *
18473690d6d6SAmar  * Returns 0 on success.
18483690d6d6SAmar  */
18493690d6d6SAmar 
18503690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
18513690d6d6SAmar 				unsigned long rpmbsize)
18523690d6d6SAmar {
18533690d6d6SAmar 	int err;
18543690d6d6SAmar 	struct mmc_cmd cmd;
18553690d6d6SAmar 
18563690d6d6SAmar 	/* Only use this command for raw EMMC moviNAND. Enter backdoor mode */
18573690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18583690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18593690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG1;
18603690d6d6SAmar 
18613690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18623690d6d6SAmar 	if (err) {
18633690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error1 = %d\n", err);
18643690d6d6SAmar 		return err;
18653690d6d6SAmar 	}
18663690d6d6SAmar 
18673690d6d6SAmar 	/* Boot partition changing mode */
18683690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18693690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18703690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG2;
18713690d6d6SAmar 
18723690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18733690d6d6SAmar 	if (err) {
18743690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error2 = %d\n", err);
18753690d6d6SAmar 		return err;
18763690d6d6SAmar 	}
18773690d6d6SAmar 	/* boot partition size is multiple of 128KB */
18783690d6d6SAmar 	bootsize = (bootsize * 1024) / 128;
18793690d6d6SAmar 
18803690d6d6SAmar 	/* Arg: boot partition size */
18813690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18823690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18833690d6d6SAmar 	cmd.cmdarg = bootsize;
18843690d6d6SAmar 
18853690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18863690d6d6SAmar 	if (err) {
18873690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error3 = %d\n", err);
18883690d6d6SAmar 		return err;
18893690d6d6SAmar 	}
18903690d6d6SAmar 	/* RPMB partition size is multiple of 128KB */
18913690d6d6SAmar 	rpmbsize = (rpmbsize * 1024) / 128;
18923690d6d6SAmar 	/* Arg: RPMB partition size */
18933690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18943690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18953690d6d6SAmar 	cmd.cmdarg = rpmbsize;
18963690d6d6SAmar 
18973690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18983690d6d6SAmar 	if (err) {
18993690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error4 = %d\n", err);
19003690d6d6SAmar 		return err;
19013690d6d6SAmar 	}
19023690d6d6SAmar 	return 0;
19033690d6d6SAmar }
19043690d6d6SAmar 
19053690d6d6SAmar /*
19065a99b9deSTom Rini  * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH
19075a99b9deSTom Rini  * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH
19085a99b9deSTom Rini  * and BOOT_MODE.
19095a99b9deSTom Rini  *
19105a99b9deSTom Rini  * Returns 0 on success.
19115a99b9deSTom Rini  */
19125a99b9deSTom Rini int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode)
19135a99b9deSTom Rini {
19145a99b9deSTom Rini 	int err;
19155a99b9deSTom Rini 
19165a99b9deSTom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH,
19175a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) |
19185a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) |
19195a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width));
19205a99b9deSTom Rini 
19215a99b9deSTom Rini 	if (err)
19225a99b9deSTom Rini 		return err;
19235a99b9deSTom Rini 	return 0;
19245a99b9deSTom Rini }
19255a99b9deSTom Rini 
19265a99b9deSTom Rini /*
1927792970b0STom Rini  * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG)
1928792970b0STom Rini  * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and
1929792970b0STom Rini  * PARTITION_ACCESS.
1930792970b0STom Rini  *
1931792970b0STom Rini  * Returns 0 on success.
1932792970b0STom Rini  */
1933792970b0STom Rini int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access)
1934792970b0STom Rini {
1935792970b0STom Rini 	int err;
1936792970b0STom Rini 
1937792970b0STom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
1938792970b0STom Rini 			 EXT_CSD_BOOT_ACK(ack) |
1939792970b0STom Rini 			 EXT_CSD_BOOT_PART_NUM(part_num) |
1940792970b0STom Rini 			 EXT_CSD_PARTITION_ACCESS(access));
1941792970b0STom Rini 
1942792970b0STom Rini 	if (err)
1943792970b0STom Rini 		return err;
1944792970b0STom Rini 	return 0;
1945792970b0STom Rini }
194633ace362STom Rini 
194733ace362STom Rini /*
194833ace362STom Rini  * Modify EXT_CSD[162] which is RST_n_FUNCTION based on the given value
194933ace362STom Rini  * for enable.  Note that this is a write-once field for non-zero values.
195033ace362STom Rini  *
195133ace362STom Rini  * Returns 0 on success.
195233ace362STom Rini  */
195333ace362STom Rini int mmc_set_rst_n_function(struct mmc *mmc, u8 enable)
195433ace362STom Rini {
195533ace362STom Rini 	return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_RST_N_FUNCTION,
195633ace362STom Rini 			  enable);
195733ace362STom Rini }
19583690d6d6SAmar #endif
1959663acabdSSimon Glass 
1960663acabdSSimon Glass U_BOOT_LEGACY_BLK(mmc) = {
1961663acabdSSimon Glass 	.if_typename	= "mmc",
1962663acabdSSimon Glass 	.if_type	= IF_TYPE_MMC,
1963663acabdSSimon Glass 	.max_devs	= -1,
19643c457f4dSSimon Glass 	.get_dev	= mmc_get_dev,
1965e17d1143SSimon Glass 	.select_hwpart	= mmc_select_hwpartp,
1966663acabdSSimon Glass };
1967