xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision a5e27b41)
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 	}
1585d4fc8d9SRaffaele Recalcati 
1595d4fc8d9SRaffaele Recalcati 	return 0;
1605d4fc8d9SRaffaele Recalcati }
1615d4fc8d9SRaffaele Recalcati 
162da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
163272cc70bSAndy Fleming {
164272cc70bSAndy Fleming 	struct mmc_cmd cmd;
165272cc70bSAndy Fleming 
166786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
167d22e3d46SJaehoon Chung 		return 0;
168d22e3d46SJaehoon Chung 
169272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
170272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
171272cc70bSAndy Fleming 	cmd.cmdarg = len;
172272cc70bSAndy Fleming 
173272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
174272cc70bSAndy Fleming }
175272cc70bSAndy Fleming 
176ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
177fdbb873eSKim Phillips 			   lbaint_t blkcnt)
178272cc70bSAndy Fleming {
179272cc70bSAndy Fleming 	struct mmc_cmd cmd;
180272cc70bSAndy Fleming 	struct mmc_data data;
181272cc70bSAndy Fleming 
1824a1a06bcSAlagu Sankar 	if (blkcnt > 1)
1834a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
1844a1a06bcSAlagu Sankar 	else
185272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
186272cc70bSAndy Fleming 
187272cc70bSAndy Fleming 	if (mmc->high_capacity)
1884a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
189272cc70bSAndy Fleming 	else
1904a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
191272cc70bSAndy Fleming 
192272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
193272cc70bSAndy Fleming 
194272cc70bSAndy Fleming 	data.dest = dst;
1954a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
196272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
197272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
198272cc70bSAndy Fleming 
1994a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
2004a1a06bcSAlagu Sankar 		return 0;
2014a1a06bcSAlagu Sankar 
2024a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
2034a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
2044a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
2054a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
2064a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
20756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2084a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
20956196826SPaul Burton #endif
2104a1a06bcSAlagu Sankar 			return 0;
2114a1a06bcSAlagu Sankar 		}
212272cc70bSAndy Fleming 	}
213272cc70bSAndy Fleming 
2144a1a06bcSAlagu Sankar 	return blkcnt;
215272cc70bSAndy Fleming }
216272cc70bSAndy Fleming 
21733fb211dSSimon Glass #ifdef CONFIG_BLK
21833fb211dSSimon Glass static ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
21933fb211dSSimon Glass 		       void *dst)
22033fb211dSSimon Glass #else
2214101f687SSimon Glass static ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start,
2227c4213f6SStephen Warren 		       lbaint_t blkcnt, void *dst)
22333fb211dSSimon Glass #endif
224272cc70bSAndy Fleming {
22533fb211dSSimon Glass #ifdef CONFIG_BLK
22633fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
22733fb211dSSimon Glass #endif
228bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
229873cc1d7SStephen Warren 	int err;
2304a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
231272cc70bSAndy Fleming 
2324a1a06bcSAlagu Sankar 	if (blkcnt == 0)
2334a1a06bcSAlagu Sankar 		return 0;
2344a1a06bcSAlagu Sankar 
2354a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
236272cc70bSAndy Fleming 	if (!mmc)
237272cc70bSAndy Fleming 		return 0;
238272cc70bSAndy Fleming 
23969f45cd5SSimon Glass 	err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
240873cc1d7SStephen Warren 	if (err < 0)
241873cc1d7SStephen Warren 		return 0;
242873cc1d7SStephen Warren 
243c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
24456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
245ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
246c40fdca6SSimon Glass 			start + blkcnt, block_dev->lba);
24756196826SPaul Burton #endif
248d2bf29e3SLei Wen 		return 0;
249d2bf29e3SLei Wen 	}
250272cc70bSAndy Fleming 
25111692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
25211692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
253272cc70bSAndy Fleming 		return 0;
25411692991SSimon Glass 	}
255272cc70bSAndy Fleming 
2564a1a06bcSAlagu Sankar 	do {
25793bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
25893bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
25911692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
26011692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
2614a1a06bcSAlagu Sankar 			return 0;
26211692991SSimon Glass 		}
2634a1a06bcSAlagu Sankar 		blocks_todo -= cur;
2644a1a06bcSAlagu Sankar 		start += cur;
2654a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
2664a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
267272cc70bSAndy Fleming 
268272cc70bSAndy Fleming 	return blkcnt;
269272cc70bSAndy Fleming }
270272cc70bSAndy Fleming 
271fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
272272cc70bSAndy Fleming {
273272cc70bSAndy Fleming 	struct mmc_cmd cmd;
274272cc70bSAndy Fleming 	int err;
275272cc70bSAndy Fleming 
276272cc70bSAndy Fleming 	udelay(1000);
277272cc70bSAndy Fleming 
278272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
279272cc70bSAndy Fleming 	cmd.cmdarg = 0;
280272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
281272cc70bSAndy Fleming 
282272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
283272cc70bSAndy Fleming 
284272cc70bSAndy Fleming 	if (err)
285272cc70bSAndy Fleming 		return err;
286272cc70bSAndy Fleming 
287272cc70bSAndy Fleming 	udelay(2000);
288272cc70bSAndy Fleming 
289272cc70bSAndy Fleming 	return 0;
290272cc70bSAndy Fleming }
291272cc70bSAndy Fleming 
292fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
293272cc70bSAndy Fleming {
294272cc70bSAndy Fleming 	int timeout = 1000;
295272cc70bSAndy Fleming 	int err;
296272cc70bSAndy Fleming 	struct mmc_cmd cmd;
297272cc70bSAndy Fleming 
2981677eef4SAndrew Gabbasov 	while (1) {
299272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
300272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
301272cc70bSAndy Fleming 		cmd.cmdarg = 0;
302272cc70bSAndy Fleming 
303272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
304272cc70bSAndy Fleming 
305272cc70bSAndy Fleming 		if (err)
306272cc70bSAndy Fleming 			return err;
307272cc70bSAndy Fleming 
308272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
309272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
310250de12bSStefano Babic 
311250de12bSStefano Babic 		/*
312250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
313250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
314250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
315250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
316250de12bSStefano Babic 		 * specified.
317250de12bSStefano Babic 		 */
318d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
31993bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
320272cc70bSAndy Fleming 
321272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
322272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
323272cc70bSAndy Fleming 
324272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
325272cc70bSAndy Fleming 
326272cc70bSAndy Fleming 		if (err)
327272cc70bSAndy Fleming 			return err;
328272cc70bSAndy Fleming 
3291677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
3301677eef4SAndrew Gabbasov 			break;
331272cc70bSAndy Fleming 
3321677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
333272cc70bSAndy Fleming 			return UNUSABLE_ERR;
334272cc70bSAndy Fleming 
3351677eef4SAndrew Gabbasov 		udelay(1000);
3361677eef4SAndrew Gabbasov 	}
3371677eef4SAndrew Gabbasov 
338272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
339272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
340272cc70bSAndy Fleming 
341d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
342d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
343d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
344d52ebf10SThomas Chou 		cmd.cmdarg = 0;
345d52ebf10SThomas Chou 
346d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
347d52ebf10SThomas Chou 
348d52ebf10SThomas Chou 		if (err)
349d52ebf10SThomas Chou 			return err;
350d52ebf10SThomas Chou 	}
351d52ebf10SThomas Chou 
352998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
353272cc70bSAndy Fleming 
354272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
355272cc70bSAndy Fleming 	mmc->rca = 0;
356272cc70bSAndy Fleming 
357272cc70bSAndy Fleming 	return 0;
358272cc70bSAndy Fleming }
359272cc70bSAndy Fleming 
3605289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
361272cc70bSAndy Fleming {
3625289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
363272cc70bSAndy Fleming 	int err;
364272cc70bSAndy Fleming 
3655289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
3665289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
3675289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
3685a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
3695a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
37093bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
371a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
372a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
373e9550449SChe-Liang Chiou 
3745289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
375e9550449SChe-Liang Chiou 	if (err)
376e9550449SChe-Liang Chiou 		return err;
3775289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
378e9550449SChe-Liang Chiou 	return 0;
379e9550449SChe-Liang Chiou }
380e9550449SChe-Liang Chiou 
381750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
382e9550449SChe-Liang Chiou {
383e9550449SChe-Liang Chiou 	int err, i;
384e9550449SChe-Liang Chiou 
385272cc70bSAndy Fleming 	/* Some cards seem to need this */
386272cc70bSAndy Fleming 	mmc_go_idle(mmc);
387272cc70bSAndy Fleming 
38831cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
389e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
3905289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
39131cacbabSRaffaele Recalcati 		if (err)
39231cacbabSRaffaele Recalcati 			return err;
39331cacbabSRaffaele Recalcati 
394e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
395a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
396bd47c135SAndrew Gabbasov 			break;
397e9550449SChe-Liang Chiou 	}
398bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
399bd47c135SAndrew Gabbasov 	return 0;
400e9550449SChe-Liang Chiou }
40131cacbabSRaffaele Recalcati 
402750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
403e9550449SChe-Liang Chiou {
404e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
405e9550449SChe-Liang Chiou 	int timeout = 1000;
406e9550449SChe-Liang Chiou 	uint start;
407e9550449SChe-Liang Chiou 	int err;
408e9550449SChe-Liang Chiou 
409e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
410cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
411e9550449SChe-Liang Chiou 		start = get_timer(0);
4121677eef4SAndrew Gabbasov 		while (1) {
4135289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
414272cc70bSAndy Fleming 			if (err)
415272cc70bSAndy Fleming 				return err;
4161677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
4171677eef4SAndrew Gabbasov 				break;
418e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
419272cc70bSAndy Fleming 				return UNUSABLE_ERR;
420e9550449SChe-Liang Chiou 			udelay(100);
4211677eef4SAndrew Gabbasov 		}
422cc17c01fSAndrew Gabbasov 	}
423272cc70bSAndy Fleming 
424d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
425d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
426d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
427d52ebf10SThomas Chou 		cmd.cmdarg = 0;
428d52ebf10SThomas Chou 
429d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
430d52ebf10SThomas Chou 
431d52ebf10SThomas Chou 		if (err)
432d52ebf10SThomas Chou 			return err;
433a626c8d4SAndrew Gabbasov 
434a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
435d52ebf10SThomas Chou 	}
436d52ebf10SThomas Chou 
437272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
438272cc70bSAndy Fleming 
439272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
440def816a2SStephen Warren 	mmc->rca = 1;
441272cc70bSAndy Fleming 
442272cc70bSAndy Fleming 	return 0;
443272cc70bSAndy Fleming }
444272cc70bSAndy Fleming 
445272cc70bSAndy Fleming 
446fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
447272cc70bSAndy Fleming {
448272cc70bSAndy Fleming 	struct mmc_cmd cmd;
449272cc70bSAndy Fleming 	struct mmc_data data;
450272cc70bSAndy Fleming 	int err;
451272cc70bSAndy Fleming 
452272cc70bSAndy Fleming 	/* Get the Card Status Register */
453272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
454272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
455272cc70bSAndy Fleming 	cmd.cmdarg = 0;
456272cc70bSAndy Fleming 
457cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
458272cc70bSAndy Fleming 	data.blocks = 1;
4598bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
460272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
461272cc70bSAndy Fleming 
462272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
463272cc70bSAndy Fleming 
464272cc70bSAndy Fleming 	return err;
465272cc70bSAndy Fleming }
466272cc70bSAndy Fleming 
467272cc70bSAndy Fleming 
468fdbb873eSKim Phillips static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
469272cc70bSAndy Fleming {
470272cc70bSAndy Fleming 	struct mmc_cmd cmd;
4715d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
4725d4fc8d9SRaffaele Recalcati 	int ret;
473272cc70bSAndy Fleming 
474272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
475272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
476272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
477272cc70bSAndy Fleming 				 (index << 16) |
478272cc70bSAndy Fleming 				 (value << 8);
479272cc70bSAndy Fleming 
4805d4fc8d9SRaffaele Recalcati 	ret = mmc_send_cmd(mmc, &cmd, NULL);
4815d4fc8d9SRaffaele Recalcati 
4825d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
48393ad0d18SJan Kloetzke 	if (!ret)
48493ad0d18SJan Kloetzke 		ret = mmc_send_status(mmc, timeout);
4855d4fc8d9SRaffaele Recalcati 
4865d4fc8d9SRaffaele Recalcati 	return ret;
4875d4fc8d9SRaffaele Recalcati 
488272cc70bSAndy Fleming }
489272cc70bSAndy Fleming 
490fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
491272cc70bSAndy Fleming {
4928bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
493272cc70bSAndy Fleming 	char cardtype;
494272cc70bSAndy Fleming 	int err;
495272cc70bSAndy Fleming 
496fc5b32fbSAndrew Gabbasov 	mmc->card_caps = 0;
497272cc70bSAndy Fleming 
498d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
499d52ebf10SThomas Chou 		return 0;
500d52ebf10SThomas Chou 
501272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
502272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
503272cc70bSAndy Fleming 		return 0;
504272cc70bSAndy Fleming 
505fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
506fc5b32fbSAndrew Gabbasov 
507272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
508272cc70bSAndy Fleming 
509272cc70bSAndy Fleming 	if (err)
510272cc70bSAndy Fleming 		return err;
511272cc70bSAndy Fleming 
5120560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
513272cc70bSAndy Fleming 
514272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
515272cc70bSAndy Fleming 
516272cc70bSAndy Fleming 	if (err)
517*a5e27b41SHeiko Schocher 		return err;
518272cc70bSAndy Fleming 
519272cc70bSAndy Fleming 	/* Now check to see that it worked */
520272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
521272cc70bSAndy Fleming 
522272cc70bSAndy Fleming 	if (err)
523272cc70bSAndy Fleming 		return err;
524272cc70bSAndy Fleming 
525272cc70bSAndy Fleming 	/* No high-speed support */
5260560db18SLei Wen 	if (!ext_csd[EXT_CSD_HS_TIMING])
527272cc70bSAndy Fleming 		return 0;
528272cc70bSAndy Fleming 
529272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
530d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
531201d5ac4SAndrew Gabbasov 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
532d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
533272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
534d22e3d46SJaehoon Chung 	} else {
535272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
536d22e3d46SJaehoon Chung 	}
537272cc70bSAndy Fleming 
538272cc70bSAndy Fleming 	return 0;
539272cc70bSAndy Fleming }
540272cc70bSAndy Fleming 
541f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
542f866a46dSStephen Warren {
543f866a46dSStephen Warren 	switch (part_num) {
544f866a46dSStephen Warren 	case 0:
545f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
546f866a46dSStephen Warren 		break;
547f866a46dSStephen Warren 	case 1:
548f866a46dSStephen Warren 	case 2:
549f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
550f866a46dSStephen Warren 		break;
551f866a46dSStephen Warren 	case 3:
552f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
553f866a46dSStephen Warren 		break;
554f866a46dSStephen Warren 	case 4:
555f866a46dSStephen Warren 	case 5:
556f866a46dSStephen Warren 	case 6:
557f866a46dSStephen Warren 	case 7:
558f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
559f866a46dSStephen Warren 		break;
560f866a46dSStephen Warren 	default:
561f866a46dSStephen Warren 		return -1;
562f866a46dSStephen Warren 	}
563f866a46dSStephen Warren 
564c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
565f866a46dSStephen Warren 
566f866a46dSStephen Warren 	return 0;
567f866a46dSStephen Warren }
568f866a46dSStephen Warren 
569fdbb139fSSimon Glass static int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
570bc897b1dSLei Wen {
571f866a46dSStephen Warren 	int ret;
572bc897b1dSLei Wen 
573f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
574bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
575bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
576f866a46dSStephen Warren 
5776dc93e70SPeter Bigot 	/*
5786dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
5796dc93e70SPeter Bigot 	 * to return to representing the raw device.
5806dc93e70SPeter Bigot 	 */
581873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
5826dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
583fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
584873cc1d7SStephen Warren 	}
5856dc93e70SPeter Bigot 
5866dc93e70SPeter Bigot 	return ret;
587bc897b1dSLei Wen }
588bc897b1dSLei Wen 
58933fb211dSSimon Glass #ifdef CONFIG_BLK
59033fb211dSSimon Glass static int mmc_select_hwpart(struct udevice *bdev, int hwpart)
59133fb211dSSimon Glass {
59233fb211dSSimon Glass 	struct udevice *mmc_dev = dev_get_parent(bdev);
59333fb211dSSimon Glass 	struct mmc *mmc = mmc_get_mmc_dev(mmc_dev);
59433fb211dSSimon Glass 	struct blk_desc *desc = dev_get_uclass_platdata(bdev);
59533fb211dSSimon Glass 	int ret;
59633fb211dSSimon Glass 
59733fb211dSSimon Glass 	if (desc->hwpart == hwpart)
59833fb211dSSimon Glass 		return 0;
59933fb211dSSimon Glass 
60033fb211dSSimon Glass 	if (mmc->part_config == MMCPART_NOAVAILABLE)
60133fb211dSSimon Glass 		return -EMEDIUMTYPE;
60233fb211dSSimon Glass 
60333fb211dSSimon Glass 	ret = mmc_switch_part(mmc, hwpart);
60433fb211dSSimon Glass 	if (ret)
60533fb211dSSimon Glass 		return ret;
60633fb211dSSimon Glass 
60733fb211dSSimon Glass 	return 0;
60833fb211dSSimon Glass }
60933fb211dSSimon Glass #else
610e17d1143SSimon Glass static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart)
611e17d1143SSimon Glass {
612e17d1143SSimon Glass 	struct mmc *mmc = find_mmc_device(desc->devnum);
613e17d1143SSimon Glass 	int ret;
614e17d1143SSimon Glass 
615e17d1143SSimon Glass 	if (!mmc)
616e17d1143SSimon Glass 		return -ENODEV;
617e17d1143SSimon Glass 
618e17d1143SSimon Glass 	if (mmc->block_dev.hwpart == hwpart)
619e17d1143SSimon Glass 		return 0;
620e17d1143SSimon Glass 
621e17d1143SSimon Glass 	if (mmc->part_config == MMCPART_NOAVAILABLE)
622e17d1143SSimon Glass 		return -EMEDIUMTYPE;
623e17d1143SSimon Glass 
624fdbb139fSSimon Glass 	ret = mmc_switch_part(mmc, hwpart);
625e17d1143SSimon Glass 	if (ret)
626e17d1143SSimon Glass 		return ret;
627e17d1143SSimon Glass 
628e17d1143SSimon Glass 	return 0;
629e17d1143SSimon Glass }
63033fb211dSSimon Glass #endif
631ff3882acSSimon Glass 
632ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
633ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
634ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
635ac9da0e0SDiego Santa Cruz {
636ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
637ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
638ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
639ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
640ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
641ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
6428dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
643ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
644ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
645ac9da0e0SDiego Santa Cruz 
646ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
647ac9da0e0SDiego Santa Cruz 		return -EINVAL;
648ac9da0e0SDiego Santa Cruz 
649ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
650ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
651ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
652ac9da0e0SDiego Santa Cruz 	}
653ac9da0e0SDiego Santa Cruz 
654ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
655ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
656ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
657ac9da0e0SDiego Santa Cruz 	}
658ac9da0e0SDiego Santa Cruz 
659ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
660ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
661ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
662ac9da0e0SDiego Santa Cruz 	}
663ac9da0e0SDiego Santa Cruz 
664ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
665ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
666ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
667ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
668ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
669ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
670ac9da0e0SDiego Santa Cruz 			return -EINVAL;
671ac9da0e0SDiego Santa Cruz 		}
672ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
673ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
674ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
675ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
676ac9da0e0SDiego Santa Cruz 		} else {
677ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
678ac9da0e0SDiego Santa Cruz 		}
679ac9da0e0SDiego Santa Cruz 	} else {
680ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
681ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
682ac9da0e0SDiego Santa Cruz 	}
683ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
684ac9da0e0SDiego Santa Cruz 
685ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
686ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
687ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
688ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
689ac9da0e0SDiego Santa Cruz 			return -EINVAL;
690ac9da0e0SDiego Santa Cruz 		}
691ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
692ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
693ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
694ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
695ac9da0e0SDiego Santa Cruz 		}
696ac9da0e0SDiego Santa Cruz 	}
697ac9da0e0SDiego Santa Cruz 
698ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
699ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
700ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
701ac9da0e0SDiego Santa Cruz 	}
702ac9da0e0SDiego Santa Cruz 
703ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
704ac9da0e0SDiego Santa Cruz 	if (err)
705ac9da0e0SDiego Santa Cruz 		return err;
706ac9da0e0SDiego Santa Cruz 
707ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
708ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
709ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
710ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
711ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
712ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
713ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
714ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
715ac9da0e0SDiego Santa Cruz 	}
716ac9da0e0SDiego Santa Cruz 
7178dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
7188dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
7198dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
7208dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
7218dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
7228dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
7238dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
7248dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
7258dda5b0eSDiego Santa Cruz 		else
7268dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
7278dda5b0eSDiego Santa Cruz 	}
7288dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
7298dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
7308dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
7318dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
7328dda5b0eSDiego Santa Cruz 			else
7338dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
7348dda5b0eSDiego Santa Cruz 		}
7358dda5b0eSDiego Santa Cruz 	}
7368dda5b0eSDiego Santa Cruz 
7378dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
7388dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
7398dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
7408dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
7418dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
7428dda5b0eSDiego Santa Cruz 	}
7438dda5b0eSDiego Santa Cruz 
744ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
745ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
746ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
747ac9da0e0SDiego Santa Cruz 		return -EPERM;
748ac9da0e0SDiego Santa Cruz 	}
749ac9da0e0SDiego Santa Cruz 
750ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
751ac9da0e0SDiego Santa Cruz 		return 0;
752ac9da0e0SDiego Santa Cruz 
753ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
754ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
755ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
756ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
757ac9da0e0SDiego Santa Cruz 
758ac9da0e0SDiego Santa Cruz 		if (err)
759ac9da0e0SDiego Santa Cruz 			return err;
760ac9da0e0SDiego Santa Cruz 
761ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
762ac9da0e0SDiego Santa Cruz 
763ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
764ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
765ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
766ac9da0e0SDiego Santa Cruz 
767ac9da0e0SDiego Santa Cruz 	}
768ac9da0e0SDiego Santa Cruz 
769ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
770ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
771ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
772ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
773ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
774ac9da0e0SDiego Santa Cruz 		if (err)
775ac9da0e0SDiego Santa Cruz 			return err;
776ac9da0e0SDiego Santa Cruz 	}
777ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
778ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
779ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
780ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
781ac9da0e0SDiego Santa Cruz 		if (err)
782ac9da0e0SDiego Santa Cruz 			return err;
783ac9da0e0SDiego Santa Cruz 	}
784ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
785ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
786ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
787ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
788ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
789ac9da0e0SDiego Santa Cruz 			if (err)
790ac9da0e0SDiego Santa Cruz 				return err;
791ac9da0e0SDiego Santa Cruz 		}
792ac9da0e0SDiego Santa Cruz 	}
793ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
794ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
795ac9da0e0SDiego Santa Cruz 	if (err)
796ac9da0e0SDiego Santa Cruz 		return err;
797ac9da0e0SDiego Santa Cruz 
798ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
799ac9da0e0SDiego Santa Cruz 		return 0;
800ac9da0e0SDiego Santa Cruz 
8018dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
8028dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
8038dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
8048dda5b0eSDiego Santa Cruz 	 * partitioning. */
8058dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
8068dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
8078dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
8088dda5b0eSDiego Santa Cruz 		if (err)
8098dda5b0eSDiego Santa Cruz 			return err;
8108dda5b0eSDiego Santa Cruz 	}
8118dda5b0eSDiego Santa Cruz 
812ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
813ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
814ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
815ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
816ac9da0e0SDiego Santa Cruz 
817ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
818ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
819ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
820ac9da0e0SDiego Santa Cruz 	if (err)
821ac9da0e0SDiego Santa Cruz 		return err;
822ac9da0e0SDiego Santa Cruz 
823ac9da0e0SDiego Santa Cruz 	return 0;
824ac9da0e0SDiego Santa Cruz }
825ac9da0e0SDiego Santa Cruz 
82648972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
82748972d90SThierry Reding {
82848972d90SThierry Reding 	int cd;
82948972d90SThierry Reding 
83048972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
83148972d90SThierry Reding 
832d4e1da4eSPeter Korsgaard 	if (cd < 0) {
83393bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
83493bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
835d4e1da4eSPeter Korsgaard 		else
836d4e1da4eSPeter Korsgaard 			cd = 1;
837d4e1da4eSPeter Korsgaard 	}
83848972d90SThierry Reding 
83948972d90SThierry Reding 	return cd;
84048972d90SThierry Reding }
84148972d90SThierry Reding 
842fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
843272cc70bSAndy Fleming {
844272cc70bSAndy Fleming 	struct mmc_cmd cmd;
845272cc70bSAndy Fleming 	struct mmc_data data;
846272cc70bSAndy Fleming 
847272cc70bSAndy Fleming 	/* Switch the frequency */
848272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
849272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
850272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
851272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
852272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
853272cc70bSAndy Fleming 
854272cc70bSAndy Fleming 	data.dest = (char *)resp;
855272cc70bSAndy Fleming 	data.blocksize = 64;
856272cc70bSAndy Fleming 	data.blocks = 1;
857272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
858272cc70bSAndy Fleming 
859272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
860272cc70bSAndy Fleming }
861272cc70bSAndy Fleming 
862272cc70bSAndy Fleming 
863fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
864272cc70bSAndy Fleming {
865272cc70bSAndy Fleming 	int err;
866272cc70bSAndy Fleming 	struct mmc_cmd cmd;
867f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
868f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
869272cc70bSAndy Fleming 	struct mmc_data data;
870272cc70bSAndy Fleming 	int timeout;
871272cc70bSAndy Fleming 
872272cc70bSAndy Fleming 	mmc->card_caps = 0;
873272cc70bSAndy Fleming 
874d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
875d52ebf10SThomas Chou 		return 0;
876d52ebf10SThomas Chou 
877272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
878272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
879272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
880272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
881272cc70bSAndy Fleming 
882272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
883272cc70bSAndy Fleming 
884272cc70bSAndy Fleming 	if (err)
885272cc70bSAndy Fleming 		return err;
886272cc70bSAndy Fleming 
887272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
888272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
889272cc70bSAndy Fleming 	cmd.cmdarg = 0;
890272cc70bSAndy Fleming 
891272cc70bSAndy Fleming 	timeout = 3;
892272cc70bSAndy Fleming 
893272cc70bSAndy Fleming retry_scr:
894f781dd38SAnton staaf 	data.dest = (char *)scr;
895272cc70bSAndy Fleming 	data.blocksize = 8;
896272cc70bSAndy Fleming 	data.blocks = 1;
897272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
898272cc70bSAndy Fleming 
899272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
900272cc70bSAndy Fleming 
901272cc70bSAndy Fleming 	if (err) {
902272cc70bSAndy Fleming 		if (timeout--)
903272cc70bSAndy Fleming 			goto retry_scr;
904272cc70bSAndy Fleming 
905272cc70bSAndy Fleming 		return err;
906272cc70bSAndy Fleming 	}
907272cc70bSAndy Fleming 
9084e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
9094e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
910272cc70bSAndy Fleming 
911272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
912272cc70bSAndy Fleming 	case 0:
913272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
914272cc70bSAndy Fleming 		break;
915272cc70bSAndy Fleming 	case 1:
916272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
917272cc70bSAndy Fleming 		break;
918272cc70bSAndy Fleming 	case 2:
919272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
9201741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
9211741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
922272cc70bSAndy Fleming 		break;
923272cc70bSAndy Fleming 	default:
924272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
925272cc70bSAndy Fleming 		break;
926272cc70bSAndy Fleming 	}
927272cc70bSAndy Fleming 
928b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
929b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
930b44c7083SAlagu Sankar 
931272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
932272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
933272cc70bSAndy Fleming 		return 0;
934272cc70bSAndy Fleming 
935272cc70bSAndy Fleming 	timeout = 4;
936272cc70bSAndy Fleming 	while (timeout--) {
937272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
938f781dd38SAnton staaf 				(u8 *)switch_status);
939272cc70bSAndy Fleming 
940272cc70bSAndy Fleming 		if (err)
941272cc70bSAndy Fleming 			return err;
942272cc70bSAndy Fleming 
943272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
9444e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
945272cc70bSAndy Fleming 			break;
946272cc70bSAndy Fleming 	}
947272cc70bSAndy Fleming 
948272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
9494e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
950272cc70bSAndy Fleming 		return 0;
951272cc70bSAndy Fleming 
9522c3fbf4cSMacpaul Lin 	/*
9532c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
9542c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
9552c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
9562c3fbf4cSMacpaul Lin 	 * mode between the host.
9572c3fbf4cSMacpaul Lin 	 */
95893bfd616SPantelis Antoniou 	if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
95993bfd616SPantelis Antoniou 		(mmc->cfg->host_caps & MMC_MODE_HS)))
9602c3fbf4cSMacpaul Lin 		return 0;
9612c3fbf4cSMacpaul Lin 
962f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
963272cc70bSAndy Fleming 
964272cc70bSAndy Fleming 	if (err)
965272cc70bSAndy Fleming 		return err;
966272cc70bSAndy Fleming 
9674e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
968272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
969272cc70bSAndy Fleming 
970272cc70bSAndy Fleming 	return 0;
971272cc70bSAndy Fleming }
972272cc70bSAndy Fleming 
973272cc70bSAndy Fleming /* frequency bases */
974272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
9755f837c2cSMike Frysinger static const int fbase[] = {
976272cc70bSAndy Fleming 	10000,
977272cc70bSAndy Fleming 	100000,
978272cc70bSAndy Fleming 	1000000,
979272cc70bSAndy Fleming 	10000000,
980272cc70bSAndy Fleming };
981272cc70bSAndy Fleming 
982272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
983272cc70bSAndy Fleming  * to platforms without floating point.
984272cc70bSAndy Fleming  */
98561fe076fSSimon Glass static const u8 multipliers[] = {
986272cc70bSAndy Fleming 	0,	/* reserved */
987272cc70bSAndy Fleming 	10,
988272cc70bSAndy Fleming 	12,
989272cc70bSAndy Fleming 	13,
990272cc70bSAndy Fleming 	15,
991272cc70bSAndy Fleming 	20,
992272cc70bSAndy Fleming 	25,
993272cc70bSAndy Fleming 	30,
994272cc70bSAndy Fleming 	35,
995272cc70bSAndy Fleming 	40,
996272cc70bSAndy Fleming 	45,
997272cc70bSAndy Fleming 	50,
998272cc70bSAndy Fleming 	55,
999272cc70bSAndy Fleming 	60,
1000272cc70bSAndy Fleming 	70,
1001272cc70bSAndy Fleming 	80,
1002272cc70bSAndy Fleming };
1003272cc70bSAndy Fleming 
1004fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
1005272cc70bSAndy Fleming {
100693bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
100793bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
1008272cc70bSAndy Fleming }
1009272cc70bSAndy Fleming 
1010272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
1011272cc70bSAndy Fleming {
101293bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
101393bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1014272cc70bSAndy Fleming 
101593bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
101693bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1017272cc70bSAndy Fleming 
1018272cc70bSAndy Fleming 	mmc->clock = clock;
1019272cc70bSAndy Fleming 
1020272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1021272cc70bSAndy Fleming }
1022272cc70bSAndy Fleming 
1023fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width)
1024272cc70bSAndy Fleming {
1025272cc70bSAndy Fleming 	mmc->bus_width = width;
1026272cc70bSAndy Fleming 
1027272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1028272cc70bSAndy Fleming }
1029272cc70bSAndy Fleming 
1030fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1031272cc70bSAndy Fleming {
1032f866a46dSStephen Warren 	int err, i;
1033272cc70bSAndy Fleming 	uint mult, freq;
1034639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
1035272cc70bSAndy Fleming 	struct mmc_cmd cmd;
10368bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
10378bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
10385d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
10390c453bb7SDiego Santa Cruz 	bool has_parts = false;
10408a0cf490SDiego Santa Cruz 	bool part_completed;
1041c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1042272cc70bSAndy Fleming 
1043d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1044d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1045d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1046d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1047d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1048d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1049d52ebf10SThomas Chou 
1050d52ebf10SThomas Chou 		if (err)
1051d52ebf10SThomas Chou 			return err;
1052d52ebf10SThomas Chou 	}
1053d52ebf10SThomas Chou #endif
1054d52ebf10SThomas Chou 
1055272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1056d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1057d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1058272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1059272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1060272cc70bSAndy Fleming 
1061272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1062272cc70bSAndy Fleming 
1063272cc70bSAndy Fleming 	if (err)
1064272cc70bSAndy Fleming 		return err;
1065272cc70bSAndy Fleming 
1066272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1067272cc70bSAndy Fleming 
1068272cc70bSAndy Fleming 	/*
1069272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1070272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1071272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1072272cc70bSAndy Fleming 	 */
1073d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1074272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1075272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1076272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1077272cc70bSAndy Fleming 
1078272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1079272cc70bSAndy Fleming 
1080272cc70bSAndy Fleming 		if (err)
1081272cc70bSAndy Fleming 			return err;
1082272cc70bSAndy Fleming 
1083272cc70bSAndy Fleming 		if (IS_SD(mmc))
1084998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1085d52ebf10SThomas Chou 	}
1086272cc70bSAndy Fleming 
1087272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1088272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1089272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1090272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1091272cc70bSAndy Fleming 
1092272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1093272cc70bSAndy Fleming 
10945d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
10955d4fc8d9SRaffaele Recalcati 	mmc_send_status(mmc, timeout);
10965d4fc8d9SRaffaele Recalcati 
1097272cc70bSAndy Fleming 	if (err)
1098272cc70bSAndy Fleming 		return err;
1099272cc70bSAndy Fleming 
1100998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1101998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1102998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1103998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1104272cc70bSAndy Fleming 
1105272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
11060b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1107272cc70bSAndy Fleming 
1108272cc70bSAndy Fleming 		switch (version) {
1109272cc70bSAndy Fleming 		case 0:
1110272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1111272cc70bSAndy Fleming 			break;
1112272cc70bSAndy Fleming 		case 1:
1113272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1114272cc70bSAndy Fleming 			break;
1115272cc70bSAndy Fleming 		case 2:
1116272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1117272cc70bSAndy Fleming 			break;
1118272cc70bSAndy Fleming 		case 3:
1119272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1120272cc70bSAndy Fleming 			break;
1121272cc70bSAndy Fleming 		case 4:
1122272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1123272cc70bSAndy Fleming 			break;
1124272cc70bSAndy Fleming 		default:
1125272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1126272cc70bSAndy Fleming 			break;
1127272cc70bSAndy Fleming 		}
1128272cc70bSAndy Fleming 	}
1129272cc70bSAndy Fleming 
1130272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
11310b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
11320b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1133272cc70bSAndy Fleming 
1134272cc70bSAndy Fleming 	mmc->tran_speed = freq * mult;
1135272cc70bSAndy Fleming 
1136ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1137998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1138272cc70bSAndy Fleming 
1139272cc70bSAndy Fleming 	if (IS_SD(mmc))
1140272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1141272cc70bSAndy Fleming 	else
1142998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1143272cc70bSAndy Fleming 
1144272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1145272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1146272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1147272cc70bSAndy Fleming 		cmult = 8;
1148272cc70bSAndy Fleming 	} else {
1149272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1150272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1151272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1152272cc70bSAndy Fleming 	}
1153272cc70bSAndy Fleming 
1154f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1155f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1156f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1157f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1158f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1159f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1160272cc70bSAndy Fleming 
11618bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
11628bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1163272cc70bSAndy Fleming 
11648bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
11658bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1166272cc70bSAndy Fleming 
1167ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1168ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1169ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1170ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1171ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1172ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1173ab71188cSMarkus Niebel 	}
1174ab71188cSMarkus Niebel 
1175272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1176d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1177272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1178fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1179272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1180272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1181272cc70bSAndy Fleming 
1182272cc70bSAndy Fleming 		if (err)
1183272cc70bSAndy Fleming 			return err;
1184d52ebf10SThomas Chou 	}
1185272cc70bSAndy Fleming 
1186e6f99a56SLei Wen 	/*
1187e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1188e6f99a56SLei Wen 	 */
1189e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1190bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1191d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
1192d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
1193d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
11949cf199ebSDiego Santa Cruz 		if (err)
11959cf199ebSDiego Santa Cruz 			return err;
11969cf199ebSDiego Santa Cruz 		if (ext_csd[EXT_CSD_REV] >= 2) {
1197639b7827SYoshihiro Shimoda 			/*
1198639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
1199639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
1200639b7827SYoshihiro Shimoda 			 * than 2GB
1201639b7827SYoshihiro Shimoda 			 */
12020560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
12030560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
12040560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
12050560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
12068bfa195eSSimon Glass 			capacity *= MMC_MAX_BLOCK_LEN;
1207b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
1208f866a46dSStephen Warren 				mmc->capacity_user = capacity;
1209d23e2c09SSukumar Ghorai 		}
1210bc897b1dSLei Wen 
121164f4a619SJaehoon Chung 		switch (ext_csd[EXT_CSD_REV]) {
121264f4a619SJaehoon Chung 		case 1:
121364f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_1;
121464f4a619SJaehoon Chung 			break;
121564f4a619SJaehoon Chung 		case 2:
121664f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_2;
121764f4a619SJaehoon Chung 			break;
121864f4a619SJaehoon Chung 		case 3:
121964f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_3;
122064f4a619SJaehoon Chung 			break;
122164f4a619SJaehoon Chung 		case 5:
122264f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_41;
122364f4a619SJaehoon Chung 			break;
122464f4a619SJaehoon Chung 		case 6:
122564f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_5;
122664f4a619SJaehoon Chung 			break;
1227edab723bSMarkus Niebel 		case 7:
1228edab723bSMarkus Niebel 			mmc->version = MMC_VERSION_5_0;
1229edab723bSMarkus Niebel 			break;
123064f4a619SJaehoon Chung 		}
123164f4a619SJaehoon Chung 
12328a0cf490SDiego Santa Cruz 		/* The partition data may be non-zero but it is only
12338a0cf490SDiego Santa Cruz 		 * effective if PARTITION_SETTING_COMPLETED is set in
12348a0cf490SDiego Santa Cruz 		 * EXT_CSD, so ignore any data if this bit is not set,
12358a0cf490SDiego Santa Cruz 		 * except for enabling the high-capacity group size
12368a0cf490SDiego Santa Cruz 		 * definition (see below). */
12378a0cf490SDiego Santa Cruz 		part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
12388a0cf490SDiego Santa Cruz 				    EXT_CSD_PARTITION_SETTING_COMPLETED);
12398a0cf490SDiego Santa Cruz 
12400c453bb7SDiego Santa Cruz 		/* store the partition info of emmc */
12410c453bb7SDiego Santa Cruz 		mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
12420c453bb7SDiego Santa Cruz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
12430c453bb7SDiego Santa Cruz 		    ext_csd[EXT_CSD_BOOT_MULT])
12440c453bb7SDiego Santa Cruz 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
12458a0cf490SDiego Santa Cruz 		if (part_completed &&
12468a0cf490SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
12470c453bb7SDiego Santa Cruz 			mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
12480c453bb7SDiego Santa Cruz 
12490c453bb7SDiego Santa Cruz 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
12500c453bb7SDiego Santa Cruz 
12510c453bb7SDiego Santa Cruz 		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
12520c453bb7SDiego Santa Cruz 
12530c453bb7SDiego Santa Cruz 		for (i = 0; i < 4; i++) {
12540c453bb7SDiego Santa Cruz 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
12558a0cf490SDiego Santa Cruz 			uint mult = (ext_csd[idx + 2] << 16) +
12560c453bb7SDiego Santa Cruz 				(ext_csd[idx + 1] << 8) + ext_csd[idx];
12578a0cf490SDiego Santa Cruz 			if (mult)
12588a0cf490SDiego Santa Cruz 				has_parts = true;
12598a0cf490SDiego Santa Cruz 			if (!part_completed)
12608a0cf490SDiego Santa Cruz 				continue;
12618a0cf490SDiego Santa Cruz 			mmc->capacity_gp[i] = mult;
12620c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *=
12630c453bb7SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
12640c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1265f8e89d67SDiego Santa Cruz 			mmc->capacity_gp[i] <<= 19;
12660c453bb7SDiego Santa Cruz 		}
12670c453bb7SDiego Santa Cruz 
12688a0cf490SDiego Santa Cruz 		if (part_completed) {
1269a7f852b6SDiego Santa Cruz 			mmc->enh_user_size =
1270a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
1271a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
1272a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_SIZE_MULT];
1273a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1274a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1275a7f852b6SDiego Santa Cruz 			mmc->enh_user_size <<= 19;
1276a7f852b6SDiego Santa Cruz 			mmc->enh_user_start =
1277a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
1278a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
1279a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
1280a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_START_ADDR];
1281a7f852b6SDiego Santa Cruz 			if (mmc->high_capacity)
1282a7f852b6SDiego Santa Cruz 				mmc->enh_user_start <<= 9;
12838a0cf490SDiego Santa Cruz 		}
1284a7f852b6SDiego Santa Cruz 
1285e6f99a56SLei Wen 		/*
12861937e5aaSOliver Metz 		 * Host needs to enable ERASE_GRP_DEF bit if device is
12871937e5aaSOliver Metz 		 * partitioned. This bit will be lost every time after a reset
12881937e5aaSOliver Metz 		 * or power off. This will affect erase size.
1289e6f99a56SLei Wen 		 */
12908a0cf490SDiego Santa Cruz 		if (part_completed)
12910c453bb7SDiego Santa Cruz 			has_parts = true;
12921937e5aaSOliver Metz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
12930c453bb7SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
12940c453bb7SDiego Santa Cruz 			has_parts = true;
12950c453bb7SDiego Santa Cruz 		if (has_parts) {
12961937e5aaSOliver Metz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
12971937e5aaSOliver Metz 				EXT_CSD_ERASE_GROUP_DEF, 1);
12981937e5aaSOliver Metz 
12991937e5aaSOliver Metz 			if (err)
13001937e5aaSOliver Metz 				return err;
1301021a8055SHannes Petermaier 			else
1302021a8055SHannes Petermaier 				ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1303037dc0abSDiego Santa Cruz 		}
13041937e5aaSOliver Metz 
1305037dc0abSDiego Santa Cruz 		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
13061937e5aaSOliver Metz 			/* Read out group size from ext_csd */
13070560db18SLei Wen 			mmc->erase_grp_size =
1308a4ff9f83SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1309d7b29129SMarkus Niebel 			/*
1310d7b29129SMarkus Niebel 			 * if high capacity and partition setting completed
1311d7b29129SMarkus Niebel 			 * SEC_COUNT is valid even if it is smaller than 2 GiB
1312d7b29129SMarkus Niebel 			 * JEDEC Standard JESD84-B45, 6.2.4
1313d7b29129SMarkus Niebel 			 */
13148a0cf490SDiego Santa Cruz 			if (mmc->high_capacity && part_completed) {
1315d7b29129SMarkus Niebel 				capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1316d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1317d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1318d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1319d7b29129SMarkus Niebel 				capacity *= MMC_MAX_BLOCK_LEN;
1320d7b29129SMarkus Niebel 				mmc->capacity_user = capacity;
1321d7b29129SMarkus Niebel 			}
13228bfa195eSSimon Glass 		} else {
13231937e5aaSOliver Metz 			/* Calculate the group size from the csd value. */
1324e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
1325e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1326e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1327e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
1328e6f99a56SLei Wen 				* (erase_gmul + 1);
1329e6f99a56SLei Wen 		}
1330037dc0abSDiego Santa Cruz 
1331037dc0abSDiego Santa Cruz 		mmc->hc_wp_grp_size = 1024
1332037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1333037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
13349e41a00bSDiego Santa Cruz 
13359e41a00bSDiego Santa Cruz 		mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1336f866a46dSStephen Warren 	}
1337f866a46dSStephen Warren 
1338c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
1339f866a46dSStephen Warren 	if (err)
1340f866a46dSStephen Warren 		return err;
1341d23e2c09SSukumar Ghorai 
1342272cc70bSAndy Fleming 	if (IS_SD(mmc))
1343272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1344272cc70bSAndy Fleming 	else
1345272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1346272cc70bSAndy Fleming 
1347272cc70bSAndy Fleming 	if (err)
1348272cc70bSAndy Fleming 		return err;
1349272cc70bSAndy Fleming 
1350272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
135193bfd616SPantelis Antoniou 	mmc->card_caps &= mmc->cfg->host_caps;
1352272cc70bSAndy Fleming 
1353272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1354272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1355272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1356272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1357272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1358272cc70bSAndy Fleming 
1359272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1360272cc70bSAndy Fleming 			if (err)
1361272cc70bSAndy Fleming 				return err;
1362272cc70bSAndy Fleming 
1363272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1364272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1365272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1366272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1367272cc70bSAndy Fleming 			if (err)
1368272cc70bSAndy Fleming 				return err;
1369272cc70bSAndy Fleming 
1370272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1371272cc70bSAndy Fleming 		}
1372272cc70bSAndy Fleming 
1373272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
1374ad5fd922SJaehoon Chung 			mmc->tran_speed = 50000000;
1375272cc70bSAndy Fleming 		else
1376ad5fd922SJaehoon Chung 			mmc->tran_speed = 25000000;
1377fc5b32fbSAndrew Gabbasov 	} else if (mmc->version >= MMC_VERSION_4) {
1378fc5b32fbSAndrew Gabbasov 		/* Only version 4 of MMC supports wider bus widths */
13797798f6dbSAndy Fleming 		int idx;
13807798f6dbSAndy Fleming 
13817798f6dbSAndy Fleming 		/* An array of possible bus widths in order of preference */
13827798f6dbSAndy Fleming 		static unsigned ext_csd_bits[] = {
1383d22e3d46SJaehoon Chung 			EXT_CSD_DDR_BUS_WIDTH_8,
1384d22e3d46SJaehoon Chung 			EXT_CSD_DDR_BUS_WIDTH_4,
13857798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_8,
13867798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_4,
13877798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_1,
13887798f6dbSAndy Fleming 		};
13897798f6dbSAndy Fleming 
13907798f6dbSAndy Fleming 		/* An array to map CSD bus widths to host cap bits */
13917798f6dbSAndy Fleming 		static unsigned ext_to_hostcaps[] = {
1392786e8f81SAndrew Gabbasov 			[EXT_CSD_DDR_BUS_WIDTH_4] =
1393786e8f81SAndrew Gabbasov 				MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
1394786e8f81SAndrew Gabbasov 			[EXT_CSD_DDR_BUS_WIDTH_8] =
1395786e8f81SAndrew Gabbasov 				MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
13967798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
13977798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
13987798f6dbSAndy Fleming 		};
13997798f6dbSAndy Fleming 
14007798f6dbSAndy Fleming 		/* An array to map chosen bus width to an integer */
14017798f6dbSAndy Fleming 		static unsigned widths[] = {
1402d22e3d46SJaehoon Chung 			8, 4, 8, 4, 1,
14037798f6dbSAndy Fleming 		};
14047798f6dbSAndy Fleming 
14057798f6dbSAndy Fleming 		for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
14067798f6dbSAndy Fleming 			unsigned int extw = ext_csd_bits[idx];
1407786e8f81SAndrew Gabbasov 			unsigned int caps = ext_to_hostcaps[extw];
14087798f6dbSAndy Fleming 
14097798f6dbSAndy Fleming 			/*
1410bf477073SAndrew Gabbasov 			 * If the bus width is still not changed,
1411bf477073SAndrew Gabbasov 			 * don't try to set the default again.
1412bf477073SAndrew Gabbasov 			 * Otherwise, recover from switch attempts
1413bf477073SAndrew Gabbasov 			 * by switching to 1-bit bus width.
1414bf477073SAndrew Gabbasov 			 */
1415bf477073SAndrew Gabbasov 			if (extw == EXT_CSD_BUS_WIDTH_1 &&
1416bf477073SAndrew Gabbasov 					mmc->bus_width == 1) {
1417bf477073SAndrew Gabbasov 				err = 0;
1418bf477073SAndrew Gabbasov 				break;
1419bf477073SAndrew Gabbasov 			}
1420bf477073SAndrew Gabbasov 
1421bf477073SAndrew Gabbasov 			/*
1422786e8f81SAndrew Gabbasov 			 * Check to make sure the card and controller support
1423786e8f81SAndrew Gabbasov 			 * these capabilities
14247798f6dbSAndy Fleming 			 */
1425786e8f81SAndrew Gabbasov 			if ((mmc->card_caps & caps) != caps)
14267798f6dbSAndy Fleming 				continue;
14277798f6dbSAndy Fleming 
1428272cc70bSAndy Fleming 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
14297798f6dbSAndy Fleming 					EXT_CSD_BUS_WIDTH, extw);
1430272cc70bSAndy Fleming 
1431272cc70bSAndy Fleming 			if (err)
14324137894eSLei Wen 				continue;
1433272cc70bSAndy Fleming 
1434786e8f81SAndrew Gabbasov 			mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
14357798f6dbSAndy Fleming 			mmc_set_bus_width(mmc, widths[idx]);
1436272cc70bSAndy Fleming 
14374137894eSLei Wen 			err = mmc_send_ext_csd(mmc, test_csd);
1438272cc70bSAndy Fleming 
1439786e8f81SAndrew Gabbasov 			if (err)
1440786e8f81SAndrew Gabbasov 				continue;
1441786e8f81SAndrew Gabbasov 
1442786e8f81SAndrew Gabbasov 			/* Only compare read only fields */
1443786e8f81SAndrew Gabbasov 			if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
1444786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
1445786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
1446786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
1447786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_REV]
1448786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_REV] &&
1449786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1450786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
1451786e8f81SAndrew Gabbasov 			    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
1452786e8f81SAndrew Gabbasov 				   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
14534137894eSLei Wen 				break;
1454786e8f81SAndrew Gabbasov 			else
1455786e8f81SAndrew Gabbasov 				err = SWITCH_ERR;
14564137894eSLei Wen 		}
1457786e8f81SAndrew Gabbasov 
1458786e8f81SAndrew Gabbasov 		if (err)
1459786e8f81SAndrew Gabbasov 			return err;
1460272cc70bSAndy Fleming 
1461272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS) {
1462272cc70bSAndy Fleming 			if (mmc->card_caps & MMC_MODE_HS_52MHz)
1463ad5fd922SJaehoon Chung 				mmc->tran_speed = 52000000;
1464272cc70bSAndy Fleming 			else
1465ad5fd922SJaehoon Chung 				mmc->tran_speed = 26000000;
1466272cc70bSAndy Fleming 		}
1467ad5fd922SJaehoon Chung 	}
1468ad5fd922SJaehoon Chung 
1469ad5fd922SJaehoon Chung 	mmc_set_clock(mmc, mmc->tran_speed);
1470272cc70bSAndy Fleming 
14715af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
14725af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
14735af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
14745af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
14755af8f45cSAndrew Gabbasov 	}
14765af8f45cSAndrew Gabbasov 
1477272cc70bSAndy Fleming 	/* fill in device description */
1478c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1479c40fdca6SSimon Glass 	bdesc->lun = 0;
1480c40fdca6SSimon Glass 	bdesc->hwpart = 0;
1481c40fdca6SSimon Glass 	bdesc->type = 0;
1482c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
1483c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
1484c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1485fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1486fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1487fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1488c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
1489babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1490babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1491c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
14920b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1493babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1494babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1495c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1496babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
149756196826SPaul Burton #else
1498c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
1499c40fdca6SSimon Glass 	bdesc->product[0] = 0;
1500c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
150156196826SPaul Burton #endif
1502122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1503c40fdca6SSimon Glass 	part_init(bdesc);
1504122efd43SMikhail Kshevetskiy #endif
1505272cc70bSAndy Fleming 
1506272cc70bSAndy Fleming 	return 0;
1507272cc70bSAndy Fleming }
1508272cc70bSAndy Fleming 
1509fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1510272cc70bSAndy Fleming {
1511272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1512272cc70bSAndy Fleming 	int err;
1513272cc70bSAndy Fleming 
1514272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1515272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
151693bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1517272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1518272cc70bSAndy Fleming 
1519272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1520272cc70bSAndy Fleming 
1521272cc70bSAndy Fleming 	if (err)
1522272cc70bSAndy Fleming 		return err;
1523272cc70bSAndy Fleming 
1524998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1525272cc70bSAndy Fleming 		return UNUSABLE_ERR;
1526272cc70bSAndy Fleming 	else
1527272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1528272cc70bSAndy Fleming 
1529272cc70bSAndy Fleming 	return 0;
1530272cc70bSAndy Fleming }
1531272cc70bSAndy Fleming 
1532ad27dd5eSSimon Glass #ifdef CONFIG_BLK
1533ad27dd5eSSimon Glass int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg)
1534ad27dd5eSSimon Glass {
1535ad27dd5eSSimon Glass 	struct blk_desc *bdesc;
1536ad27dd5eSSimon Glass 	struct udevice *bdev;
1537ad27dd5eSSimon Glass 	int ret;
1538ad27dd5eSSimon Glass 
1539ad27dd5eSSimon Glass 	ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC, -1, 512,
1540ad27dd5eSSimon Glass 				 0, &bdev);
1541ad27dd5eSSimon Glass 	if (ret) {
1542ad27dd5eSSimon Glass 		debug("Cannot create block device\n");
1543ad27dd5eSSimon Glass 		return ret;
1544ad27dd5eSSimon Glass 	}
1545ad27dd5eSSimon Glass 	bdesc = dev_get_uclass_platdata(bdev);
1546ad27dd5eSSimon Glass 	mmc->cfg = cfg;
1547ad27dd5eSSimon Glass 	mmc->priv = dev;
1548ad27dd5eSSimon Glass 
1549ad27dd5eSSimon Glass 	/* the following chunk was from mmc_register() */
1550ad27dd5eSSimon Glass 
1551ad27dd5eSSimon Glass 	/* Setup dsr related values */
1552ad27dd5eSSimon Glass 	mmc->dsr_imp = 0;
1553ad27dd5eSSimon Glass 	mmc->dsr = 0xffffffff;
1554ad27dd5eSSimon Glass 	/* Setup the universal parts of the block interface just once */
1555ad27dd5eSSimon Glass 	bdesc->removable = 1;
1556ad27dd5eSSimon Glass 
1557ad27dd5eSSimon Glass 	/* setup initial part type */
1558e6c28073SSimon Glass 	bdesc->part_type = cfg->part_type;
1559ad27dd5eSSimon Glass 	mmc->dev = dev;
1560ad27dd5eSSimon Glass 
1561ad27dd5eSSimon Glass 	return 0;
1562ad27dd5eSSimon Glass }
1563ad27dd5eSSimon Glass 
1564ad27dd5eSSimon Glass int mmc_unbind(struct udevice *dev)
1565ad27dd5eSSimon Glass {
1566ad27dd5eSSimon Glass 	struct udevice *bdev;
1567ad27dd5eSSimon Glass 
1568ad27dd5eSSimon Glass 	device_find_first_child(dev, &bdev);
1569ad27dd5eSSimon Glass 	if (bdev) {
1570ad27dd5eSSimon Glass 		device_remove(bdev);
1571ad27dd5eSSimon Glass 		device_unbind(bdev);
1572ad27dd5eSSimon Glass 	}
1573ad27dd5eSSimon Glass 
1574ad27dd5eSSimon Glass 	return 0;
1575ad27dd5eSSimon Glass }
1576ad27dd5eSSimon Glass 
1577ad27dd5eSSimon Glass #else
157893bfd616SPantelis Antoniou struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
157993bfd616SPantelis Antoniou {
1580c40fdca6SSimon Glass 	struct blk_desc *bdesc;
158193bfd616SPantelis Antoniou 	struct mmc *mmc;
158293bfd616SPantelis Antoniou 
158393bfd616SPantelis Antoniou 	/* quick validation */
158493bfd616SPantelis Antoniou 	if (cfg == NULL || cfg->ops == NULL || cfg->ops->send_cmd == NULL ||
158593bfd616SPantelis Antoniou 			cfg->f_min == 0 || cfg->f_max == 0 || cfg->b_max == 0)
158693bfd616SPantelis Antoniou 		return NULL;
158793bfd616SPantelis Antoniou 
158893bfd616SPantelis Antoniou 	mmc = calloc(1, sizeof(*mmc));
158993bfd616SPantelis Antoniou 	if (mmc == NULL)
159093bfd616SPantelis Antoniou 		return NULL;
159193bfd616SPantelis Antoniou 
159293bfd616SPantelis Antoniou 	mmc->cfg = cfg;
159393bfd616SPantelis Antoniou 	mmc->priv = priv;
159493bfd616SPantelis Antoniou 
159593bfd616SPantelis Antoniou 	/* the following chunk was mmc_register() */
159693bfd616SPantelis Antoniou 
1597ab71188cSMarkus Niebel 	/* Setup dsr related values */
1598ab71188cSMarkus Niebel 	mmc->dsr_imp = 0;
1599ab71188cSMarkus Niebel 	mmc->dsr = 0xffffffff;
1600272cc70bSAndy Fleming 	/* Setup the universal parts of the block interface just once */
1601c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1602c40fdca6SSimon Glass 	bdesc->if_type = IF_TYPE_MMC;
1603c40fdca6SSimon Glass 	bdesc->removable = 1;
1604c40fdca6SSimon Glass 	bdesc->devnum = mmc_get_next_devnum();
1605c40fdca6SSimon Glass 	bdesc->block_read = mmc_bread;
1606c40fdca6SSimon Glass 	bdesc->block_write = mmc_bwrite;
1607c40fdca6SSimon Glass 	bdesc->block_erase = mmc_berase;
160893bfd616SPantelis Antoniou 
160993bfd616SPantelis Antoniou 	/* setup initial part type */
1610c40fdca6SSimon Glass 	bdesc->part_type = mmc->cfg->part_type;
1611c40fdca6SSimon Glass 	mmc_list_add(mmc);
1612272cc70bSAndy Fleming 
161393bfd616SPantelis Antoniou 	return mmc;
161493bfd616SPantelis Antoniou }
161593bfd616SPantelis Antoniou 
161693bfd616SPantelis Antoniou void mmc_destroy(struct mmc *mmc)
161793bfd616SPantelis Antoniou {
161893bfd616SPantelis Antoniou 	/* only freeing memory for now */
161993bfd616SPantelis Antoniou 	free(mmc);
1620272cc70bSAndy Fleming }
1621ad27dd5eSSimon Glass #endif
1622272cc70bSAndy Fleming 
162333fb211dSSimon Glass #ifndef CONFIG_BLK
16243c457f4dSSimon Glass static int mmc_get_dev(int dev, struct blk_desc **descp)
1625663acabdSSimon Glass {
1626663acabdSSimon Glass 	struct mmc *mmc = find_mmc_device(dev);
1627663acabdSSimon Glass 	int ret;
1628663acabdSSimon Glass 
1629663acabdSSimon Glass 	if (!mmc)
1630663acabdSSimon Glass 		return -ENODEV;
1631663acabdSSimon Glass 	ret = mmc_init(mmc);
1632663acabdSSimon Glass 	if (ret)
1633663acabdSSimon Glass 		return ret;
1634663acabdSSimon Glass 
1635663acabdSSimon Glass 	*descp = &mmc->block_dev;
1636663acabdSSimon Glass 
1637663acabdSSimon Glass 	return 0;
1638663acabdSSimon Glass }
163933fb211dSSimon Glass #endif
1640663acabdSSimon Glass 
164195de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
164295de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
164395de9ab2SPaul Kocialkowski {
164495de9ab2SPaul Kocialkowski }
164595de9ab2SPaul Kocialkowski 
1646e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1647272cc70bSAndy Fleming {
1648afd5932bSMacpaul Lin 	int err;
1649272cc70bSAndy Fleming 
1650ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
165193bfd616SPantelis Antoniou 	if (mmc_getcd(mmc) == 0 || mmc->cfg->ops->init == NULL) {
165248972d90SThierry Reding 		mmc->has_init = 0;
165356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
165448972d90SThierry Reding 		printf("MMC: no card present\n");
165556196826SPaul Burton #endif
165648972d90SThierry Reding 		return NO_CARD_ERR;
165748972d90SThierry Reding 	}
165848972d90SThierry Reding 
1659bc897b1dSLei Wen 	if (mmc->has_init)
1660bc897b1dSLei Wen 		return 0;
1661bc897b1dSLei Wen 
16625a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
16635a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
16645a8dbdc6SYangbo Lu #endif
166595de9ab2SPaul Kocialkowski 	board_mmc_power_init();
166695de9ab2SPaul Kocialkowski 
1667ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
166893bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
1669272cc70bSAndy Fleming 
1670272cc70bSAndy Fleming 	if (err)
1671272cc70bSAndy Fleming 		return err;
1672272cc70bSAndy Fleming 
1673786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
1674b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1675b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1676b86b85e2SIlya Yanok 
1677272cc70bSAndy Fleming 	/* Reset the Card */
1678272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1679272cc70bSAndy Fleming 
1680272cc70bSAndy Fleming 	if (err)
1681272cc70bSAndy Fleming 		return err;
1682272cc70bSAndy Fleming 
1683bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1684c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
1685bc897b1dSLei Wen 
1686272cc70bSAndy Fleming 	/* Test for SD version 2 */
1687272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1688272cc70bSAndy Fleming 
1689272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1690272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1691272cc70bSAndy Fleming 
1692272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1693272cc70bSAndy Fleming 	if (err == TIMEOUT) {
1694272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1695272cc70bSAndy Fleming 
1696bd47c135SAndrew Gabbasov 		if (err) {
169756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1698272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
169956196826SPaul Burton #endif
1700272cc70bSAndy Fleming 			return UNUSABLE_ERR;
1701272cc70bSAndy Fleming 		}
1702272cc70bSAndy Fleming 	}
1703272cc70bSAndy Fleming 
1704bd47c135SAndrew Gabbasov 	if (!err)
1705e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
1706e9550449SChe-Liang Chiou 
1707e9550449SChe-Liang Chiou 	return err;
1708e9550449SChe-Liang Chiou }
1709e9550449SChe-Liang Chiou 
1710e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
1711e9550449SChe-Liang Chiou {
1712e9550449SChe-Liang Chiou 	int err = 0;
1713e9550449SChe-Liang Chiou 
1714bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
1715e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
1716e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
1717e9550449SChe-Liang Chiou 
1718e9550449SChe-Liang Chiou 	if (!err)
1719bc897b1dSLei Wen 		err = mmc_startup(mmc);
1720bc897b1dSLei Wen 	if (err)
1721bc897b1dSLei Wen 		mmc->has_init = 0;
1722bc897b1dSLei Wen 	else
1723bc897b1dSLei Wen 		mmc->has_init = 1;
1724e9550449SChe-Liang Chiou 	return err;
1725e9550449SChe-Liang Chiou }
1726e9550449SChe-Liang Chiou 
1727e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
1728e9550449SChe-Liang Chiou {
1729bd47c135SAndrew Gabbasov 	int err = 0;
1730d803fea5SMateusz Zalega 	unsigned start;
173133fb211dSSimon Glass #ifdef CONFIG_DM_MMC
173233fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
1733e9550449SChe-Liang Chiou 
173433fb211dSSimon Glass 	upriv->mmc = mmc;
173533fb211dSSimon Glass #endif
1736e9550449SChe-Liang Chiou 	if (mmc->has_init)
1737e9550449SChe-Liang Chiou 		return 0;
1738d803fea5SMateusz Zalega 
1739d803fea5SMateusz Zalega 	start = get_timer(0);
1740d803fea5SMateusz Zalega 
1741e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
1742e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
1743e9550449SChe-Liang Chiou 
1744bd47c135SAndrew Gabbasov 	if (!err)
1745e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
1746e9550449SChe-Liang Chiou 	debug("%s: %d, time %lu\n", __func__, err, get_timer(start));
1747bc897b1dSLei Wen 	return err;
1748272cc70bSAndy Fleming }
1749272cc70bSAndy Fleming 
1750ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
1751ab71188cSMarkus Niebel {
1752ab71188cSMarkus Niebel 	mmc->dsr = val;
1753ab71188cSMarkus Niebel 	return 0;
1754ab71188cSMarkus Niebel }
1755ab71188cSMarkus Niebel 
1756cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
1757cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
1758272cc70bSAndy Fleming {
1759272cc70bSAndy Fleming 	return -1;
1760272cc70bSAndy Fleming }
1761272cc70bSAndy Fleming 
1762cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
1763cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
1764cee9ab7cSJeroen Hofstee {
1765cee9ab7cSJeroen Hofstee 	return -1;
1766cee9ab7cSJeroen Hofstee }
1767272cc70bSAndy Fleming 
1768e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
1769e9550449SChe-Liang Chiou {
1770e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
1771e9550449SChe-Liang Chiou }
1772e9550449SChe-Liang Chiou 
17738e3332e2SSjoerd Simons #if defined(CONFIG_DM_MMC) && defined(CONFIG_SPL_BUILD)
17748e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
17758e3332e2SSjoerd Simons {
17768e3332e2SSjoerd Simons 	return 0;
17778e3332e2SSjoerd Simons }
17788e3332e2SSjoerd Simons #elif defined(CONFIG_DM_MMC)
17798e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
17808e3332e2SSjoerd Simons {
17814a1db6d8SSimon Glass 	int ret, i;
17828e3332e2SSjoerd Simons 	struct uclass *uc;
17834a1db6d8SSimon Glass 	struct udevice *dev;
17848e3332e2SSjoerd Simons 
17858e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
17868e3332e2SSjoerd Simons 	if (ret)
17878e3332e2SSjoerd Simons 		return ret;
17888e3332e2SSjoerd Simons 
17894a1db6d8SSimon Glass 	/*
17904a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
17914a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
17924a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
17934a1db6d8SSimon Glass 	 */
17944a1db6d8SSimon Glass 	for (i = 0; ; i++) {
17954a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
17964a1db6d8SSimon Glass 		if (ret == -ENODEV)
17974a1db6d8SSimon Glass 			break;
17984a1db6d8SSimon Glass 	}
17994a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
18004a1db6d8SSimon Glass 		ret = device_probe(dev);
18018e3332e2SSjoerd Simons 		if (ret)
18024a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
18038e3332e2SSjoerd Simons 	}
18048e3332e2SSjoerd Simons 
18058e3332e2SSjoerd Simons 	return 0;
18068e3332e2SSjoerd Simons }
18078e3332e2SSjoerd Simons #else
18088e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
18098e3332e2SSjoerd Simons {
18108e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
18118e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
18128e3332e2SSjoerd Simons 
18138e3332e2SSjoerd Simons 	return 0;
18148e3332e2SSjoerd Simons }
18158e3332e2SSjoerd Simons #endif
1816e9550449SChe-Liang Chiou 
1817272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1818272cc70bSAndy Fleming {
18191b26bab1SDaniel Kochmański 	static int initialized = 0;
18208e3332e2SSjoerd Simons 	int ret;
18211b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
18221b26bab1SDaniel Kochmański 		return 0;
18231b26bab1SDaniel Kochmański 	initialized = 1;
18241b26bab1SDaniel Kochmański 
1825c40fdca6SSimon Glass #ifndef CONFIG_BLK
1826c40fdca6SSimon Glass 	mmc_list_init();
1827c40fdca6SSimon Glass #endif
18288e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
18298e3332e2SSjoerd Simons 	if (ret)
18308e3332e2SSjoerd Simons 		return ret;
1831272cc70bSAndy Fleming 
1832bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
1833272cc70bSAndy Fleming 	print_mmc_devices(',');
1834bb0dc108SYing Zhang #endif
1835272cc70bSAndy Fleming 
1836c40fdca6SSimon Glass 	mmc_do_preinit();
1837272cc70bSAndy Fleming 	return 0;
1838272cc70bSAndy Fleming }
18393690d6d6SAmar 
18403690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT
18413690d6d6SAmar /*
18423690d6d6SAmar  * This function changes the size of boot partition and the size of rpmb
18433690d6d6SAmar  * partition present on EMMC devices.
18443690d6d6SAmar  *
18453690d6d6SAmar  * Input Parameters:
18463690d6d6SAmar  * struct *mmc: pointer for the mmc device strcuture
18473690d6d6SAmar  * bootsize: size of boot partition
18483690d6d6SAmar  * rpmbsize: size of rpmb partition
18493690d6d6SAmar  *
18503690d6d6SAmar  * Returns 0 on success.
18513690d6d6SAmar  */
18523690d6d6SAmar 
18533690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
18543690d6d6SAmar 				unsigned long rpmbsize)
18553690d6d6SAmar {
18563690d6d6SAmar 	int err;
18573690d6d6SAmar 	struct mmc_cmd cmd;
18583690d6d6SAmar 
18593690d6d6SAmar 	/* Only use this command for raw EMMC moviNAND. Enter backdoor mode */
18603690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18613690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18623690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG1;
18633690d6d6SAmar 
18643690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18653690d6d6SAmar 	if (err) {
18663690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error1 = %d\n", err);
18673690d6d6SAmar 		return err;
18683690d6d6SAmar 	}
18693690d6d6SAmar 
18703690d6d6SAmar 	/* Boot partition changing mode */
18713690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18723690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18733690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG2;
18743690d6d6SAmar 
18753690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18763690d6d6SAmar 	if (err) {
18773690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error2 = %d\n", err);
18783690d6d6SAmar 		return err;
18793690d6d6SAmar 	}
18803690d6d6SAmar 	/* boot partition size is multiple of 128KB */
18813690d6d6SAmar 	bootsize = (bootsize * 1024) / 128;
18823690d6d6SAmar 
18833690d6d6SAmar 	/* Arg: boot partition size */
18843690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18853690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18863690d6d6SAmar 	cmd.cmdarg = bootsize;
18873690d6d6SAmar 
18883690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18893690d6d6SAmar 	if (err) {
18903690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error3 = %d\n", err);
18913690d6d6SAmar 		return err;
18923690d6d6SAmar 	}
18933690d6d6SAmar 	/* RPMB partition size is multiple of 128KB */
18943690d6d6SAmar 	rpmbsize = (rpmbsize * 1024) / 128;
18953690d6d6SAmar 	/* Arg: RPMB partition size */
18963690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18973690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18983690d6d6SAmar 	cmd.cmdarg = rpmbsize;
18993690d6d6SAmar 
19003690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
19013690d6d6SAmar 	if (err) {
19023690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error4 = %d\n", err);
19033690d6d6SAmar 		return err;
19043690d6d6SAmar 	}
19053690d6d6SAmar 	return 0;
19063690d6d6SAmar }
19073690d6d6SAmar 
19083690d6d6SAmar /*
19095a99b9deSTom Rini  * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH
19105a99b9deSTom Rini  * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH
19115a99b9deSTom Rini  * and BOOT_MODE.
19125a99b9deSTom Rini  *
19135a99b9deSTom Rini  * Returns 0 on success.
19145a99b9deSTom Rini  */
19155a99b9deSTom Rini int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode)
19165a99b9deSTom Rini {
19175a99b9deSTom Rini 	int err;
19185a99b9deSTom Rini 
19195a99b9deSTom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH,
19205a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) |
19215a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) |
19225a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width));
19235a99b9deSTom Rini 
19245a99b9deSTom Rini 	if (err)
19255a99b9deSTom Rini 		return err;
19265a99b9deSTom Rini 	return 0;
19275a99b9deSTom Rini }
19285a99b9deSTom Rini 
19295a99b9deSTom Rini /*
1930792970b0STom Rini  * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG)
1931792970b0STom Rini  * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and
1932792970b0STom Rini  * PARTITION_ACCESS.
1933792970b0STom Rini  *
1934792970b0STom Rini  * Returns 0 on success.
1935792970b0STom Rini  */
1936792970b0STom Rini int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access)
1937792970b0STom Rini {
1938792970b0STom Rini 	int err;
1939792970b0STom Rini 
1940792970b0STom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
1941792970b0STom Rini 			 EXT_CSD_BOOT_ACK(ack) |
1942792970b0STom Rini 			 EXT_CSD_BOOT_PART_NUM(part_num) |
1943792970b0STom Rini 			 EXT_CSD_PARTITION_ACCESS(access));
1944792970b0STom Rini 
1945792970b0STom Rini 	if (err)
1946792970b0STom Rini 		return err;
1947792970b0STom Rini 	return 0;
1948792970b0STom Rini }
194933ace362STom Rini 
195033ace362STom Rini /*
195133ace362STom Rini  * Modify EXT_CSD[162] which is RST_n_FUNCTION based on the given value
195233ace362STom Rini  * for enable.  Note that this is a write-once field for non-zero values.
195333ace362STom Rini  *
195433ace362STom Rini  * Returns 0 on success.
195533ace362STom Rini  */
195633ace362STom Rini int mmc_set_rst_n_function(struct mmc *mmc, u8 enable)
195733ace362STom Rini {
195833ace362STom Rini 	return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_RST_N_FUNCTION,
195933ace362STom Rini 			  enable);
196033ace362STom Rini }
19613690d6d6SAmar #endif
1962663acabdSSimon Glass 
196333fb211dSSimon Glass #ifdef CONFIG_BLK
196433fb211dSSimon Glass static const struct blk_ops mmc_blk_ops = {
196533fb211dSSimon Glass 	.read	= mmc_bread,
196633fb211dSSimon Glass 	.write	= mmc_bwrite,
196733fb211dSSimon Glass 	.select_hwpart	= mmc_select_hwpart,
196833fb211dSSimon Glass };
196933fb211dSSimon Glass 
197033fb211dSSimon Glass U_BOOT_DRIVER(mmc_blk) = {
197133fb211dSSimon Glass 	.name		= "mmc_blk",
197233fb211dSSimon Glass 	.id		= UCLASS_BLK,
197333fb211dSSimon Glass 	.ops		= &mmc_blk_ops,
197433fb211dSSimon Glass };
197533fb211dSSimon Glass #else
1976663acabdSSimon Glass U_BOOT_LEGACY_BLK(mmc) = {
1977663acabdSSimon Glass 	.if_typename	= "mmc",
1978663acabdSSimon Glass 	.if_type	= IF_TYPE_MMC,
1979663acabdSSimon Glass 	.max_devs	= -1,
19803c457f4dSSimon Glass 	.get_dev	= mmc_get_dev,
1981e17d1143SSimon Glass 	.select_hwpart	= mmc_select_hwpartp,
1982663acabdSSimon Glass };
198333fb211dSSimon Glass #endif
1984