xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 61fe076f0fceaa00bcbb8901504aedf1d1096293)
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 
21933fb211dSSimon Glass #ifdef CONFIG_BLK
22033fb211dSSimon Glass static ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
22133fb211dSSimon Glass 		       void *dst)
22233fb211dSSimon Glass #else
2234101f687SSimon Glass static ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start,
2247c4213f6SStephen Warren 		       lbaint_t blkcnt, void *dst)
22533fb211dSSimon Glass #endif
226272cc70bSAndy Fleming {
22733fb211dSSimon Glass #ifdef CONFIG_BLK
22833fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
22933fb211dSSimon Glass #endif
230bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
231873cc1d7SStephen Warren 	int err;
2324a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
233272cc70bSAndy Fleming 
2344a1a06bcSAlagu Sankar 	if (blkcnt == 0)
2354a1a06bcSAlagu Sankar 		return 0;
2364a1a06bcSAlagu Sankar 
2374a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
238272cc70bSAndy Fleming 	if (!mmc)
239272cc70bSAndy Fleming 		return 0;
240272cc70bSAndy Fleming 
24169f45cd5SSimon Glass 	err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
242873cc1d7SStephen Warren 	if (err < 0)
243873cc1d7SStephen Warren 		return 0;
244873cc1d7SStephen Warren 
245c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
24656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
247ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
248c40fdca6SSimon Glass 			start + blkcnt, block_dev->lba);
24956196826SPaul Burton #endif
250d2bf29e3SLei Wen 		return 0;
251d2bf29e3SLei Wen 	}
252272cc70bSAndy Fleming 
25311692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
25411692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
255272cc70bSAndy Fleming 		return 0;
25611692991SSimon Glass 	}
257272cc70bSAndy Fleming 
2584a1a06bcSAlagu Sankar 	do {
25993bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
26093bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
26111692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
26211692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
2634a1a06bcSAlagu Sankar 			return 0;
26411692991SSimon Glass 		}
2654a1a06bcSAlagu Sankar 		blocks_todo -= cur;
2664a1a06bcSAlagu Sankar 		start += cur;
2674a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
2684a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
269272cc70bSAndy Fleming 
270272cc70bSAndy Fleming 	return blkcnt;
271272cc70bSAndy Fleming }
272272cc70bSAndy Fleming 
273fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
274272cc70bSAndy Fleming {
275272cc70bSAndy Fleming 	struct mmc_cmd cmd;
276272cc70bSAndy Fleming 	int err;
277272cc70bSAndy Fleming 
278272cc70bSAndy Fleming 	udelay(1000);
279272cc70bSAndy Fleming 
280272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
281272cc70bSAndy Fleming 	cmd.cmdarg = 0;
282272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
283272cc70bSAndy Fleming 
284272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
285272cc70bSAndy Fleming 
286272cc70bSAndy Fleming 	if (err)
287272cc70bSAndy Fleming 		return err;
288272cc70bSAndy Fleming 
289272cc70bSAndy Fleming 	udelay(2000);
290272cc70bSAndy Fleming 
291272cc70bSAndy Fleming 	return 0;
292272cc70bSAndy Fleming }
293272cc70bSAndy Fleming 
294fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
295272cc70bSAndy Fleming {
296272cc70bSAndy Fleming 	int timeout = 1000;
297272cc70bSAndy Fleming 	int err;
298272cc70bSAndy Fleming 	struct mmc_cmd cmd;
299272cc70bSAndy Fleming 
3001677eef4SAndrew Gabbasov 	while (1) {
301272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
302272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
303272cc70bSAndy Fleming 		cmd.cmdarg = 0;
304272cc70bSAndy Fleming 
305272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
306272cc70bSAndy Fleming 
307272cc70bSAndy Fleming 		if (err)
308272cc70bSAndy Fleming 			return err;
309272cc70bSAndy Fleming 
310272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
311272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
312250de12bSStefano Babic 
313250de12bSStefano Babic 		/*
314250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
315250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
316250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
317250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
318250de12bSStefano Babic 		 * specified.
319250de12bSStefano Babic 		 */
320d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
32193bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
322272cc70bSAndy Fleming 
323272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
324272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
325272cc70bSAndy Fleming 
326272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
327272cc70bSAndy Fleming 
328272cc70bSAndy Fleming 		if (err)
329272cc70bSAndy Fleming 			return err;
330272cc70bSAndy Fleming 
3311677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
3321677eef4SAndrew Gabbasov 			break;
333272cc70bSAndy Fleming 
3341677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
335272cc70bSAndy Fleming 			return UNUSABLE_ERR;
336272cc70bSAndy Fleming 
3371677eef4SAndrew Gabbasov 		udelay(1000);
3381677eef4SAndrew Gabbasov 	}
3391677eef4SAndrew Gabbasov 
340272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
341272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
342272cc70bSAndy Fleming 
343d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
344d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
345d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
346d52ebf10SThomas Chou 		cmd.cmdarg = 0;
347d52ebf10SThomas Chou 
348d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
349d52ebf10SThomas Chou 
350d52ebf10SThomas Chou 		if (err)
351d52ebf10SThomas Chou 			return err;
352d52ebf10SThomas Chou 	}
353d52ebf10SThomas Chou 
354998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
355272cc70bSAndy Fleming 
356272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
357272cc70bSAndy Fleming 	mmc->rca = 0;
358272cc70bSAndy Fleming 
359272cc70bSAndy Fleming 	return 0;
360272cc70bSAndy Fleming }
361272cc70bSAndy Fleming 
3625289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
363272cc70bSAndy Fleming {
3645289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
365272cc70bSAndy Fleming 	int err;
366272cc70bSAndy Fleming 
3675289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
3685289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
3695289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
3705a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
3715a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
37293bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
373a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
374a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
375e9550449SChe-Liang Chiou 
3765289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
377e9550449SChe-Liang Chiou 	if (err)
378e9550449SChe-Liang Chiou 		return err;
3795289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
380e9550449SChe-Liang Chiou 	return 0;
381e9550449SChe-Liang Chiou }
382e9550449SChe-Liang Chiou 
383750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
384e9550449SChe-Liang Chiou {
385e9550449SChe-Liang Chiou 	int err, i;
386e9550449SChe-Liang Chiou 
387272cc70bSAndy Fleming 	/* Some cards seem to need this */
388272cc70bSAndy Fleming 	mmc_go_idle(mmc);
389272cc70bSAndy Fleming 
39031cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
391e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
3925289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
39331cacbabSRaffaele Recalcati 		if (err)
39431cacbabSRaffaele Recalcati 			return err;
39531cacbabSRaffaele Recalcati 
396e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
397a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
398bd47c135SAndrew Gabbasov 			break;
399e9550449SChe-Liang Chiou 	}
400bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
401bd47c135SAndrew Gabbasov 	return 0;
402e9550449SChe-Liang Chiou }
40331cacbabSRaffaele Recalcati 
404750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
405e9550449SChe-Liang Chiou {
406e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
407e9550449SChe-Liang Chiou 	int timeout = 1000;
408e9550449SChe-Liang Chiou 	uint start;
409e9550449SChe-Liang Chiou 	int err;
410e9550449SChe-Liang Chiou 
411e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
412cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
413e9550449SChe-Liang Chiou 		start = get_timer(0);
4141677eef4SAndrew Gabbasov 		while (1) {
4155289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
416272cc70bSAndy Fleming 			if (err)
417272cc70bSAndy Fleming 				return err;
4181677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
4191677eef4SAndrew Gabbasov 				break;
420e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
421272cc70bSAndy Fleming 				return UNUSABLE_ERR;
422e9550449SChe-Liang Chiou 			udelay(100);
4231677eef4SAndrew Gabbasov 		}
424cc17c01fSAndrew Gabbasov 	}
425272cc70bSAndy Fleming 
426d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
427d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
428d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
429d52ebf10SThomas Chou 		cmd.cmdarg = 0;
430d52ebf10SThomas Chou 
431d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
432d52ebf10SThomas Chou 
433d52ebf10SThomas Chou 		if (err)
434d52ebf10SThomas Chou 			return err;
435a626c8d4SAndrew Gabbasov 
436a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
437d52ebf10SThomas Chou 	}
438d52ebf10SThomas Chou 
439272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
440272cc70bSAndy Fleming 
441272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
442def816a2SStephen Warren 	mmc->rca = 1;
443272cc70bSAndy Fleming 
444272cc70bSAndy Fleming 	return 0;
445272cc70bSAndy Fleming }
446272cc70bSAndy Fleming 
447272cc70bSAndy Fleming 
448fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
449272cc70bSAndy Fleming {
450272cc70bSAndy Fleming 	struct mmc_cmd cmd;
451272cc70bSAndy Fleming 	struct mmc_data data;
452272cc70bSAndy Fleming 	int err;
453272cc70bSAndy Fleming 
454272cc70bSAndy Fleming 	/* Get the Card Status Register */
455272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
456272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
457272cc70bSAndy Fleming 	cmd.cmdarg = 0;
458272cc70bSAndy Fleming 
459cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
460272cc70bSAndy Fleming 	data.blocks = 1;
4618bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
462272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
463272cc70bSAndy Fleming 
464272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
465272cc70bSAndy Fleming 
466272cc70bSAndy Fleming 	return err;
467272cc70bSAndy Fleming }
468272cc70bSAndy Fleming 
469272cc70bSAndy Fleming 
470fdbb873eSKim Phillips static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
471272cc70bSAndy Fleming {
472272cc70bSAndy Fleming 	struct mmc_cmd cmd;
4735d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
4745d4fc8d9SRaffaele Recalcati 	int ret;
475272cc70bSAndy Fleming 
476272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
477272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
478272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
479272cc70bSAndy Fleming 				 (index << 16) |
480272cc70bSAndy Fleming 				 (value << 8);
481272cc70bSAndy Fleming 
4825d4fc8d9SRaffaele Recalcati 	ret = mmc_send_cmd(mmc, &cmd, NULL);
4835d4fc8d9SRaffaele Recalcati 
4845d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
48593ad0d18SJan Kloetzke 	if (!ret)
48693ad0d18SJan Kloetzke 		ret = mmc_send_status(mmc, timeout);
4875d4fc8d9SRaffaele Recalcati 
4885d4fc8d9SRaffaele Recalcati 	return ret;
4895d4fc8d9SRaffaele Recalcati 
490272cc70bSAndy Fleming }
491272cc70bSAndy Fleming 
492fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
493272cc70bSAndy Fleming {
4948bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
495272cc70bSAndy Fleming 	char cardtype;
496272cc70bSAndy Fleming 	int err;
497272cc70bSAndy Fleming 
498fc5b32fbSAndrew Gabbasov 	mmc->card_caps = 0;
499272cc70bSAndy Fleming 
500d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
501d52ebf10SThomas Chou 		return 0;
502d52ebf10SThomas Chou 
503272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
504272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
505272cc70bSAndy Fleming 		return 0;
506272cc70bSAndy Fleming 
507fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
508fc5b32fbSAndrew Gabbasov 
509272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
510272cc70bSAndy Fleming 
511272cc70bSAndy Fleming 	if (err)
512272cc70bSAndy Fleming 		return err;
513272cc70bSAndy Fleming 
5140560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
515272cc70bSAndy Fleming 
516272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
517272cc70bSAndy Fleming 
518272cc70bSAndy Fleming 	if (err)
5196b2221b0SAndrew Gabbasov 		return err == SWITCH_ERR ? 0 : err;
520272cc70bSAndy Fleming 
521272cc70bSAndy Fleming 	/* Now check to see that it worked */
522272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
523272cc70bSAndy Fleming 
524272cc70bSAndy Fleming 	if (err)
525272cc70bSAndy Fleming 		return err;
526272cc70bSAndy Fleming 
527272cc70bSAndy Fleming 	/* No high-speed support */
5280560db18SLei Wen 	if (!ext_csd[EXT_CSD_HS_TIMING])
529272cc70bSAndy Fleming 		return 0;
530272cc70bSAndy Fleming 
531272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
532d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
533201d5ac4SAndrew Gabbasov 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
534d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
535272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
536d22e3d46SJaehoon Chung 	} else {
537272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
538d22e3d46SJaehoon Chung 	}
539272cc70bSAndy Fleming 
540272cc70bSAndy Fleming 	return 0;
541272cc70bSAndy Fleming }
542272cc70bSAndy Fleming 
543f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
544f866a46dSStephen Warren {
545f866a46dSStephen Warren 	switch (part_num) {
546f866a46dSStephen Warren 	case 0:
547f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
548f866a46dSStephen Warren 		break;
549f866a46dSStephen Warren 	case 1:
550f866a46dSStephen Warren 	case 2:
551f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
552f866a46dSStephen Warren 		break;
553f866a46dSStephen Warren 	case 3:
554f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
555f866a46dSStephen Warren 		break;
556f866a46dSStephen Warren 	case 4:
557f866a46dSStephen Warren 	case 5:
558f866a46dSStephen Warren 	case 6:
559f866a46dSStephen Warren 	case 7:
560f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
561f866a46dSStephen Warren 		break;
562f866a46dSStephen Warren 	default:
563f866a46dSStephen Warren 		return -1;
564f866a46dSStephen Warren 	}
565f866a46dSStephen Warren 
566c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
567f866a46dSStephen Warren 
568f866a46dSStephen Warren 	return 0;
569f866a46dSStephen Warren }
570f866a46dSStephen Warren 
571fdbb139fSSimon Glass static int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
572bc897b1dSLei Wen {
573f866a46dSStephen Warren 	int ret;
574bc897b1dSLei Wen 
575f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
576bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
577bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
578f866a46dSStephen Warren 
5796dc93e70SPeter Bigot 	/*
5806dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
5816dc93e70SPeter Bigot 	 * to return to representing the raw device.
5826dc93e70SPeter Bigot 	 */
583873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
5846dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
585fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
586873cc1d7SStephen Warren 	}
5876dc93e70SPeter Bigot 
5886dc93e70SPeter Bigot 	return ret;
589bc897b1dSLei Wen }
590bc897b1dSLei Wen 
59133fb211dSSimon Glass #ifdef CONFIG_BLK
59233fb211dSSimon Glass static int mmc_select_hwpart(struct udevice *bdev, int hwpart)
59333fb211dSSimon Glass {
59433fb211dSSimon Glass 	struct udevice *mmc_dev = dev_get_parent(bdev);
59533fb211dSSimon Glass 	struct mmc *mmc = mmc_get_mmc_dev(mmc_dev);
59633fb211dSSimon Glass 	struct blk_desc *desc = dev_get_uclass_platdata(bdev);
59733fb211dSSimon Glass 	int ret;
59833fb211dSSimon Glass 
59933fb211dSSimon Glass 	if (desc->hwpart == hwpart)
60033fb211dSSimon Glass 		return 0;
60133fb211dSSimon Glass 
60233fb211dSSimon Glass 	if (mmc->part_config == MMCPART_NOAVAILABLE)
60333fb211dSSimon Glass 		return -EMEDIUMTYPE;
60433fb211dSSimon Glass 
60533fb211dSSimon Glass 	ret = mmc_switch_part(mmc, hwpart);
60633fb211dSSimon Glass 	if (ret)
60733fb211dSSimon Glass 		return ret;
60833fb211dSSimon Glass 
60933fb211dSSimon Glass 	return 0;
61033fb211dSSimon Glass }
61133fb211dSSimon Glass #else
612e17d1143SSimon Glass static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart)
613e17d1143SSimon Glass {
614e17d1143SSimon Glass 	struct mmc *mmc = find_mmc_device(desc->devnum);
615e17d1143SSimon Glass 	int ret;
616e17d1143SSimon Glass 
617e17d1143SSimon Glass 	if (!mmc)
618e17d1143SSimon Glass 		return -ENODEV;
619e17d1143SSimon Glass 
620e17d1143SSimon Glass 	if (mmc->block_dev.hwpart == hwpart)
621e17d1143SSimon Glass 		return 0;
622e17d1143SSimon Glass 
623e17d1143SSimon Glass 	if (mmc->part_config == MMCPART_NOAVAILABLE)
624e17d1143SSimon Glass 		return -EMEDIUMTYPE;
625e17d1143SSimon Glass 
626fdbb139fSSimon Glass 	ret = mmc_switch_part(mmc, hwpart);
627e17d1143SSimon Glass 	if (ret)
628e17d1143SSimon Glass 		return ret;
629e17d1143SSimon Glass 
630e17d1143SSimon Glass 	return 0;
631e17d1143SSimon Glass }
63233fb211dSSimon Glass #endif
633ff3882acSSimon Glass 
634ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
635ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
636ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
637ac9da0e0SDiego Santa Cruz {
638ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
639ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
640ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
641ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
642ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
643ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
6448dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
645ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
646ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
647ac9da0e0SDiego Santa Cruz 
648ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
649ac9da0e0SDiego Santa Cruz 		return -EINVAL;
650ac9da0e0SDiego Santa Cruz 
651ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
652ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
653ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
654ac9da0e0SDiego Santa Cruz 	}
655ac9da0e0SDiego Santa Cruz 
656ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
657ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
658ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
659ac9da0e0SDiego Santa Cruz 	}
660ac9da0e0SDiego Santa Cruz 
661ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
662ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
663ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
664ac9da0e0SDiego Santa Cruz 	}
665ac9da0e0SDiego Santa Cruz 
666ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
667ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
668ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
669ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
670ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
671ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
672ac9da0e0SDiego Santa Cruz 			return -EINVAL;
673ac9da0e0SDiego Santa Cruz 		}
674ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
675ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
676ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
677ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
678ac9da0e0SDiego Santa Cruz 		} else {
679ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
680ac9da0e0SDiego Santa Cruz 		}
681ac9da0e0SDiego Santa Cruz 	} else {
682ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
683ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
684ac9da0e0SDiego Santa Cruz 	}
685ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
686ac9da0e0SDiego Santa Cruz 
687ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
688ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
689ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
690ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
691ac9da0e0SDiego Santa Cruz 			return -EINVAL;
692ac9da0e0SDiego Santa Cruz 		}
693ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
694ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
695ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
696ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
697ac9da0e0SDiego Santa Cruz 		}
698ac9da0e0SDiego Santa Cruz 	}
699ac9da0e0SDiego Santa Cruz 
700ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
701ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
702ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
703ac9da0e0SDiego Santa Cruz 	}
704ac9da0e0SDiego Santa Cruz 
705ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
706ac9da0e0SDiego Santa Cruz 	if (err)
707ac9da0e0SDiego Santa Cruz 		return err;
708ac9da0e0SDiego Santa Cruz 
709ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
710ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
711ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
712ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
713ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
714ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
715ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
716ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
717ac9da0e0SDiego Santa Cruz 	}
718ac9da0e0SDiego Santa Cruz 
7198dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
7208dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
7218dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
7228dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
7238dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
7248dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
7258dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
7268dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
7278dda5b0eSDiego Santa Cruz 		else
7288dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
7298dda5b0eSDiego Santa Cruz 	}
7308dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
7318dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
7328dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
7338dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
7348dda5b0eSDiego Santa Cruz 			else
7358dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
7368dda5b0eSDiego Santa Cruz 		}
7378dda5b0eSDiego Santa Cruz 	}
7388dda5b0eSDiego Santa Cruz 
7398dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
7408dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
7418dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
7428dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
7438dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
7448dda5b0eSDiego Santa Cruz 	}
7458dda5b0eSDiego Santa Cruz 
746ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
747ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
748ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
749ac9da0e0SDiego Santa Cruz 		return -EPERM;
750ac9da0e0SDiego Santa Cruz 	}
751ac9da0e0SDiego Santa Cruz 
752ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
753ac9da0e0SDiego Santa Cruz 		return 0;
754ac9da0e0SDiego Santa Cruz 
755ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
756ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
757ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
758ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
759ac9da0e0SDiego Santa Cruz 
760ac9da0e0SDiego Santa Cruz 		if (err)
761ac9da0e0SDiego Santa Cruz 			return err;
762ac9da0e0SDiego Santa Cruz 
763ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
764ac9da0e0SDiego Santa Cruz 
765ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
766ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
767ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
768ac9da0e0SDiego Santa Cruz 
769ac9da0e0SDiego Santa Cruz 	}
770ac9da0e0SDiego Santa Cruz 
771ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
772ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
773ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
774ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
775ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
776ac9da0e0SDiego Santa Cruz 		if (err)
777ac9da0e0SDiego Santa Cruz 			return err;
778ac9da0e0SDiego Santa Cruz 	}
779ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
780ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
781ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
782ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
783ac9da0e0SDiego Santa Cruz 		if (err)
784ac9da0e0SDiego Santa Cruz 			return err;
785ac9da0e0SDiego Santa Cruz 	}
786ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
787ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
788ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
789ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
790ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
791ac9da0e0SDiego Santa Cruz 			if (err)
792ac9da0e0SDiego Santa Cruz 				return err;
793ac9da0e0SDiego Santa Cruz 		}
794ac9da0e0SDiego Santa Cruz 	}
795ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
796ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
797ac9da0e0SDiego Santa Cruz 	if (err)
798ac9da0e0SDiego Santa Cruz 		return err;
799ac9da0e0SDiego Santa Cruz 
800ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
801ac9da0e0SDiego Santa Cruz 		return 0;
802ac9da0e0SDiego Santa Cruz 
8038dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
8048dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
8058dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
8068dda5b0eSDiego Santa Cruz 	 * partitioning. */
8078dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
8088dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
8098dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
8108dda5b0eSDiego Santa Cruz 		if (err)
8118dda5b0eSDiego Santa Cruz 			return err;
8128dda5b0eSDiego Santa Cruz 	}
8138dda5b0eSDiego Santa Cruz 
814ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
815ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
816ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
817ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
818ac9da0e0SDiego Santa Cruz 
819ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
820ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
821ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
822ac9da0e0SDiego Santa Cruz 	if (err)
823ac9da0e0SDiego Santa Cruz 		return err;
824ac9da0e0SDiego Santa Cruz 
825ac9da0e0SDiego Santa Cruz 	return 0;
826ac9da0e0SDiego Santa Cruz }
827ac9da0e0SDiego Santa Cruz 
82848972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
82948972d90SThierry Reding {
83048972d90SThierry Reding 	int cd;
83148972d90SThierry Reding 
83248972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
83348972d90SThierry Reding 
834d4e1da4eSPeter Korsgaard 	if (cd < 0) {
83593bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
83693bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
837d4e1da4eSPeter Korsgaard 		else
838d4e1da4eSPeter Korsgaard 			cd = 1;
839d4e1da4eSPeter Korsgaard 	}
84048972d90SThierry Reding 
84148972d90SThierry Reding 	return cd;
84248972d90SThierry Reding }
84348972d90SThierry Reding 
844fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
845272cc70bSAndy Fleming {
846272cc70bSAndy Fleming 	struct mmc_cmd cmd;
847272cc70bSAndy Fleming 	struct mmc_data data;
848272cc70bSAndy Fleming 
849272cc70bSAndy Fleming 	/* Switch the frequency */
850272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
851272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
852272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
853272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
854272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
855272cc70bSAndy Fleming 
856272cc70bSAndy Fleming 	data.dest = (char *)resp;
857272cc70bSAndy Fleming 	data.blocksize = 64;
858272cc70bSAndy Fleming 	data.blocks = 1;
859272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
860272cc70bSAndy Fleming 
861272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
862272cc70bSAndy Fleming }
863272cc70bSAndy Fleming 
864272cc70bSAndy Fleming 
865fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
866272cc70bSAndy Fleming {
867272cc70bSAndy Fleming 	int err;
868272cc70bSAndy Fleming 	struct mmc_cmd cmd;
869f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
870f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
871272cc70bSAndy Fleming 	struct mmc_data data;
872272cc70bSAndy Fleming 	int timeout;
873272cc70bSAndy Fleming 
874272cc70bSAndy Fleming 	mmc->card_caps = 0;
875272cc70bSAndy Fleming 
876d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
877d52ebf10SThomas Chou 		return 0;
878d52ebf10SThomas Chou 
879272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
880272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
881272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
882272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
883272cc70bSAndy Fleming 
884272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
885272cc70bSAndy Fleming 
886272cc70bSAndy Fleming 	if (err)
887272cc70bSAndy Fleming 		return err;
888272cc70bSAndy Fleming 
889272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
890272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
891272cc70bSAndy Fleming 	cmd.cmdarg = 0;
892272cc70bSAndy Fleming 
893272cc70bSAndy Fleming 	timeout = 3;
894272cc70bSAndy Fleming 
895272cc70bSAndy Fleming retry_scr:
896f781dd38SAnton staaf 	data.dest = (char *)scr;
897272cc70bSAndy Fleming 	data.blocksize = 8;
898272cc70bSAndy Fleming 	data.blocks = 1;
899272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
900272cc70bSAndy Fleming 
901272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
902272cc70bSAndy Fleming 
903272cc70bSAndy Fleming 	if (err) {
904272cc70bSAndy Fleming 		if (timeout--)
905272cc70bSAndy Fleming 			goto retry_scr;
906272cc70bSAndy Fleming 
907272cc70bSAndy Fleming 		return err;
908272cc70bSAndy Fleming 	}
909272cc70bSAndy Fleming 
9104e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
9114e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
912272cc70bSAndy Fleming 
913272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
914272cc70bSAndy Fleming 	case 0:
915272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
916272cc70bSAndy Fleming 		break;
917272cc70bSAndy Fleming 	case 1:
918272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
919272cc70bSAndy Fleming 		break;
920272cc70bSAndy Fleming 	case 2:
921272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
9221741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
9231741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
924272cc70bSAndy Fleming 		break;
925272cc70bSAndy Fleming 	default:
926272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
927272cc70bSAndy Fleming 		break;
928272cc70bSAndy Fleming 	}
929272cc70bSAndy Fleming 
930b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
931b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
932b44c7083SAlagu Sankar 
933272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
934272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
935272cc70bSAndy Fleming 		return 0;
936272cc70bSAndy Fleming 
937272cc70bSAndy Fleming 	timeout = 4;
938272cc70bSAndy Fleming 	while (timeout--) {
939272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
940f781dd38SAnton staaf 				(u8 *)switch_status);
941272cc70bSAndy Fleming 
942272cc70bSAndy Fleming 		if (err)
943272cc70bSAndy Fleming 			return err;
944272cc70bSAndy Fleming 
945272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
9464e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
947272cc70bSAndy Fleming 			break;
948272cc70bSAndy Fleming 	}
949272cc70bSAndy Fleming 
950272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
9514e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
952272cc70bSAndy Fleming 		return 0;
953272cc70bSAndy Fleming 
9542c3fbf4cSMacpaul Lin 	/*
9552c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
9562c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
9572c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
9582c3fbf4cSMacpaul Lin 	 * mode between the host.
9592c3fbf4cSMacpaul Lin 	 */
96093bfd616SPantelis Antoniou 	if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
96193bfd616SPantelis Antoniou 		(mmc->cfg->host_caps & MMC_MODE_HS)))
9622c3fbf4cSMacpaul Lin 		return 0;
9632c3fbf4cSMacpaul Lin 
964f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
965272cc70bSAndy Fleming 
966272cc70bSAndy Fleming 	if (err)
967272cc70bSAndy Fleming 		return err;
968272cc70bSAndy Fleming 
9694e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
970272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
971272cc70bSAndy Fleming 
972272cc70bSAndy Fleming 	return 0;
973272cc70bSAndy Fleming }
974272cc70bSAndy Fleming 
975272cc70bSAndy Fleming /* frequency bases */
976272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
9775f837c2cSMike Frysinger static const int fbase[] = {
978272cc70bSAndy Fleming 	10000,
979272cc70bSAndy Fleming 	100000,
980272cc70bSAndy Fleming 	1000000,
981272cc70bSAndy Fleming 	10000000,
982272cc70bSAndy Fleming };
983272cc70bSAndy Fleming 
984272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
985272cc70bSAndy Fleming  * to platforms without floating point.
986272cc70bSAndy Fleming  */
987*61fe076fSSimon Glass static const u8 multipliers[] = {
988272cc70bSAndy Fleming 	0,	/* reserved */
989272cc70bSAndy Fleming 	10,
990272cc70bSAndy Fleming 	12,
991272cc70bSAndy Fleming 	13,
992272cc70bSAndy Fleming 	15,
993272cc70bSAndy Fleming 	20,
994272cc70bSAndy Fleming 	25,
995272cc70bSAndy Fleming 	30,
996272cc70bSAndy Fleming 	35,
997272cc70bSAndy Fleming 	40,
998272cc70bSAndy Fleming 	45,
999272cc70bSAndy Fleming 	50,
1000272cc70bSAndy Fleming 	55,
1001272cc70bSAndy Fleming 	60,
1002272cc70bSAndy Fleming 	70,
1003272cc70bSAndy Fleming 	80,
1004272cc70bSAndy Fleming };
1005272cc70bSAndy Fleming 
1006fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
1007272cc70bSAndy Fleming {
100893bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
100993bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
1010272cc70bSAndy Fleming }
1011272cc70bSAndy Fleming 
1012272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
1013272cc70bSAndy Fleming {
101493bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
101593bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1016272cc70bSAndy Fleming 
101793bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
101893bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1019272cc70bSAndy Fleming 
1020272cc70bSAndy Fleming 	mmc->clock = clock;
1021272cc70bSAndy Fleming 
1022272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1023272cc70bSAndy Fleming }
1024272cc70bSAndy Fleming 
1025fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width)
1026272cc70bSAndy Fleming {
1027272cc70bSAndy Fleming 	mmc->bus_width = width;
1028272cc70bSAndy Fleming 
1029272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1030272cc70bSAndy Fleming }
1031272cc70bSAndy Fleming 
1032fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1033272cc70bSAndy Fleming {
1034f866a46dSStephen Warren 	int err, i;
1035272cc70bSAndy Fleming 	uint mult, freq;
1036639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
1037272cc70bSAndy Fleming 	struct mmc_cmd cmd;
10388bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
10398bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
10405d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
10410c453bb7SDiego Santa Cruz 	bool has_parts = false;
10428a0cf490SDiego Santa Cruz 	bool part_completed;
1043c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1044272cc70bSAndy Fleming 
1045d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1046d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1047d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1048d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1049d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1050d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1051d52ebf10SThomas Chou 
1052d52ebf10SThomas Chou 		if (err)
1053d52ebf10SThomas Chou 			return err;
1054d52ebf10SThomas Chou 	}
1055d52ebf10SThomas Chou #endif
1056d52ebf10SThomas Chou 
1057272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1058d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1059d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1060272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1061272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1062272cc70bSAndy Fleming 
1063272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1064272cc70bSAndy Fleming 
1065272cc70bSAndy Fleming 	if (err)
1066272cc70bSAndy Fleming 		return err;
1067272cc70bSAndy Fleming 
1068272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1069272cc70bSAndy Fleming 
1070272cc70bSAndy Fleming 	/*
1071272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1072272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1073272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1074272cc70bSAndy Fleming 	 */
1075d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1076272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1077272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1078272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1079272cc70bSAndy Fleming 
1080272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1081272cc70bSAndy Fleming 
1082272cc70bSAndy Fleming 		if (err)
1083272cc70bSAndy Fleming 			return err;
1084272cc70bSAndy Fleming 
1085272cc70bSAndy Fleming 		if (IS_SD(mmc))
1086998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1087d52ebf10SThomas Chou 	}
1088272cc70bSAndy Fleming 
1089272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1090272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1091272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1092272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1093272cc70bSAndy Fleming 
1094272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1095272cc70bSAndy Fleming 
10965d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
10975d4fc8d9SRaffaele Recalcati 	mmc_send_status(mmc, timeout);
10985d4fc8d9SRaffaele Recalcati 
1099272cc70bSAndy Fleming 	if (err)
1100272cc70bSAndy Fleming 		return err;
1101272cc70bSAndy Fleming 
1102998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1103998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1104998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1105998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1106272cc70bSAndy Fleming 
1107272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
11080b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1109272cc70bSAndy Fleming 
1110272cc70bSAndy Fleming 		switch (version) {
1111272cc70bSAndy Fleming 		case 0:
1112272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1113272cc70bSAndy Fleming 			break;
1114272cc70bSAndy Fleming 		case 1:
1115272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1116272cc70bSAndy Fleming 			break;
1117272cc70bSAndy Fleming 		case 2:
1118272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1119272cc70bSAndy Fleming 			break;
1120272cc70bSAndy Fleming 		case 3:
1121272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1122272cc70bSAndy Fleming 			break;
1123272cc70bSAndy Fleming 		case 4:
1124272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1125272cc70bSAndy Fleming 			break;
1126272cc70bSAndy Fleming 		default:
1127272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1128272cc70bSAndy Fleming 			break;
1129272cc70bSAndy Fleming 		}
1130272cc70bSAndy Fleming 	}
1131272cc70bSAndy Fleming 
1132272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
11330b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
11340b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1135272cc70bSAndy Fleming 
1136272cc70bSAndy Fleming 	mmc->tran_speed = freq * mult;
1137272cc70bSAndy Fleming 
1138ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1139998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1140272cc70bSAndy Fleming 
1141272cc70bSAndy Fleming 	if (IS_SD(mmc))
1142272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1143272cc70bSAndy Fleming 	else
1144998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1145272cc70bSAndy Fleming 
1146272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1147272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1148272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1149272cc70bSAndy Fleming 		cmult = 8;
1150272cc70bSAndy Fleming 	} else {
1151272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1152272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1153272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1154272cc70bSAndy Fleming 	}
1155272cc70bSAndy Fleming 
1156f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1157f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1158f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1159f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1160f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1161f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1162272cc70bSAndy Fleming 
11638bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
11648bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1165272cc70bSAndy Fleming 
11668bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
11678bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1168272cc70bSAndy Fleming 
1169ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1170ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1171ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1172ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1173ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1174ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1175ab71188cSMarkus Niebel 	}
1176ab71188cSMarkus Niebel 
1177272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1178d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1179272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1180fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1181272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1182272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1183272cc70bSAndy Fleming 
1184272cc70bSAndy Fleming 		if (err)
1185272cc70bSAndy Fleming 			return err;
1186d52ebf10SThomas Chou 	}
1187272cc70bSAndy Fleming 
1188e6f99a56SLei Wen 	/*
1189e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1190e6f99a56SLei Wen 	 */
1191e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1192bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1193d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
1194d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
1195d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
11969cf199ebSDiego Santa Cruz 		if (err)
11979cf199ebSDiego Santa Cruz 			return err;
11989cf199ebSDiego Santa Cruz 		if (ext_csd[EXT_CSD_REV] >= 2) {
1199639b7827SYoshihiro Shimoda 			/*
1200639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
1201639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
1202639b7827SYoshihiro Shimoda 			 * than 2GB
1203639b7827SYoshihiro Shimoda 			 */
12040560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
12050560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
12060560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
12070560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
12088bfa195eSSimon Glass 			capacity *= MMC_MAX_BLOCK_LEN;
1209b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
1210f866a46dSStephen Warren 				mmc->capacity_user = capacity;
1211d23e2c09SSukumar Ghorai 		}
1212bc897b1dSLei Wen 
121364f4a619SJaehoon Chung 		switch (ext_csd[EXT_CSD_REV]) {
121464f4a619SJaehoon Chung 		case 1:
121564f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_1;
121664f4a619SJaehoon Chung 			break;
121764f4a619SJaehoon Chung 		case 2:
121864f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_2;
121964f4a619SJaehoon Chung 			break;
122064f4a619SJaehoon Chung 		case 3:
122164f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_3;
122264f4a619SJaehoon Chung 			break;
122364f4a619SJaehoon Chung 		case 5:
122464f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_41;
122564f4a619SJaehoon Chung 			break;
122664f4a619SJaehoon Chung 		case 6:
122764f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_5;
122864f4a619SJaehoon Chung 			break;
1229edab723bSMarkus Niebel 		case 7:
1230edab723bSMarkus Niebel 			mmc->version = MMC_VERSION_5_0;
1231edab723bSMarkus Niebel 			break;
123264f4a619SJaehoon Chung 		}
123364f4a619SJaehoon Chung 
12348a0cf490SDiego Santa Cruz 		/* The partition data may be non-zero but it is only
12358a0cf490SDiego Santa Cruz 		 * effective if PARTITION_SETTING_COMPLETED is set in
12368a0cf490SDiego Santa Cruz 		 * EXT_CSD, so ignore any data if this bit is not set,
12378a0cf490SDiego Santa Cruz 		 * except for enabling the high-capacity group size
12388a0cf490SDiego Santa Cruz 		 * definition (see below). */
12398a0cf490SDiego Santa Cruz 		part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
12408a0cf490SDiego Santa Cruz 				    EXT_CSD_PARTITION_SETTING_COMPLETED);
12418a0cf490SDiego Santa Cruz 
12420c453bb7SDiego Santa Cruz 		/* store the partition info of emmc */
12430c453bb7SDiego Santa Cruz 		mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
12440c453bb7SDiego Santa Cruz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
12450c453bb7SDiego Santa Cruz 		    ext_csd[EXT_CSD_BOOT_MULT])
12460c453bb7SDiego Santa Cruz 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
12478a0cf490SDiego Santa Cruz 		if (part_completed &&
12488a0cf490SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
12490c453bb7SDiego Santa Cruz 			mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
12500c453bb7SDiego Santa Cruz 
12510c453bb7SDiego Santa Cruz 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
12520c453bb7SDiego Santa Cruz 
12530c453bb7SDiego Santa Cruz 		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
12540c453bb7SDiego Santa Cruz 
12550c453bb7SDiego Santa Cruz 		for (i = 0; i < 4; i++) {
12560c453bb7SDiego Santa Cruz 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
12578a0cf490SDiego Santa Cruz 			uint mult = (ext_csd[idx + 2] << 16) +
12580c453bb7SDiego Santa Cruz 				(ext_csd[idx + 1] << 8) + ext_csd[idx];
12598a0cf490SDiego Santa Cruz 			if (mult)
12608a0cf490SDiego Santa Cruz 				has_parts = true;
12618a0cf490SDiego Santa Cruz 			if (!part_completed)
12628a0cf490SDiego Santa Cruz 				continue;
12638a0cf490SDiego Santa Cruz 			mmc->capacity_gp[i] = mult;
12640c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *=
12650c453bb7SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
12660c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1267f8e89d67SDiego Santa Cruz 			mmc->capacity_gp[i] <<= 19;
12680c453bb7SDiego Santa Cruz 		}
12690c453bb7SDiego Santa Cruz 
12708a0cf490SDiego Santa Cruz 		if (part_completed) {
1271a7f852b6SDiego Santa Cruz 			mmc->enh_user_size =
1272a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
1273a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
1274a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_SIZE_MULT];
1275a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1276a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1277a7f852b6SDiego Santa Cruz 			mmc->enh_user_size <<= 19;
1278a7f852b6SDiego Santa Cruz 			mmc->enh_user_start =
1279a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
1280a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
1281a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
1282a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_START_ADDR];
1283a7f852b6SDiego Santa Cruz 			if (mmc->high_capacity)
1284a7f852b6SDiego Santa Cruz 				mmc->enh_user_start <<= 9;
12858a0cf490SDiego Santa Cruz 		}
1286a7f852b6SDiego Santa Cruz 
1287e6f99a56SLei Wen 		/*
12881937e5aaSOliver Metz 		 * Host needs to enable ERASE_GRP_DEF bit if device is
12891937e5aaSOliver Metz 		 * partitioned. This bit will be lost every time after a reset
12901937e5aaSOliver Metz 		 * or power off. This will affect erase size.
1291e6f99a56SLei Wen 		 */
12928a0cf490SDiego Santa Cruz 		if (part_completed)
12930c453bb7SDiego Santa Cruz 			has_parts = true;
12941937e5aaSOliver Metz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
12950c453bb7SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
12960c453bb7SDiego Santa Cruz 			has_parts = true;
12970c453bb7SDiego Santa Cruz 		if (has_parts) {
12981937e5aaSOliver Metz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
12991937e5aaSOliver Metz 				EXT_CSD_ERASE_GROUP_DEF, 1);
13001937e5aaSOliver Metz 
13011937e5aaSOliver Metz 			if (err)
13021937e5aaSOliver Metz 				return err;
1303021a8055SHannes Petermaier 			else
1304021a8055SHannes Petermaier 				ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1305037dc0abSDiego Santa Cruz 		}
13061937e5aaSOliver Metz 
1307037dc0abSDiego Santa Cruz 		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
13081937e5aaSOliver Metz 			/* Read out group size from ext_csd */
13090560db18SLei Wen 			mmc->erase_grp_size =
1310a4ff9f83SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1311d7b29129SMarkus Niebel 			/*
1312d7b29129SMarkus Niebel 			 * if high capacity and partition setting completed
1313d7b29129SMarkus Niebel 			 * SEC_COUNT is valid even if it is smaller than 2 GiB
1314d7b29129SMarkus Niebel 			 * JEDEC Standard JESD84-B45, 6.2.4
1315d7b29129SMarkus Niebel 			 */
13168a0cf490SDiego Santa Cruz 			if (mmc->high_capacity && part_completed) {
1317d7b29129SMarkus Niebel 				capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1318d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1319d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1320d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1321d7b29129SMarkus Niebel 				capacity *= MMC_MAX_BLOCK_LEN;
1322d7b29129SMarkus Niebel 				mmc->capacity_user = capacity;
1323d7b29129SMarkus Niebel 			}
13248bfa195eSSimon Glass 		} else {
13251937e5aaSOliver Metz 			/* Calculate the group size from the csd value. */
1326e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
1327e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1328e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1329e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
1330e6f99a56SLei Wen 				* (erase_gmul + 1);
1331e6f99a56SLei Wen 		}
1332037dc0abSDiego Santa Cruz 
1333037dc0abSDiego Santa Cruz 		mmc->hc_wp_grp_size = 1024
1334037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1335037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
13369e41a00bSDiego Santa Cruz 
13379e41a00bSDiego Santa Cruz 		mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1338f866a46dSStephen Warren 	}
1339f866a46dSStephen Warren 
1340c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
1341f866a46dSStephen Warren 	if (err)
1342f866a46dSStephen Warren 		return err;
1343d23e2c09SSukumar Ghorai 
1344272cc70bSAndy Fleming 	if (IS_SD(mmc))
1345272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1346272cc70bSAndy Fleming 	else
1347272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1348272cc70bSAndy Fleming 
1349272cc70bSAndy Fleming 	if (err)
1350272cc70bSAndy Fleming 		return err;
1351272cc70bSAndy Fleming 
1352272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
135393bfd616SPantelis Antoniou 	mmc->card_caps &= mmc->cfg->host_caps;
1354272cc70bSAndy Fleming 
1355272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1356272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1357272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1358272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1359272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1360272cc70bSAndy Fleming 
1361272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1362272cc70bSAndy Fleming 			if (err)
1363272cc70bSAndy Fleming 				return err;
1364272cc70bSAndy Fleming 
1365272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1366272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1367272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1368272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1369272cc70bSAndy Fleming 			if (err)
1370272cc70bSAndy Fleming 				return err;
1371272cc70bSAndy Fleming 
1372272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1373272cc70bSAndy Fleming 		}
1374272cc70bSAndy Fleming 
1375272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
1376ad5fd922SJaehoon Chung 			mmc->tran_speed = 50000000;
1377272cc70bSAndy Fleming 		else
1378ad5fd922SJaehoon Chung 			mmc->tran_speed = 25000000;
1379fc5b32fbSAndrew Gabbasov 	} else if (mmc->version >= MMC_VERSION_4) {
1380fc5b32fbSAndrew Gabbasov 		/* Only version 4 of MMC supports wider bus widths */
13817798f6dbSAndy Fleming 		int idx;
13827798f6dbSAndy Fleming 
13837798f6dbSAndy Fleming 		/* An array of possible bus widths in order of preference */
13847798f6dbSAndy Fleming 		static unsigned ext_csd_bits[] = {
1385d22e3d46SJaehoon Chung 			EXT_CSD_DDR_BUS_WIDTH_8,
1386d22e3d46SJaehoon Chung 			EXT_CSD_DDR_BUS_WIDTH_4,
13877798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_8,
13887798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_4,
13897798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_1,
13907798f6dbSAndy Fleming 		};
13917798f6dbSAndy Fleming 
13927798f6dbSAndy Fleming 		/* An array to map CSD bus widths to host cap bits */
13937798f6dbSAndy Fleming 		static unsigned ext_to_hostcaps[] = {
1394786e8f81SAndrew Gabbasov 			[EXT_CSD_DDR_BUS_WIDTH_4] =
1395786e8f81SAndrew Gabbasov 				MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
1396786e8f81SAndrew Gabbasov 			[EXT_CSD_DDR_BUS_WIDTH_8] =
1397786e8f81SAndrew Gabbasov 				MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
13987798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
13997798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
14007798f6dbSAndy Fleming 		};
14017798f6dbSAndy Fleming 
14027798f6dbSAndy Fleming 		/* An array to map chosen bus width to an integer */
14037798f6dbSAndy Fleming 		static unsigned widths[] = {
1404d22e3d46SJaehoon Chung 			8, 4, 8, 4, 1,
14057798f6dbSAndy Fleming 		};
14067798f6dbSAndy Fleming 
14077798f6dbSAndy Fleming 		for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
14087798f6dbSAndy Fleming 			unsigned int extw = ext_csd_bits[idx];
1409786e8f81SAndrew Gabbasov 			unsigned int caps = ext_to_hostcaps[extw];
14107798f6dbSAndy Fleming 
14117798f6dbSAndy Fleming 			/*
1412bf477073SAndrew Gabbasov 			 * If the bus width is still not changed,
1413bf477073SAndrew Gabbasov 			 * don't try to set the default again.
1414bf477073SAndrew Gabbasov 			 * Otherwise, recover from switch attempts
1415bf477073SAndrew Gabbasov 			 * by switching to 1-bit bus width.
1416bf477073SAndrew Gabbasov 			 */
1417bf477073SAndrew Gabbasov 			if (extw == EXT_CSD_BUS_WIDTH_1 &&
1418bf477073SAndrew Gabbasov 					mmc->bus_width == 1) {
1419bf477073SAndrew Gabbasov 				err = 0;
1420bf477073SAndrew Gabbasov 				break;
1421bf477073SAndrew Gabbasov 			}
1422bf477073SAndrew Gabbasov 
1423bf477073SAndrew Gabbasov 			/*
1424786e8f81SAndrew Gabbasov 			 * Check to make sure the card and controller support
1425786e8f81SAndrew Gabbasov 			 * these capabilities
14267798f6dbSAndy Fleming 			 */
1427786e8f81SAndrew Gabbasov 			if ((mmc->card_caps & caps) != caps)
14287798f6dbSAndy Fleming 				continue;
14297798f6dbSAndy Fleming 
1430272cc70bSAndy Fleming 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
14317798f6dbSAndy Fleming 					EXT_CSD_BUS_WIDTH, extw);
1432272cc70bSAndy Fleming 
1433272cc70bSAndy Fleming 			if (err)
14344137894eSLei Wen 				continue;
1435272cc70bSAndy Fleming 
1436786e8f81SAndrew Gabbasov 			mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
14377798f6dbSAndy Fleming 			mmc_set_bus_width(mmc, widths[idx]);
1438272cc70bSAndy Fleming 
14394137894eSLei Wen 			err = mmc_send_ext_csd(mmc, test_csd);
1440272cc70bSAndy Fleming 
1441786e8f81SAndrew Gabbasov 			if (err)
1442786e8f81SAndrew Gabbasov 				continue;
1443786e8f81SAndrew Gabbasov 
1444786e8f81SAndrew Gabbasov 			/* Only compare read only fields */
1445786e8f81SAndrew Gabbasov 			if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
1446786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
1447786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
1448786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
1449786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_REV]
1450786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_REV] &&
1451786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1452786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
1453786e8f81SAndrew Gabbasov 			    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
1454786e8f81SAndrew Gabbasov 				   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
14554137894eSLei Wen 				break;
1456786e8f81SAndrew Gabbasov 			else
1457786e8f81SAndrew Gabbasov 				err = SWITCH_ERR;
14584137894eSLei Wen 		}
1459786e8f81SAndrew Gabbasov 
1460786e8f81SAndrew Gabbasov 		if (err)
1461786e8f81SAndrew Gabbasov 			return err;
1462272cc70bSAndy Fleming 
1463272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS) {
1464272cc70bSAndy Fleming 			if (mmc->card_caps & MMC_MODE_HS_52MHz)
1465ad5fd922SJaehoon Chung 				mmc->tran_speed = 52000000;
1466272cc70bSAndy Fleming 			else
1467ad5fd922SJaehoon Chung 				mmc->tran_speed = 26000000;
1468272cc70bSAndy Fleming 		}
1469ad5fd922SJaehoon Chung 	}
1470ad5fd922SJaehoon Chung 
1471ad5fd922SJaehoon Chung 	mmc_set_clock(mmc, mmc->tran_speed);
1472272cc70bSAndy Fleming 
14735af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
14745af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
14755af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
14765af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
14775af8f45cSAndrew Gabbasov 	}
14785af8f45cSAndrew Gabbasov 
1479272cc70bSAndy Fleming 	/* fill in device description */
1480c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1481c40fdca6SSimon Glass 	bdesc->lun = 0;
1482c40fdca6SSimon Glass 	bdesc->hwpart = 0;
1483c40fdca6SSimon Glass 	bdesc->type = 0;
1484c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
1485c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
1486c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1487fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1488fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1489fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1490c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
1491babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1492babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1493c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
14940b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1495babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1496babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1497c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1498babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
149956196826SPaul Burton #else
1500c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
1501c40fdca6SSimon Glass 	bdesc->product[0] = 0;
1502c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
150356196826SPaul Burton #endif
1504122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1505c40fdca6SSimon Glass 	part_init(bdesc);
1506122efd43SMikhail Kshevetskiy #endif
1507272cc70bSAndy Fleming 
1508272cc70bSAndy Fleming 	return 0;
1509272cc70bSAndy Fleming }
1510272cc70bSAndy Fleming 
1511fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1512272cc70bSAndy Fleming {
1513272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1514272cc70bSAndy Fleming 	int err;
1515272cc70bSAndy Fleming 
1516272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1517272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
151893bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1519272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1520272cc70bSAndy Fleming 
1521272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1522272cc70bSAndy Fleming 
1523272cc70bSAndy Fleming 	if (err)
1524272cc70bSAndy Fleming 		return err;
1525272cc70bSAndy Fleming 
1526998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1527272cc70bSAndy Fleming 		return UNUSABLE_ERR;
1528272cc70bSAndy Fleming 	else
1529272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1530272cc70bSAndy Fleming 
1531272cc70bSAndy Fleming 	return 0;
1532272cc70bSAndy Fleming }
1533272cc70bSAndy Fleming 
1534ad27dd5eSSimon Glass #ifdef CONFIG_BLK
1535ad27dd5eSSimon Glass int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg)
1536ad27dd5eSSimon Glass {
1537ad27dd5eSSimon Glass 	struct blk_desc *bdesc;
1538ad27dd5eSSimon Glass 	struct udevice *bdev;
1539ad27dd5eSSimon Glass 	int ret;
1540ad27dd5eSSimon Glass 
1541ad27dd5eSSimon Glass 	ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC, -1, 512,
1542ad27dd5eSSimon Glass 				 0, &bdev);
1543ad27dd5eSSimon Glass 	if (ret) {
1544ad27dd5eSSimon Glass 		debug("Cannot create block device\n");
1545ad27dd5eSSimon Glass 		return ret;
1546ad27dd5eSSimon Glass 	}
1547ad27dd5eSSimon Glass 	bdesc = dev_get_uclass_platdata(bdev);
1548ad27dd5eSSimon Glass 	mmc->cfg = cfg;
1549ad27dd5eSSimon Glass 	mmc->priv = dev;
1550ad27dd5eSSimon Glass 
1551ad27dd5eSSimon Glass 	/* the following chunk was from mmc_register() */
1552ad27dd5eSSimon Glass 
1553ad27dd5eSSimon Glass 	/* Setup dsr related values */
1554ad27dd5eSSimon Glass 	mmc->dsr_imp = 0;
1555ad27dd5eSSimon Glass 	mmc->dsr = 0xffffffff;
1556ad27dd5eSSimon Glass 	/* Setup the universal parts of the block interface just once */
1557ad27dd5eSSimon Glass 	bdesc->removable = 1;
1558ad27dd5eSSimon Glass 
1559ad27dd5eSSimon Glass 	/* setup initial part type */
1560ad27dd5eSSimon Glass 	bdesc->part_type = mmc->cfg->part_type;
1561ad27dd5eSSimon Glass 	mmc->dev = dev;
1562ad27dd5eSSimon Glass 
1563ad27dd5eSSimon Glass 	return 0;
1564ad27dd5eSSimon Glass }
1565ad27dd5eSSimon Glass 
1566ad27dd5eSSimon Glass int mmc_unbind(struct udevice *dev)
1567ad27dd5eSSimon Glass {
1568ad27dd5eSSimon Glass 	struct udevice *bdev;
1569ad27dd5eSSimon Glass 
1570ad27dd5eSSimon Glass 	device_find_first_child(dev, &bdev);
1571ad27dd5eSSimon Glass 	if (bdev) {
1572ad27dd5eSSimon Glass 		device_remove(bdev);
1573ad27dd5eSSimon Glass 		device_unbind(bdev);
1574ad27dd5eSSimon Glass 	}
1575ad27dd5eSSimon Glass 
1576ad27dd5eSSimon Glass 	return 0;
1577ad27dd5eSSimon Glass }
1578ad27dd5eSSimon Glass 
1579ad27dd5eSSimon Glass #else
158093bfd616SPantelis Antoniou struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
158193bfd616SPantelis Antoniou {
1582c40fdca6SSimon Glass 	struct blk_desc *bdesc;
158393bfd616SPantelis Antoniou 	struct mmc *mmc;
158493bfd616SPantelis Antoniou 
158593bfd616SPantelis Antoniou 	/* quick validation */
158693bfd616SPantelis Antoniou 	if (cfg == NULL || cfg->ops == NULL || cfg->ops->send_cmd == NULL ||
158793bfd616SPantelis Antoniou 			cfg->f_min == 0 || cfg->f_max == 0 || cfg->b_max == 0)
158893bfd616SPantelis Antoniou 		return NULL;
158993bfd616SPantelis Antoniou 
159093bfd616SPantelis Antoniou 	mmc = calloc(1, sizeof(*mmc));
159193bfd616SPantelis Antoniou 	if (mmc == NULL)
159293bfd616SPantelis Antoniou 		return NULL;
159393bfd616SPantelis Antoniou 
159493bfd616SPantelis Antoniou 	mmc->cfg = cfg;
159593bfd616SPantelis Antoniou 	mmc->priv = priv;
159693bfd616SPantelis Antoniou 
159793bfd616SPantelis Antoniou 	/* the following chunk was mmc_register() */
159893bfd616SPantelis Antoniou 
1599ab71188cSMarkus Niebel 	/* Setup dsr related values */
1600ab71188cSMarkus Niebel 	mmc->dsr_imp = 0;
1601ab71188cSMarkus Niebel 	mmc->dsr = 0xffffffff;
1602272cc70bSAndy Fleming 	/* Setup the universal parts of the block interface just once */
1603c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1604c40fdca6SSimon Glass 	bdesc->if_type = IF_TYPE_MMC;
1605c40fdca6SSimon Glass 	bdesc->removable = 1;
1606c40fdca6SSimon Glass 	bdesc->devnum = mmc_get_next_devnum();
1607c40fdca6SSimon Glass 	bdesc->block_read = mmc_bread;
1608c40fdca6SSimon Glass 	bdesc->block_write = mmc_bwrite;
1609c40fdca6SSimon Glass 	bdesc->block_erase = mmc_berase;
161093bfd616SPantelis Antoniou 
161193bfd616SPantelis Antoniou 	/* setup initial part type */
1612c40fdca6SSimon Glass 	bdesc->part_type = mmc->cfg->part_type;
1613c40fdca6SSimon Glass 	mmc_list_add(mmc);
1614272cc70bSAndy Fleming 
161593bfd616SPantelis Antoniou 	return mmc;
161693bfd616SPantelis Antoniou }
161793bfd616SPantelis Antoniou 
161893bfd616SPantelis Antoniou void mmc_destroy(struct mmc *mmc)
161993bfd616SPantelis Antoniou {
162093bfd616SPantelis Antoniou 	/* only freeing memory for now */
162193bfd616SPantelis Antoniou 	free(mmc);
1622272cc70bSAndy Fleming }
1623ad27dd5eSSimon Glass #endif
1624272cc70bSAndy Fleming 
162533fb211dSSimon Glass #ifndef CONFIG_BLK
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 }
164133fb211dSSimon Glass #endif
1642663acabdSSimon Glass 
164395de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
164495de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
164595de9ab2SPaul Kocialkowski {
164695de9ab2SPaul Kocialkowski }
164795de9ab2SPaul Kocialkowski 
1648e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1649272cc70bSAndy Fleming {
1650afd5932bSMacpaul Lin 	int err;
1651272cc70bSAndy Fleming 
1652ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
165393bfd616SPantelis Antoniou 	if (mmc_getcd(mmc) == 0 || mmc->cfg->ops->init == NULL) {
165448972d90SThierry Reding 		mmc->has_init = 0;
165556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
165648972d90SThierry Reding 		printf("MMC: no card present\n");
165756196826SPaul Burton #endif
165848972d90SThierry Reding 		return NO_CARD_ERR;
165948972d90SThierry Reding 	}
166048972d90SThierry Reding 
1661bc897b1dSLei Wen 	if (mmc->has_init)
1662bc897b1dSLei Wen 		return 0;
1663bc897b1dSLei Wen 
16645a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
16655a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
16665a8dbdc6SYangbo Lu #endif
166795de9ab2SPaul Kocialkowski 	board_mmc_power_init();
166895de9ab2SPaul Kocialkowski 
1669ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
167093bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
1671272cc70bSAndy Fleming 
1672272cc70bSAndy Fleming 	if (err)
1673272cc70bSAndy Fleming 		return err;
1674272cc70bSAndy Fleming 
1675786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
1676b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1677b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1678b86b85e2SIlya Yanok 
1679272cc70bSAndy Fleming 	/* Reset the Card */
1680272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1681272cc70bSAndy Fleming 
1682272cc70bSAndy Fleming 	if (err)
1683272cc70bSAndy Fleming 		return err;
1684272cc70bSAndy Fleming 
1685bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1686c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
1687bc897b1dSLei Wen 
1688272cc70bSAndy Fleming 	/* Test for SD version 2 */
1689272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1690272cc70bSAndy Fleming 
1691272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1692272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1693272cc70bSAndy Fleming 
1694272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1695272cc70bSAndy Fleming 	if (err == TIMEOUT) {
1696272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1697272cc70bSAndy Fleming 
1698bd47c135SAndrew Gabbasov 		if (err) {
169956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1700272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
170156196826SPaul Burton #endif
1702272cc70bSAndy Fleming 			return UNUSABLE_ERR;
1703272cc70bSAndy Fleming 		}
1704272cc70bSAndy Fleming 	}
1705272cc70bSAndy Fleming 
1706bd47c135SAndrew Gabbasov 	if (!err)
1707e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
1708e9550449SChe-Liang Chiou 
1709e9550449SChe-Liang Chiou 	return err;
1710e9550449SChe-Liang Chiou }
1711e9550449SChe-Liang Chiou 
1712e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
1713e9550449SChe-Liang Chiou {
1714e9550449SChe-Liang Chiou 	int err = 0;
1715e9550449SChe-Liang Chiou 
1716bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
1717e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
1718e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
1719e9550449SChe-Liang Chiou 
1720e9550449SChe-Liang Chiou 	if (!err)
1721bc897b1dSLei Wen 		err = mmc_startup(mmc);
1722bc897b1dSLei Wen 	if (err)
1723bc897b1dSLei Wen 		mmc->has_init = 0;
1724bc897b1dSLei Wen 	else
1725bc897b1dSLei Wen 		mmc->has_init = 1;
1726e9550449SChe-Liang Chiou 	return err;
1727e9550449SChe-Liang Chiou }
1728e9550449SChe-Liang Chiou 
1729e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
1730e9550449SChe-Liang Chiou {
1731bd47c135SAndrew Gabbasov 	int err = 0;
1732d803fea5SMateusz Zalega 	unsigned start;
173333fb211dSSimon Glass #ifdef CONFIG_DM_MMC
173433fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
1735e9550449SChe-Liang Chiou 
173633fb211dSSimon Glass 	upriv->mmc = mmc;
173733fb211dSSimon Glass #endif
1738e9550449SChe-Liang Chiou 	if (mmc->has_init)
1739e9550449SChe-Liang Chiou 		return 0;
1740d803fea5SMateusz Zalega 
1741d803fea5SMateusz Zalega 	start = get_timer(0);
1742d803fea5SMateusz Zalega 
1743e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
1744e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
1745e9550449SChe-Liang Chiou 
1746bd47c135SAndrew Gabbasov 	if (!err)
1747e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
1748e9550449SChe-Liang Chiou 	debug("%s: %d, time %lu\n", __func__, err, get_timer(start));
1749bc897b1dSLei Wen 	return err;
1750272cc70bSAndy Fleming }
1751272cc70bSAndy Fleming 
1752ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
1753ab71188cSMarkus Niebel {
1754ab71188cSMarkus Niebel 	mmc->dsr = val;
1755ab71188cSMarkus Niebel 	return 0;
1756ab71188cSMarkus Niebel }
1757ab71188cSMarkus Niebel 
1758cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
1759cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
1760272cc70bSAndy Fleming {
1761272cc70bSAndy Fleming 	return -1;
1762272cc70bSAndy Fleming }
1763272cc70bSAndy Fleming 
1764cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
1765cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
1766cee9ab7cSJeroen Hofstee {
1767cee9ab7cSJeroen Hofstee 	return -1;
1768cee9ab7cSJeroen Hofstee }
1769272cc70bSAndy Fleming 
1770e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
1771e9550449SChe-Liang Chiou {
1772e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
1773e9550449SChe-Liang Chiou }
1774e9550449SChe-Liang Chiou 
17758e3332e2SSjoerd Simons #if defined(CONFIG_DM_MMC) && defined(CONFIG_SPL_BUILD)
17768e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
17778e3332e2SSjoerd Simons {
17788e3332e2SSjoerd Simons 	return 0;
17798e3332e2SSjoerd Simons }
17808e3332e2SSjoerd Simons #elif defined(CONFIG_DM_MMC)
17818e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
17828e3332e2SSjoerd Simons {
17834a1db6d8SSimon Glass 	int ret, i;
17848e3332e2SSjoerd Simons 	struct uclass *uc;
17854a1db6d8SSimon Glass 	struct udevice *dev;
17868e3332e2SSjoerd Simons 
17878e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
17888e3332e2SSjoerd Simons 	if (ret)
17898e3332e2SSjoerd Simons 		return ret;
17908e3332e2SSjoerd Simons 
17914a1db6d8SSimon Glass 	/*
17924a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
17934a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
17944a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
17954a1db6d8SSimon Glass 	 */
17964a1db6d8SSimon Glass 	for (i = 0; ; i++) {
17974a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
17984a1db6d8SSimon Glass 		if (ret == -ENODEV)
17994a1db6d8SSimon Glass 			break;
18004a1db6d8SSimon Glass 	}
18014a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
18024a1db6d8SSimon Glass 		ret = device_probe(dev);
18038e3332e2SSjoerd Simons 		if (ret)
18044a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
18058e3332e2SSjoerd Simons 	}
18068e3332e2SSjoerd Simons 
18078e3332e2SSjoerd Simons 	return 0;
18088e3332e2SSjoerd Simons }
18098e3332e2SSjoerd Simons #else
18108e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
18118e3332e2SSjoerd Simons {
18128e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
18138e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
18148e3332e2SSjoerd Simons 
18158e3332e2SSjoerd Simons 	return 0;
18168e3332e2SSjoerd Simons }
18178e3332e2SSjoerd Simons #endif
1818e9550449SChe-Liang Chiou 
1819272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1820272cc70bSAndy Fleming {
18211b26bab1SDaniel Kochmański 	static int initialized = 0;
18228e3332e2SSjoerd Simons 	int ret;
18231b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
18241b26bab1SDaniel Kochmański 		return 0;
18251b26bab1SDaniel Kochmański 	initialized = 1;
18261b26bab1SDaniel Kochmański 
1827c40fdca6SSimon Glass #ifndef CONFIG_BLK
1828c40fdca6SSimon Glass 	mmc_list_init();
1829c40fdca6SSimon Glass #endif
18308e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
18318e3332e2SSjoerd Simons 	if (ret)
18328e3332e2SSjoerd Simons 		return ret;
1833272cc70bSAndy Fleming 
1834bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
1835272cc70bSAndy Fleming 	print_mmc_devices(',');
1836bb0dc108SYing Zhang #endif
1837272cc70bSAndy Fleming 
1838c40fdca6SSimon Glass 	mmc_do_preinit();
1839272cc70bSAndy Fleming 	return 0;
1840272cc70bSAndy Fleming }
18413690d6d6SAmar 
18423690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT
18433690d6d6SAmar /*
18443690d6d6SAmar  * This function changes the size of boot partition and the size of rpmb
18453690d6d6SAmar  * partition present on EMMC devices.
18463690d6d6SAmar  *
18473690d6d6SAmar  * Input Parameters:
18483690d6d6SAmar  * struct *mmc: pointer for the mmc device strcuture
18493690d6d6SAmar  * bootsize: size of boot partition
18503690d6d6SAmar  * rpmbsize: size of rpmb partition
18513690d6d6SAmar  *
18523690d6d6SAmar  * Returns 0 on success.
18533690d6d6SAmar  */
18543690d6d6SAmar 
18553690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
18563690d6d6SAmar 				unsigned long rpmbsize)
18573690d6d6SAmar {
18583690d6d6SAmar 	int err;
18593690d6d6SAmar 	struct mmc_cmd cmd;
18603690d6d6SAmar 
18613690d6d6SAmar 	/* Only use this command for raw EMMC moviNAND. Enter backdoor mode */
18623690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18633690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18643690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG1;
18653690d6d6SAmar 
18663690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18673690d6d6SAmar 	if (err) {
18683690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error1 = %d\n", err);
18693690d6d6SAmar 		return err;
18703690d6d6SAmar 	}
18713690d6d6SAmar 
18723690d6d6SAmar 	/* Boot partition changing mode */
18733690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18743690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18753690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG2;
18763690d6d6SAmar 
18773690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18783690d6d6SAmar 	if (err) {
18793690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error2 = %d\n", err);
18803690d6d6SAmar 		return err;
18813690d6d6SAmar 	}
18823690d6d6SAmar 	/* boot partition size is multiple of 128KB */
18833690d6d6SAmar 	bootsize = (bootsize * 1024) / 128;
18843690d6d6SAmar 
18853690d6d6SAmar 	/* Arg: boot partition size */
18863690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18873690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18883690d6d6SAmar 	cmd.cmdarg = bootsize;
18893690d6d6SAmar 
18903690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18913690d6d6SAmar 	if (err) {
18923690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error3 = %d\n", err);
18933690d6d6SAmar 		return err;
18943690d6d6SAmar 	}
18953690d6d6SAmar 	/* RPMB partition size is multiple of 128KB */
18963690d6d6SAmar 	rpmbsize = (rpmbsize * 1024) / 128;
18973690d6d6SAmar 	/* Arg: RPMB partition size */
18983690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18993690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
19003690d6d6SAmar 	cmd.cmdarg = rpmbsize;
19013690d6d6SAmar 
19023690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
19033690d6d6SAmar 	if (err) {
19043690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error4 = %d\n", err);
19053690d6d6SAmar 		return err;
19063690d6d6SAmar 	}
19073690d6d6SAmar 	return 0;
19083690d6d6SAmar }
19093690d6d6SAmar 
19103690d6d6SAmar /*
19115a99b9deSTom Rini  * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH
19125a99b9deSTom Rini  * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH
19135a99b9deSTom Rini  * and BOOT_MODE.
19145a99b9deSTom Rini  *
19155a99b9deSTom Rini  * Returns 0 on success.
19165a99b9deSTom Rini  */
19175a99b9deSTom Rini int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode)
19185a99b9deSTom Rini {
19195a99b9deSTom Rini 	int err;
19205a99b9deSTom Rini 
19215a99b9deSTom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH,
19225a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) |
19235a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) |
19245a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width));
19255a99b9deSTom Rini 
19265a99b9deSTom Rini 	if (err)
19275a99b9deSTom Rini 		return err;
19285a99b9deSTom Rini 	return 0;
19295a99b9deSTom Rini }
19305a99b9deSTom Rini 
19315a99b9deSTom Rini /*
1932792970b0STom Rini  * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG)
1933792970b0STom Rini  * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and
1934792970b0STom Rini  * PARTITION_ACCESS.
1935792970b0STom Rini  *
1936792970b0STom Rini  * Returns 0 on success.
1937792970b0STom Rini  */
1938792970b0STom Rini int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access)
1939792970b0STom Rini {
1940792970b0STom Rini 	int err;
1941792970b0STom Rini 
1942792970b0STom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
1943792970b0STom Rini 			 EXT_CSD_BOOT_ACK(ack) |
1944792970b0STom Rini 			 EXT_CSD_BOOT_PART_NUM(part_num) |
1945792970b0STom Rini 			 EXT_CSD_PARTITION_ACCESS(access));
1946792970b0STom Rini 
1947792970b0STom Rini 	if (err)
1948792970b0STom Rini 		return err;
1949792970b0STom Rini 	return 0;
1950792970b0STom Rini }
195133ace362STom Rini 
195233ace362STom Rini /*
195333ace362STom Rini  * Modify EXT_CSD[162] which is RST_n_FUNCTION based on the given value
195433ace362STom Rini  * for enable.  Note that this is a write-once field for non-zero values.
195533ace362STom Rini  *
195633ace362STom Rini  * Returns 0 on success.
195733ace362STom Rini  */
195833ace362STom Rini int mmc_set_rst_n_function(struct mmc *mmc, u8 enable)
195933ace362STom Rini {
196033ace362STom Rini 	return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_RST_N_FUNCTION,
196133ace362STom Rini 			  enable);
196233ace362STom Rini }
19633690d6d6SAmar #endif
1964663acabdSSimon Glass 
196533fb211dSSimon Glass #ifdef CONFIG_BLK
196633fb211dSSimon Glass static const struct blk_ops mmc_blk_ops = {
196733fb211dSSimon Glass 	.read	= mmc_bread,
196833fb211dSSimon Glass 	.write	= mmc_bwrite,
196933fb211dSSimon Glass 	.select_hwpart	= mmc_select_hwpart,
197033fb211dSSimon Glass };
197133fb211dSSimon Glass 
197233fb211dSSimon Glass U_BOOT_DRIVER(mmc_blk) = {
197333fb211dSSimon Glass 	.name		= "mmc_blk",
197433fb211dSSimon Glass 	.id		= UCLASS_BLK,
197533fb211dSSimon Glass 	.ops		= &mmc_blk_ops,
197633fb211dSSimon Glass };
197733fb211dSSimon Glass #else
1978663acabdSSimon Glass U_BOOT_LEGACY_BLK(mmc) = {
1979663acabdSSimon Glass 	.if_typename	= "mmc",
1980663acabdSSimon Glass 	.if_type	= IF_TYPE_MMC,
1981663acabdSSimon Glass 	.max_devs	= -1,
19823c457f4dSSimon Glass 	.get_dev	= mmc_get_dev,
1983e17d1143SSimon Glass 	.select_hwpart	= mmc_select_hwpartp,
1984663acabdSSimon Glass };
198533fb211dSSimon Glass #endif
1986