xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 4a1db6d8ab4d5e4565bda079710a028ada12ddbe)
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 
24272cc70bSAndy Fleming static struct list_head mmc_devices;
25272cc70bSAndy Fleming static int cur_dev_num = -1;
26272cc70bSAndy Fleming 
27750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
28d23d8d7eSNikita Kiryanov {
29d23d8d7eSNikita Kiryanov 	return -1;
30d23d8d7eSNikita Kiryanov }
31d23d8d7eSNikita Kiryanov 
32d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
33d23d8d7eSNikita Kiryanov {
34d23d8d7eSNikita Kiryanov 	int wp;
35d23d8d7eSNikita Kiryanov 
36d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
37d23d8d7eSNikita Kiryanov 
38d4e1da4eSPeter Korsgaard 	if (wp < 0) {
3993bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
4093bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
41d4e1da4eSPeter Korsgaard 		else
42d4e1da4eSPeter Korsgaard 			wp = 0;
43d4e1da4eSPeter Korsgaard 	}
44d23d8d7eSNikita Kiryanov 
45d23d8d7eSNikita Kiryanov 	return wp;
46d23d8d7eSNikita Kiryanov }
47d23d8d7eSNikita Kiryanov 
48cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc)
49cee9ab7cSJeroen Hofstee {
5011fdade2SStefano Babic 	return -1;
5111fdade2SStefano Babic }
5211fdade2SStefano Babic 
53da61fa5fSPaul Burton int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
54272cc70bSAndy Fleming {
555db2fe3aSRaffaele Recalcati 	int ret;
568635ff9eSMarek Vasut 
578635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
585db2fe3aSRaffaele Recalcati 	int i;
595db2fe3aSRaffaele Recalcati 	u8 *ptr;
605db2fe3aSRaffaele Recalcati 
615db2fe3aSRaffaele Recalcati 	printf("CMD_SEND:%d\n", cmd->cmdidx);
625db2fe3aSRaffaele Recalcati 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
6393bfd616SPantelis Antoniou 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
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 	}
1055db2fe3aSRaffaele Recalcati #else
10693bfd616SPantelis Antoniou 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
1075db2fe3aSRaffaele Recalcati #endif
1088635ff9eSMarek Vasut 	return ret;
109272cc70bSAndy Fleming }
110272cc70bSAndy Fleming 
111da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
1125d4fc8d9SRaffaele Recalcati {
1135d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
114d617c426SJan Kloetzke 	int err, retries = 5;
1155d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
1165d4fc8d9SRaffaele Recalcati 	int status;
1175d4fc8d9SRaffaele Recalcati #endif
1185d4fc8d9SRaffaele Recalcati 
1195d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
1205d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
121aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
122aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
1235d4fc8d9SRaffaele Recalcati 
1241677eef4SAndrew Gabbasov 	while (1) {
1255d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
126d617c426SJan Kloetzke 		if (!err) {
127d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
128d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
129d617c426SJan Kloetzke 			     MMC_STATE_PRG)
1305d4fc8d9SRaffaele Recalcati 				break;
131d617c426SJan Kloetzke 			else if (cmd.response[0] & MMC_STATUS_MASK) {
13256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
133d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
134d617c426SJan Kloetzke 					cmd.response[0]);
13556196826SPaul Burton #endif
136d617c426SJan Kloetzke 				return COMM_ERR;
137d617c426SJan Kloetzke 			}
138d617c426SJan Kloetzke 		} else if (--retries < 0)
139d617c426SJan Kloetzke 			return err;
1405d4fc8d9SRaffaele Recalcati 
1411677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
1421677eef4SAndrew Gabbasov 			break;
1435d4fc8d9SRaffaele Recalcati 
1441677eef4SAndrew Gabbasov 		udelay(1000);
1451677eef4SAndrew Gabbasov 	}
1465d4fc8d9SRaffaele Recalcati 
1475db2fe3aSRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
1485db2fe3aSRaffaele Recalcati 	status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9;
1495db2fe3aSRaffaele Recalcati 	printf("CURR STATE:%d\n", status);
1505db2fe3aSRaffaele Recalcati #endif
1515b0c942fSJongman Heo 	if (timeout <= 0) {
15256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1535d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
15456196826SPaul Burton #endif
1555d4fc8d9SRaffaele Recalcati 		return TIMEOUT;
1565d4fc8d9SRaffaele Recalcati 	}
1576b2221b0SAndrew Gabbasov 	if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR)
1586b2221b0SAndrew Gabbasov 		return SWITCH_ERR;
1595d4fc8d9SRaffaele Recalcati 
1605d4fc8d9SRaffaele Recalcati 	return 0;
1615d4fc8d9SRaffaele Recalcati }
1625d4fc8d9SRaffaele Recalcati 
163da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
164272cc70bSAndy Fleming {
165272cc70bSAndy Fleming 	struct mmc_cmd cmd;
166272cc70bSAndy Fleming 
167786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
168d22e3d46SJaehoon Chung 		return 0;
169d22e3d46SJaehoon Chung 
170272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
171272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
172272cc70bSAndy Fleming 	cmd.cmdarg = len;
173272cc70bSAndy Fleming 
174272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
175272cc70bSAndy Fleming }
176272cc70bSAndy Fleming 
177272cc70bSAndy Fleming struct mmc *find_mmc_device(int dev_num)
178272cc70bSAndy Fleming {
179272cc70bSAndy Fleming 	struct mmc *m;
180272cc70bSAndy Fleming 	struct list_head *entry;
181272cc70bSAndy Fleming 
182272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
183272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
184272cc70bSAndy Fleming 
185272cc70bSAndy Fleming 		if (m->block_dev.dev == dev_num)
186272cc70bSAndy Fleming 			return m;
187272cc70bSAndy Fleming 	}
188272cc70bSAndy Fleming 
18956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
190272cc70bSAndy Fleming 	printf("MMC Device %d not found\n", dev_num);
19156196826SPaul Burton #endif
192272cc70bSAndy Fleming 
193272cc70bSAndy Fleming 	return NULL;
194272cc70bSAndy Fleming }
195272cc70bSAndy Fleming 
196ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
197fdbb873eSKim Phillips 			   lbaint_t blkcnt)
198272cc70bSAndy Fleming {
199272cc70bSAndy Fleming 	struct mmc_cmd cmd;
200272cc70bSAndy Fleming 	struct mmc_data data;
201272cc70bSAndy Fleming 
2024a1a06bcSAlagu Sankar 	if (blkcnt > 1)
2034a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
2044a1a06bcSAlagu Sankar 	else
205272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
206272cc70bSAndy Fleming 
207272cc70bSAndy Fleming 	if (mmc->high_capacity)
2084a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
209272cc70bSAndy Fleming 	else
2104a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
211272cc70bSAndy Fleming 
212272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
213272cc70bSAndy Fleming 
214272cc70bSAndy Fleming 	data.dest = dst;
2154a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
216272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
217272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
218272cc70bSAndy Fleming 
2194a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
2204a1a06bcSAlagu Sankar 		return 0;
2214a1a06bcSAlagu Sankar 
2224a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
2234a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
2244a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
2254a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
2264a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
22756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2284a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
22956196826SPaul Burton #endif
2304a1a06bcSAlagu Sankar 			return 0;
2314a1a06bcSAlagu Sankar 		}
232272cc70bSAndy Fleming 	}
233272cc70bSAndy Fleming 
2344a1a06bcSAlagu Sankar 	return blkcnt;
235272cc70bSAndy Fleming }
236272cc70bSAndy Fleming 
2377c4213f6SStephen Warren static ulong mmc_bread(block_dev_desc_t *block_dev, lbaint_t start,
2387c4213f6SStephen Warren 		       lbaint_t blkcnt, void *dst)
239272cc70bSAndy Fleming {
2407c4213f6SStephen Warren 	int dev_num = block_dev->dev;
241873cc1d7SStephen Warren 	int err;
2424a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
243272cc70bSAndy Fleming 
2444a1a06bcSAlagu Sankar 	if (blkcnt == 0)
2454a1a06bcSAlagu Sankar 		return 0;
2464a1a06bcSAlagu Sankar 
2474a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
248272cc70bSAndy Fleming 	if (!mmc)
249272cc70bSAndy Fleming 		return 0;
250272cc70bSAndy Fleming 
251873cc1d7SStephen Warren 	err = mmc_select_hwpart(dev_num, block_dev->hwpart);
252873cc1d7SStephen Warren 	if (err < 0)
253873cc1d7SStephen Warren 		return 0;
254873cc1d7SStephen Warren 
255d2bf29e3SLei Wen 	if ((start + blkcnt) > mmc->block_dev.lba) {
25656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
257ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
258d2bf29e3SLei Wen 			start + blkcnt, mmc->block_dev.lba);
25956196826SPaul Burton #endif
260d2bf29e3SLei Wen 		return 0;
261d2bf29e3SLei Wen 	}
262272cc70bSAndy Fleming 
26311692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
26411692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
265272cc70bSAndy Fleming 		return 0;
26611692991SSimon Glass 	}
267272cc70bSAndy Fleming 
2684a1a06bcSAlagu Sankar 	do {
26993bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
27093bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
27111692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
27211692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
2734a1a06bcSAlagu Sankar 			return 0;
27411692991SSimon Glass 		}
2754a1a06bcSAlagu Sankar 		blocks_todo -= cur;
2764a1a06bcSAlagu Sankar 		start += cur;
2774a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
2784a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
279272cc70bSAndy Fleming 
280272cc70bSAndy Fleming 	return blkcnt;
281272cc70bSAndy Fleming }
282272cc70bSAndy Fleming 
283fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
284272cc70bSAndy Fleming {
285272cc70bSAndy Fleming 	struct mmc_cmd cmd;
286272cc70bSAndy Fleming 	int err;
287272cc70bSAndy Fleming 
288272cc70bSAndy Fleming 	udelay(1000);
289272cc70bSAndy Fleming 
290272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
291272cc70bSAndy Fleming 	cmd.cmdarg = 0;
292272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
293272cc70bSAndy Fleming 
294272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
295272cc70bSAndy Fleming 
296272cc70bSAndy Fleming 	if (err)
297272cc70bSAndy Fleming 		return err;
298272cc70bSAndy Fleming 
299272cc70bSAndy Fleming 	udelay(2000);
300272cc70bSAndy Fleming 
301272cc70bSAndy Fleming 	return 0;
302272cc70bSAndy Fleming }
303272cc70bSAndy Fleming 
304fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
305272cc70bSAndy Fleming {
306272cc70bSAndy Fleming 	int timeout = 1000;
307272cc70bSAndy Fleming 	int err;
308272cc70bSAndy Fleming 	struct mmc_cmd cmd;
309272cc70bSAndy Fleming 
3101677eef4SAndrew Gabbasov 	while (1) {
311272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
312272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
313272cc70bSAndy Fleming 		cmd.cmdarg = 0;
314272cc70bSAndy Fleming 
315272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
316272cc70bSAndy Fleming 
317272cc70bSAndy Fleming 		if (err)
318272cc70bSAndy Fleming 			return err;
319272cc70bSAndy Fleming 
320272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
321272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
322250de12bSStefano Babic 
323250de12bSStefano Babic 		/*
324250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
325250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
326250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
327250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
328250de12bSStefano Babic 		 * specified.
329250de12bSStefano Babic 		 */
330d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
33193bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
332272cc70bSAndy Fleming 
333272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
334272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
335272cc70bSAndy Fleming 
336272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
337272cc70bSAndy Fleming 
338272cc70bSAndy Fleming 		if (err)
339272cc70bSAndy Fleming 			return err;
340272cc70bSAndy Fleming 
3411677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
3421677eef4SAndrew Gabbasov 			break;
343272cc70bSAndy Fleming 
3441677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
345272cc70bSAndy Fleming 			return UNUSABLE_ERR;
346272cc70bSAndy Fleming 
3471677eef4SAndrew Gabbasov 		udelay(1000);
3481677eef4SAndrew Gabbasov 	}
3491677eef4SAndrew Gabbasov 
350272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
351272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
352272cc70bSAndy Fleming 
353d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
354d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
355d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
356d52ebf10SThomas Chou 		cmd.cmdarg = 0;
357d52ebf10SThomas Chou 
358d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
359d52ebf10SThomas Chou 
360d52ebf10SThomas Chou 		if (err)
361d52ebf10SThomas Chou 			return err;
362d52ebf10SThomas Chou 	}
363d52ebf10SThomas Chou 
364998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
365272cc70bSAndy Fleming 
366272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
367272cc70bSAndy Fleming 	mmc->rca = 0;
368272cc70bSAndy Fleming 
369272cc70bSAndy Fleming 	return 0;
370272cc70bSAndy Fleming }
371272cc70bSAndy Fleming 
3725289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
373272cc70bSAndy Fleming {
3745289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
375272cc70bSAndy Fleming 	int err;
376272cc70bSAndy Fleming 
3775289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
3785289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
3795289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
3805a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
3815a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
38293bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
383a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
384a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
385e9550449SChe-Liang Chiou 
3865289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
387e9550449SChe-Liang Chiou 	if (err)
388e9550449SChe-Liang Chiou 		return err;
3895289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
390e9550449SChe-Liang Chiou 	return 0;
391e9550449SChe-Liang Chiou }
392e9550449SChe-Liang Chiou 
393750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
394e9550449SChe-Liang Chiou {
395e9550449SChe-Liang Chiou 	int err, i;
396e9550449SChe-Liang Chiou 
397272cc70bSAndy Fleming 	/* Some cards seem to need this */
398272cc70bSAndy Fleming 	mmc_go_idle(mmc);
399272cc70bSAndy Fleming 
40031cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
401e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
4025289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
40331cacbabSRaffaele Recalcati 		if (err)
40431cacbabSRaffaele Recalcati 			return err;
40531cacbabSRaffaele Recalcati 
406e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
407a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
408bd47c135SAndrew Gabbasov 			break;
409e9550449SChe-Liang Chiou 	}
410bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
411bd47c135SAndrew Gabbasov 	return 0;
412e9550449SChe-Liang Chiou }
41331cacbabSRaffaele Recalcati 
414750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
415e9550449SChe-Liang Chiou {
416e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
417e9550449SChe-Liang Chiou 	int timeout = 1000;
418e9550449SChe-Liang Chiou 	uint start;
419e9550449SChe-Liang Chiou 	int err;
420e9550449SChe-Liang Chiou 
421e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
422cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
423e9550449SChe-Liang Chiou 		start = get_timer(0);
4241677eef4SAndrew Gabbasov 		while (1) {
4255289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
426272cc70bSAndy Fleming 			if (err)
427272cc70bSAndy Fleming 				return err;
4281677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
4291677eef4SAndrew Gabbasov 				break;
430e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
431272cc70bSAndy Fleming 				return UNUSABLE_ERR;
432e9550449SChe-Liang Chiou 			udelay(100);
4331677eef4SAndrew Gabbasov 		}
434cc17c01fSAndrew Gabbasov 	}
435272cc70bSAndy Fleming 
436d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
437d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
438d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
439d52ebf10SThomas Chou 		cmd.cmdarg = 0;
440d52ebf10SThomas Chou 
441d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
442d52ebf10SThomas Chou 
443d52ebf10SThomas Chou 		if (err)
444d52ebf10SThomas Chou 			return err;
445a626c8d4SAndrew Gabbasov 
446a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
447d52ebf10SThomas Chou 	}
448d52ebf10SThomas Chou 
449272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
450272cc70bSAndy Fleming 
451272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
452def816a2SStephen Warren 	mmc->rca = 1;
453272cc70bSAndy Fleming 
454272cc70bSAndy Fleming 	return 0;
455272cc70bSAndy Fleming }
456272cc70bSAndy Fleming 
457272cc70bSAndy Fleming 
458fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
459272cc70bSAndy Fleming {
460272cc70bSAndy Fleming 	struct mmc_cmd cmd;
461272cc70bSAndy Fleming 	struct mmc_data data;
462272cc70bSAndy Fleming 	int err;
463272cc70bSAndy Fleming 
464272cc70bSAndy Fleming 	/* Get the Card Status Register */
465272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
466272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
467272cc70bSAndy Fleming 	cmd.cmdarg = 0;
468272cc70bSAndy Fleming 
469cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
470272cc70bSAndy Fleming 	data.blocks = 1;
4718bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
472272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
473272cc70bSAndy Fleming 
474272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
475272cc70bSAndy Fleming 
476272cc70bSAndy Fleming 	return err;
477272cc70bSAndy Fleming }
478272cc70bSAndy Fleming 
479272cc70bSAndy Fleming 
480fdbb873eSKim Phillips static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
481272cc70bSAndy Fleming {
482272cc70bSAndy Fleming 	struct mmc_cmd cmd;
4835d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
4845d4fc8d9SRaffaele Recalcati 	int ret;
485272cc70bSAndy Fleming 
486272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
487272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
488272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
489272cc70bSAndy Fleming 				 (index << 16) |
490272cc70bSAndy Fleming 				 (value << 8);
491272cc70bSAndy Fleming 
4925d4fc8d9SRaffaele Recalcati 	ret = mmc_send_cmd(mmc, &cmd, NULL);
4935d4fc8d9SRaffaele Recalcati 
4945d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
49593ad0d18SJan Kloetzke 	if (!ret)
49693ad0d18SJan Kloetzke 		ret = mmc_send_status(mmc, timeout);
4975d4fc8d9SRaffaele Recalcati 
4985d4fc8d9SRaffaele Recalcati 	return ret;
4995d4fc8d9SRaffaele Recalcati 
500272cc70bSAndy Fleming }
501272cc70bSAndy Fleming 
502fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
503272cc70bSAndy Fleming {
5048bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
505272cc70bSAndy Fleming 	char cardtype;
506272cc70bSAndy Fleming 	int err;
507272cc70bSAndy Fleming 
508fc5b32fbSAndrew Gabbasov 	mmc->card_caps = 0;
509272cc70bSAndy Fleming 
510d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
511d52ebf10SThomas Chou 		return 0;
512d52ebf10SThomas Chou 
513272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
514272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
515272cc70bSAndy Fleming 		return 0;
516272cc70bSAndy Fleming 
517fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
518fc5b32fbSAndrew Gabbasov 
519272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
520272cc70bSAndy Fleming 
521272cc70bSAndy Fleming 	if (err)
522272cc70bSAndy Fleming 		return err;
523272cc70bSAndy Fleming 
5240560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
525272cc70bSAndy Fleming 
526272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
527272cc70bSAndy Fleming 
528272cc70bSAndy Fleming 	if (err)
5296b2221b0SAndrew Gabbasov 		return err == SWITCH_ERR ? 0 : err;
530272cc70bSAndy Fleming 
531272cc70bSAndy Fleming 	/* Now check to see that it worked */
532272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
533272cc70bSAndy Fleming 
534272cc70bSAndy Fleming 	if (err)
535272cc70bSAndy Fleming 		return err;
536272cc70bSAndy Fleming 
537272cc70bSAndy Fleming 	/* No high-speed support */
5380560db18SLei Wen 	if (!ext_csd[EXT_CSD_HS_TIMING])
539272cc70bSAndy Fleming 		return 0;
540272cc70bSAndy Fleming 
541272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
542d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
543201d5ac4SAndrew Gabbasov 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
544d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
545272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
546d22e3d46SJaehoon Chung 	} else {
547272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
548d22e3d46SJaehoon Chung 	}
549272cc70bSAndy Fleming 
550272cc70bSAndy Fleming 	return 0;
551272cc70bSAndy Fleming }
552272cc70bSAndy Fleming 
553f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
554f866a46dSStephen Warren {
555f866a46dSStephen Warren 	switch (part_num) {
556f866a46dSStephen Warren 	case 0:
557f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
558f866a46dSStephen Warren 		break;
559f866a46dSStephen Warren 	case 1:
560f866a46dSStephen Warren 	case 2:
561f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
562f866a46dSStephen Warren 		break;
563f866a46dSStephen Warren 	case 3:
564f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
565f866a46dSStephen Warren 		break;
566f866a46dSStephen Warren 	case 4:
567f866a46dSStephen Warren 	case 5:
568f866a46dSStephen Warren 	case 6:
569f866a46dSStephen Warren 	case 7:
570f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
571f866a46dSStephen Warren 		break;
572f866a46dSStephen Warren 	default:
573f866a46dSStephen Warren 		return -1;
574f866a46dSStephen Warren 	}
575f866a46dSStephen Warren 
576f866a46dSStephen Warren 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
577f866a46dSStephen Warren 
578f866a46dSStephen Warren 	return 0;
579f866a46dSStephen Warren }
580f866a46dSStephen Warren 
581d2356284SStephen Warren int mmc_select_hwpart(int dev_num, int hwpart)
582d2356284SStephen Warren {
583d2356284SStephen Warren 	struct mmc *mmc = find_mmc_device(dev_num);
584d2356284SStephen Warren 	int ret;
585d2356284SStephen Warren 
586d2356284SStephen Warren 	if (!mmc)
587d4622df3SStephen Warren 		return -ENODEV;
588d2356284SStephen Warren 
589873cc1d7SStephen Warren 	if (mmc->block_dev.hwpart == hwpart)
590d2356284SStephen Warren 		return 0;
591d2356284SStephen Warren 
592d2356284SStephen Warren 	if (mmc->part_config == MMCPART_NOAVAILABLE) {
593d2356284SStephen Warren 		printf("Card doesn't support part_switch\n");
594d4622df3SStephen Warren 		return -EMEDIUMTYPE;
595d2356284SStephen Warren 	}
596d2356284SStephen Warren 
597d2356284SStephen Warren 	ret = mmc_switch_part(dev_num, hwpart);
598d2356284SStephen Warren 	if (ret)
599d4622df3SStephen Warren 		return ret;
600d2356284SStephen Warren 
601d2356284SStephen Warren 	return 0;
602d2356284SStephen Warren }
603d2356284SStephen Warren 
604d2356284SStephen Warren 
605bc897b1dSLei Wen int mmc_switch_part(int dev_num, unsigned int part_num)
606bc897b1dSLei Wen {
607bc897b1dSLei Wen 	struct mmc *mmc = find_mmc_device(dev_num);
608f866a46dSStephen Warren 	int ret;
609bc897b1dSLei Wen 
610bc897b1dSLei Wen 	if (!mmc)
611bc897b1dSLei Wen 		return -1;
612bc897b1dSLei Wen 
613f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
614bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
615bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
616f866a46dSStephen Warren 
6176dc93e70SPeter Bigot 	/*
6186dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
6196dc93e70SPeter Bigot 	 * to return to representing the raw device.
6206dc93e70SPeter Bigot 	 */
621873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
6226dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
623873cc1d7SStephen Warren 		mmc->block_dev.hwpart = part_num;
624873cc1d7SStephen Warren 	}
6256dc93e70SPeter Bigot 
6266dc93e70SPeter Bigot 	return ret;
627bc897b1dSLei Wen }
628bc897b1dSLei Wen 
629ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
630ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
631ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
632ac9da0e0SDiego Santa Cruz {
633ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
634ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
635ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
636ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
637ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
638ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
6398dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
640ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
641ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
642ac9da0e0SDiego Santa Cruz 
643ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
644ac9da0e0SDiego Santa Cruz 		return -EINVAL;
645ac9da0e0SDiego Santa Cruz 
646ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
647ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
648ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
649ac9da0e0SDiego Santa Cruz 	}
650ac9da0e0SDiego Santa Cruz 
651ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
652ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
653ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
654ac9da0e0SDiego Santa Cruz 	}
655ac9da0e0SDiego Santa Cruz 
656ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
657ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
658ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
659ac9da0e0SDiego Santa Cruz 	}
660ac9da0e0SDiego Santa Cruz 
661ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
662ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
663ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
664ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
665ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
666ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
667ac9da0e0SDiego Santa Cruz 			return -EINVAL;
668ac9da0e0SDiego Santa Cruz 		}
669ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
670ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
671ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
672ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
673ac9da0e0SDiego Santa Cruz 		} else {
674ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
675ac9da0e0SDiego Santa Cruz 		}
676ac9da0e0SDiego Santa Cruz 	} else {
677ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
678ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
679ac9da0e0SDiego Santa Cruz 	}
680ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
681ac9da0e0SDiego Santa Cruz 
682ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
683ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
684ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
685ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
686ac9da0e0SDiego Santa Cruz 			return -EINVAL;
687ac9da0e0SDiego Santa Cruz 		}
688ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
689ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
690ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
691ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
692ac9da0e0SDiego Santa Cruz 		}
693ac9da0e0SDiego Santa Cruz 	}
694ac9da0e0SDiego Santa Cruz 
695ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
696ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
697ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
698ac9da0e0SDiego Santa Cruz 	}
699ac9da0e0SDiego Santa Cruz 
700ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
701ac9da0e0SDiego Santa Cruz 	if (err)
702ac9da0e0SDiego Santa Cruz 		return err;
703ac9da0e0SDiego Santa Cruz 
704ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
705ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
706ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
707ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
708ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
709ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
710ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
711ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
712ac9da0e0SDiego Santa Cruz 	}
713ac9da0e0SDiego Santa Cruz 
7148dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
7158dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
7168dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
7178dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
7188dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
7198dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
7208dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
7218dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
7228dda5b0eSDiego Santa Cruz 		else
7238dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
7248dda5b0eSDiego Santa Cruz 	}
7258dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
7268dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
7278dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
7288dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
7298dda5b0eSDiego Santa Cruz 			else
7308dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
7318dda5b0eSDiego Santa Cruz 		}
7328dda5b0eSDiego Santa Cruz 	}
7338dda5b0eSDiego Santa Cruz 
7348dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
7358dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
7368dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
7378dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
7388dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
7398dda5b0eSDiego Santa Cruz 	}
7408dda5b0eSDiego Santa Cruz 
741ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
742ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
743ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
744ac9da0e0SDiego Santa Cruz 		return -EPERM;
745ac9da0e0SDiego Santa Cruz 	}
746ac9da0e0SDiego Santa Cruz 
747ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
748ac9da0e0SDiego Santa Cruz 		return 0;
749ac9da0e0SDiego Santa Cruz 
750ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
751ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
752ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
753ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
754ac9da0e0SDiego Santa Cruz 
755ac9da0e0SDiego Santa Cruz 		if (err)
756ac9da0e0SDiego Santa Cruz 			return err;
757ac9da0e0SDiego Santa Cruz 
758ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
759ac9da0e0SDiego Santa Cruz 
760ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
761ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
762ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
763ac9da0e0SDiego Santa Cruz 
764ac9da0e0SDiego Santa Cruz 	}
765ac9da0e0SDiego Santa Cruz 
766ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
767ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
768ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
769ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
770ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
771ac9da0e0SDiego Santa Cruz 		if (err)
772ac9da0e0SDiego Santa Cruz 			return err;
773ac9da0e0SDiego Santa Cruz 	}
774ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
775ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
776ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
777ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
778ac9da0e0SDiego Santa Cruz 		if (err)
779ac9da0e0SDiego Santa Cruz 			return err;
780ac9da0e0SDiego Santa Cruz 	}
781ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
782ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
783ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
784ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
785ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
786ac9da0e0SDiego Santa Cruz 			if (err)
787ac9da0e0SDiego Santa Cruz 				return err;
788ac9da0e0SDiego Santa Cruz 		}
789ac9da0e0SDiego Santa Cruz 	}
790ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
791ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
792ac9da0e0SDiego Santa Cruz 	if (err)
793ac9da0e0SDiego Santa Cruz 		return err;
794ac9da0e0SDiego Santa Cruz 
795ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
796ac9da0e0SDiego Santa Cruz 		return 0;
797ac9da0e0SDiego Santa Cruz 
7988dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
7998dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
8008dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
8018dda5b0eSDiego Santa Cruz 	 * partitioning. */
8028dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
8038dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
8048dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
8058dda5b0eSDiego Santa Cruz 		if (err)
8068dda5b0eSDiego Santa Cruz 			return err;
8078dda5b0eSDiego Santa Cruz 	}
8088dda5b0eSDiego Santa Cruz 
809ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
810ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
811ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
812ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
813ac9da0e0SDiego Santa Cruz 
814ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
815ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
816ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
817ac9da0e0SDiego Santa Cruz 	if (err)
818ac9da0e0SDiego Santa Cruz 		return err;
819ac9da0e0SDiego Santa Cruz 
820ac9da0e0SDiego Santa Cruz 	return 0;
821ac9da0e0SDiego Santa Cruz }
822ac9da0e0SDiego Santa Cruz 
82348972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
82448972d90SThierry Reding {
82548972d90SThierry Reding 	int cd;
82648972d90SThierry Reding 
82748972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
82848972d90SThierry Reding 
829d4e1da4eSPeter Korsgaard 	if (cd < 0) {
83093bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
83193bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
832d4e1da4eSPeter Korsgaard 		else
833d4e1da4eSPeter Korsgaard 			cd = 1;
834d4e1da4eSPeter Korsgaard 	}
83548972d90SThierry Reding 
83648972d90SThierry Reding 	return cd;
83748972d90SThierry Reding }
83848972d90SThierry Reding 
839fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
840272cc70bSAndy Fleming {
841272cc70bSAndy Fleming 	struct mmc_cmd cmd;
842272cc70bSAndy Fleming 	struct mmc_data data;
843272cc70bSAndy Fleming 
844272cc70bSAndy Fleming 	/* Switch the frequency */
845272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
846272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
847272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
848272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
849272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
850272cc70bSAndy Fleming 
851272cc70bSAndy Fleming 	data.dest = (char *)resp;
852272cc70bSAndy Fleming 	data.blocksize = 64;
853272cc70bSAndy Fleming 	data.blocks = 1;
854272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
855272cc70bSAndy Fleming 
856272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
857272cc70bSAndy Fleming }
858272cc70bSAndy Fleming 
859272cc70bSAndy Fleming 
860fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
861272cc70bSAndy Fleming {
862272cc70bSAndy Fleming 	int err;
863272cc70bSAndy Fleming 	struct mmc_cmd cmd;
864f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
865f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
866272cc70bSAndy Fleming 	struct mmc_data data;
867272cc70bSAndy Fleming 	int timeout;
868272cc70bSAndy Fleming 
869272cc70bSAndy Fleming 	mmc->card_caps = 0;
870272cc70bSAndy Fleming 
871d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
872d52ebf10SThomas Chou 		return 0;
873d52ebf10SThomas Chou 
874272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
875272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
876272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
877272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
878272cc70bSAndy Fleming 
879272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
880272cc70bSAndy Fleming 
881272cc70bSAndy Fleming 	if (err)
882272cc70bSAndy Fleming 		return err;
883272cc70bSAndy Fleming 
884272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
885272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
886272cc70bSAndy Fleming 	cmd.cmdarg = 0;
887272cc70bSAndy Fleming 
888272cc70bSAndy Fleming 	timeout = 3;
889272cc70bSAndy Fleming 
890272cc70bSAndy Fleming retry_scr:
891f781dd38SAnton staaf 	data.dest = (char *)scr;
892272cc70bSAndy Fleming 	data.blocksize = 8;
893272cc70bSAndy Fleming 	data.blocks = 1;
894272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
895272cc70bSAndy Fleming 
896272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
897272cc70bSAndy Fleming 
898272cc70bSAndy Fleming 	if (err) {
899272cc70bSAndy Fleming 		if (timeout--)
900272cc70bSAndy Fleming 			goto retry_scr;
901272cc70bSAndy Fleming 
902272cc70bSAndy Fleming 		return err;
903272cc70bSAndy Fleming 	}
904272cc70bSAndy Fleming 
9054e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
9064e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
907272cc70bSAndy Fleming 
908272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
909272cc70bSAndy Fleming 		case 0:
910272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
911272cc70bSAndy Fleming 			break;
912272cc70bSAndy Fleming 		case 1:
913272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_10;
914272cc70bSAndy Fleming 			break;
915272cc70bSAndy Fleming 		case 2:
916272cc70bSAndy Fleming 			mmc->version = SD_VERSION_2;
9171741c64dSJaehoon Chung 			if ((mmc->scr[0] >> 15) & 0x1)
9181741c64dSJaehoon Chung 				mmc->version = SD_VERSION_3;
919272cc70bSAndy Fleming 			break;
920272cc70bSAndy Fleming 		default:
921272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
922272cc70bSAndy Fleming 			break;
923272cc70bSAndy Fleming 	}
924272cc70bSAndy Fleming 
925b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
926b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
927b44c7083SAlagu Sankar 
928272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
929272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
930272cc70bSAndy Fleming 		return 0;
931272cc70bSAndy Fleming 
932272cc70bSAndy Fleming 	timeout = 4;
933272cc70bSAndy Fleming 	while (timeout--) {
934272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
935f781dd38SAnton staaf 				(u8 *)switch_status);
936272cc70bSAndy Fleming 
937272cc70bSAndy Fleming 		if (err)
938272cc70bSAndy Fleming 			return err;
939272cc70bSAndy Fleming 
940272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
9414e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
942272cc70bSAndy Fleming 			break;
943272cc70bSAndy Fleming 	}
944272cc70bSAndy Fleming 
945272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
9464e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
947272cc70bSAndy Fleming 		return 0;
948272cc70bSAndy Fleming 
9492c3fbf4cSMacpaul Lin 	/*
9502c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
9512c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
9522c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
9532c3fbf4cSMacpaul Lin 	 * mode between the host.
9542c3fbf4cSMacpaul Lin 	 */
95593bfd616SPantelis Antoniou 	if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
95693bfd616SPantelis Antoniou 		(mmc->cfg->host_caps & MMC_MODE_HS)))
9572c3fbf4cSMacpaul Lin 		return 0;
9582c3fbf4cSMacpaul Lin 
959f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
960272cc70bSAndy Fleming 
961272cc70bSAndy Fleming 	if (err)
962272cc70bSAndy Fleming 		return err;
963272cc70bSAndy Fleming 
9644e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
965272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
966272cc70bSAndy Fleming 
967272cc70bSAndy Fleming 	return 0;
968272cc70bSAndy Fleming }
969272cc70bSAndy Fleming 
970272cc70bSAndy Fleming /* frequency bases */
971272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
9725f837c2cSMike Frysinger static const int fbase[] = {
973272cc70bSAndy Fleming 	10000,
974272cc70bSAndy Fleming 	100000,
975272cc70bSAndy Fleming 	1000000,
976272cc70bSAndy Fleming 	10000000,
977272cc70bSAndy Fleming };
978272cc70bSAndy Fleming 
979272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
980272cc70bSAndy Fleming  * to platforms without floating point.
981272cc70bSAndy Fleming  */
9825f837c2cSMike Frysinger static const int multipliers[] = {
983272cc70bSAndy Fleming 	0,	/* reserved */
984272cc70bSAndy Fleming 	10,
985272cc70bSAndy Fleming 	12,
986272cc70bSAndy Fleming 	13,
987272cc70bSAndy Fleming 	15,
988272cc70bSAndy Fleming 	20,
989272cc70bSAndy Fleming 	25,
990272cc70bSAndy Fleming 	30,
991272cc70bSAndy Fleming 	35,
992272cc70bSAndy Fleming 	40,
993272cc70bSAndy Fleming 	45,
994272cc70bSAndy Fleming 	50,
995272cc70bSAndy Fleming 	55,
996272cc70bSAndy Fleming 	60,
997272cc70bSAndy Fleming 	70,
998272cc70bSAndy Fleming 	80,
999272cc70bSAndy Fleming };
1000272cc70bSAndy Fleming 
1001fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
1002272cc70bSAndy Fleming {
100393bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
100493bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
1005272cc70bSAndy Fleming }
1006272cc70bSAndy Fleming 
1007272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
1008272cc70bSAndy Fleming {
100993bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
101093bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1011272cc70bSAndy Fleming 
101293bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
101393bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1014272cc70bSAndy Fleming 
1015272cc70bSAndy Fleming 	mmc->clock = clock;
1016272cc70bSAndy Fleming 
1017272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1018272cc70bSAndy Fleming }
1019272cc70bSAndy Fleming 
1020fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width)
1021272cc70bSAndy Fleming {
1022272cc70bSAndy Fleming 	mmc->bus_width = width;
1023272cc70bSAndy Fleming 
1024272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1025272cc70bSAndy Fleming }
1026272cc70bSAndy Fleming 
1027fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1028272cc70bSAndy Fleming {
1029f866a46dSStephen Warren 	int err, i;
1030272cc70bSAndy Fleming 	uint mult, freq;
1031639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
1032272cc70bSAndy Fleming 	struct mmc_cmd cmd;
10338bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
10348bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
10355d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
10360c453bb7SDiego Santa Cruz 	bool has_parts = false;
10378a0cf490SDiego Santa Cruz 	bool part_completed;
1038272cc70bSAndy Fleming 
1039d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1040d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1041d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1042d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1043d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1044d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1045d52ebf10SThomas Chou 
1046d52ebf10SThomas Chou 		if (err)
1047d52ebf10SThomas Chou 			return err;
1048d52ebf10SThomas Chou 	}
1049d52ebf10SThomas Chou #endif
1050d52ebf10SThomas Chou 
1051272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1052d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1053d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1054272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1055272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1056272cc70bSAndy Fleming 
1057272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1058272cc70bSAndy Fleming 
1059272cc70bSAndy Fleming 	if (err)
1060272cc70bSAndy Fleming 		return err;
1061272cc70bSAndy Fleming 
1062272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1063272cc70bSAndy Fleming 
1064272cc70bSAndy Fleming 	/*
1065272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1066272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1067272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1068272cc70bSAndy Fleming 	 */
1069d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1070272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1071272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1072272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1073272cc70bSAndy Fleming 
1074272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1075272cc70bSAndy Fleming 
1076272cc70bSAndy Fleming 		if (err)
1077272cc70bSAndy Fleming 			return err;
1078272cc70bSAndy Fleming 
1079272cc70bSAndy Fleming 		if (IS_SD(mmc))
1080998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1081d52ebf10SThomas Chou 	}
1082272cc70bSAndy Fleming 
1083272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1084272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1085272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1086272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1087272cc70bSAndy Fleming 
1088272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1089272cc70bSAndy Fleming 
10905d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
10915d4fc8d9SRaffaele Recalcati 	mmc_send_status(mmc, timeout);
10925d4fc8d9SRaffaele Recalcati 
1093272cc70bSAndy Fleming 	if (err)
1094272cc70bSAndy Fleming 		return err;
1095272cc70bSAndy Fleming 
1096998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1097998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1098998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1099998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1100272cc70bSAndy Fleming 
1101272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
11020b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1103272cc70bSAndy Fleming 
1104272cc70bSAndy Fleming 		switch (version) {
1105272cc70bSAndy Fleming 			case 0:
1106272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
1107272cc70bSAndy Fleming 				break;
1108272cc70bSAndy Fleming 			case 1:
1109272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_4;
1110272cc70bSAndy Fleming 				break;
1111272cc70bSAndy Fleming 			case 2:
1112272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_2_2;
1113272cc70bSAndy Fleming 				break;
1114272cc70bSAndy Fleming 			case 3:
1115272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_3;
1116272cc70bSAndy Fleming 				break;
1117272cc70bSAndy Fleming 			case 4:
1118272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_4;
1119272cc70bSAndy Fleming 				break;
1120272cc70bSAndy Fleming 			default:
1121272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
1122272cc70bSAndy Fleming 				break;
1123272cc70bSAndy Fleming 		}
1124272cc70bSAndy Fleming 	}
1125272cc70bSAndy Fleming 
1126272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
11270b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
11280b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1129272cc70bSAndy Fleming 
1130272cc70bSAndy Fleming 	mmc->tran_speed = freq * mult;
1131272cc70bSAndy Fleming 
1132ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1133998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1134272cc70bSAndy Fleming 
1135272cc70bSAndy Fleming 	if (IS_SD(mmc))
1136272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1137272cc70bSAndy Fleming 	else
1138998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1139272cc70bSAndy Fleming 
1140272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1141272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1142272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1143272cc70bSAndy Fleming 		cmult = 8;
1144272cc70bSAndy Fleming 	} else {
1145272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1146272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1147272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1148272cc70bSAndy Fleming 	}
1149272cc70bSAndy Fleming 
1150f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1151f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1152f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1153f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1154f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1155f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1156272cc70bSAndy Fleming 
11578bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
11588bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1159272cc70bSAndy Fleming 
11608bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
11618bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1162272cc70bSAndy Fleming 
1163ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1164ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1165ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1166ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1167ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1168ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1169ab71188cSMarkus Niebel 	}
1170ab71188cSMarkus Niebel 
1171272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1172d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1173272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1174fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1175272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1176272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1177272cc70bSAndy Fleming 
1178272cc70bSAndy Fleming 		if (err)
1179272cc70bSAndy Fleming 			return err;
1180d52ebf10SThomas Chou 	}
1181272cc70bSAndy Fleming 
1182e6f99a56SLei Wen 	/*
1183e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1184e6f99a56SLei Wen 	 */
1185e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1186bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1187d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
1188d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
1189d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
11909cf199ebSDiego Santa Cruz 		if (err)
11919cf199ebSDiego Santa Cruz 			return err;
11929cf199ebSDiego Santa Cruz 		if (ext_csd[EXT_CSD_REV] >= 2) {
1193639b7827SYoshihiro Shimoda 			/*
1194639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
1195639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
1196639b7827SYoshihiro Shimoda 			 * than 2GB
1197639b7827SYoshihiro Shimoda 			 */
11980560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
11990560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
12000560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
12010560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
12028bfa195eSSimon Glass 			capacity *= MMC_MAX_BLOCK_LEN;
1203b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
1204f866a46dSStephen Warren 				mmc->capacity_user = capacity;
1205d23e2c09SSukumar Ghorai 		}
1206bc897b1dSLei Wen 
120764f4a619SJaehoon Chung 		switch (ext_csd[EXT_CSD_REV]) {
120864f4a619SJaehoon Chung 		case 1:
120964f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_1;
121064f4a619SJaehoon Chung 			break;
121164f4a619SJaehoon Chung 		case 2:
121264f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_2;
121364f4a619SJaehoon Chung 			break;
121464f4a619SJaehoon Chung 		case 3:
121564f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_3;
121664f4a619SJaehoon Chung 			break;
121764f4a619SJaehoon Chung 		case 5:
121864f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_41;
121964f4a619SJaehoon Chung 			break;
122064f4a619SJaehoon Chung 		case 6:
122164f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_5;
122264f4a619SJaehoon Chung 			break;
1223edab723bSMarkus Niebel 		case 7:
1224edab723bSMarkus Niebel 			mmc->version = MMC_VERSION_5_0;
1225edab723bSMarkus Niebel 			break;
122664f4a619SJaehoon Chung 		}
122764f4a619SJaehoon Chung 
12288a0cf490SDiego Santa Cruz 		/* The partition data may be non-zero but it is only
12298a0cf490SDiego Santa Cruz 		 * effective if PARTITION_SETTING_COMPLETED is set in
12308a0cf490SDiego Santa Cruz 		 * EXT_CSD, so ignore any data if this bit is not set,
12318a0cf490SDiego Santa Cruz 		 * except for enabling the high-capacity group size
12328a0cf490SDiego Santa Cruz 		 * definition (see below). */
12338a0cf490SDiego Santa Cruz 		part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
12348a0cf490SDiego Santa Cruz 				    EXT_CSD_PARTITION_SETTING_COMPLETED);
12358a0cf490SDiego Santa Cruz 
12360c453bb7SDiego Santa Cruz 		/* store the partition info of emmc */
12370c453bb7SDiego Santa Cruz 		mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
12380c453bb7SDiego Santa Cruz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
12390c453bb7SDiego Santa Cruz 		    ext_csd[EXT_CSD_BOOT_MULT])
12400c453bb7SDiego Santa Cruz 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
12418a0cf490SDiego Santa Cruz 		if (part_completed &&
12428a0cf490SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
12430c453bb7SDiego Santa Cruz 			mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
12440c453bb7SDiego Santa Cruz 
12450c453bb7SDiego Santa Cruz 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
12460c453bb7SDiego Santa Cruz 
12470c453bb7SDiego Santa Cruz 		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
12480c453bb7SDiego Santa Cruz 
12490c453bb7SDiego Santa Cruz 		for (i = 0; i < 4; i++) {
12500c453bb7SDiego Santa Cruz 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
12518a0cf490SDiego Santa Cruz 			uint mult = (ext_csd[idx + 2] << 16) +
12520c453bb7SDiego Santa Cruz 				(ext_csd[idx + 1] << 8) + ext_csd[idx];
12538a0cf490SDiego Santa Cruz 			if (mult)
12548a0cf490SDiego Santa Cruz 				has_parts = true;
12558a0cf490SDiego Santa Cruz 			if (!part_completed)
12568a0cf490SDiego Santa Cruz 				continue;
12578a0cf490SDiego Santa Cruz 			mmc->capacity_gp[i] = mult;
12580c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *=
12590c453bb7SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
12600c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1261f8e89d67SDiego Santa Cruz 			mmc->capacity_gp[i] <<= 19;
12620c453bb7SDiego Santa Cruz 		}
12630c453bb7SDiego Santa Cruz 
12648a0cf490SDiego Santa Cruz 		if (part_completed) {
1265a7f852b6SDiego Santa Cruz 			mmc->enh_user_size =
1266a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
1267a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
1268a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_SIZE_MULT];
1269a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1270a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1271a7f852b6SDiego Santa Cruz 			mmc->enh_user_size <<= 19;
1272a7f852b6SDiego Santa Cruz 			mmc->enh_user_start =
1273a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
1274a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
1275a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
1276a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_START_ADDR];
1277a7f852b6SDiego Santa Cruz 			if (mmc->high_capacity)
1278a7f852b6SDiego Santa Cruz 				mmc->enh_user_start <<= 9;
12798a0cf490SDiego Santa Cruz 		}
1280a7f852b6SDiego Santa Cruz 
1281e6f99a56SLei Wen 		/*
12821937e5aaSOliver Metz 		 * Host needs to enable ERASE_GRP_DEF bit if device is
12831937e5aaSOliver Metz 		 * partitioned. This bit will be lost every time after a reset
12841937e5aaSOliver Metz 		 * or power off. This will affect erase size.
1285e6f99a56SLei Wen 		 */
12868a0cf490SDiego Santa Cruz 		if (part_completed)
12870c453bb7SDiego Santa Cruz 			has_parts = true;
12881937e5aaSOliver Metz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
12890c453bb7SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
12900c453bb7SDiego Santa Cruz 			has_parts = true;
12910c453bb7SDiego Santa Cruz 		if (has_parts) {
12921937e5aaSOliver Metz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
12931937e5aaSOliver Metz 				EXT_CSD_ERASE_GROUP_DEF, 1);
12941937e5aaSOliver Metz 
12951937e5aaSOliver Metz 			if (err)
12961937e5aaSOliver Metz 				return err;
1297021a8055SHannes Petermaier 			else
1298021a8055SHannes Petermaier 				ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1299037dc0abSDiego Santa Cruz 		}
13001937e5aaSOliver Metz 
1301037dc0abSDiego Santa Cruz 		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
13021937e5aaSOliver Metz 			/* Read out group size from ext_csd */
13030560db18SLei Wen 			mmc->erase_grp_size =
1304a4ff9f83SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1305d7b29129SMarkus Niebel 			/*
1306d7b29129SMarkus Niebel 			 * if high capacity and partition setting completed
1307d7b29129SMarkus Niebel 			 * SEC_COUNT is valid even if it is smaller than 2 GiB
1308d7b29129SMarkus Niebel 			 * JEDEC Standard JESD84-B45, 6.2.4
1309d7b29129SMarkus Niebel 			 */
13108a0cf490SDiego Santa Cruz 			if (mmc->high_capacity && part_completed) {
1311d7b29129SMarkus Niebel 				capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1312d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1313d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1314d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1315d7b29129SMarkus Niebel 				capacity *= MMC_MAX_BLOCK_LEN;
1316d7b29129SMarkus Niebel 				mmc->capacity_user = capacity;
1317d7b29129SMarkus Niebel 			}
13188bfa195eSSimon Glass 		} else {
13191937e5aaSOliver Metz 			/* Calculate the group size from the csd value. */
1320e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
1321e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1322e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1323e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
1324e6f99a56SLei Wen 				* (erase_gmul + 1);
1325e6f99a56SLei Wen 		}
1326037dc0abSDiego Santa Cruz 
1327037dc0abSDiego Santa Cruz 		mmc->hc_wp_grp_size = 1024
1328037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1329037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
13309e41a00bSDiego Santa Cruz 
13319e41a00bSDiego Santa Cruz 		mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1332f866a46dSStephen Warren 	}
1333f866a46dSStephen Warren 
1334873cc1d7SStephen Warren 	err = mmc_set_capacity(mmc, mmc->block_dev.hwpart);
1335f866a46dSStephen Warren 	if (err)
1336f866a46dSStephen Warren 		return err;
1337d23e2c09SSukumar Ghorai 
1338272cc70bSAndy Fleming 	if (IS_SD(mmc))
1339272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1340272cc70bSAndy Fleming 	else
1341272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1342272cc70bSAndy Fleming 
1343272cc70bSAndy Fleming 	if (err)
1344272cc70bSAndy Fleming 		return err;
1345272cc70bSAndy Fleming 
1346272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
134793bfd616SPantelis Antoniou 	mmc->card_caps &= mmc->cfg->host_caps;
1348272cc70bSAndy Fleming 
1349272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1350272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1351272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1352272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1353272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1354272cc70bSAndy Fleming 
1355272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1356272cc70bSAndy Fleming 			if (err)
1357272cc70bSAndy Fleming 				return err;
1358272cc70bSAndy Fleming 
1359272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1360272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1361272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1362272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1363272cc70bSAndy Fleming 			if (err)
1364272cc70bSAndy Fleming 				return err;
1365272cc70bSAndy Fleming 
1366272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1367272cc70bSAndy Fleming 		}
1368272cc70bSAndy Fleming 
1369272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
1370ad5fd922SJaehoon Chung 			mmc->tran_speed = 50000000;
1371272cc70bSAndy Fleming 		else
1372ad5fd922SJaehoon Chung 			mmc->tran_speed = 25000000;
1373fc5b32fbSAndrew Gabbasov 	} else if (mmc->version >= MMC_VERSION_4) {
1374fc5b32fbSAndrew Gabbasov 		/* Only version 4 of MMC supports wider bus widths */
13757798f6dbSAndy Fleming 		int idx;
13767798f6dbSAndy Fleming 
13777798f6dbSAndy Fleming 		/* An array of possible bus widths in order of preference */
13787798f6dbSAndy Fleming 		static unsigned ext_csd_bits[] = {
1379d22e3d46SJaehoon Chung 			EXT_CSD_DDR_BUS_WIDTH_8,
1380d22e3d46SJaehoon Chung 			EXT_CSD_DDR_BUS_WIDTH_4,
13817798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_8,
13827798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_4,
13837798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_1,
13847798f6dbSAndy Fleming 		};
13857798f6dbSAndy Fleming 
13867798f6dbSAndy Fleming 		/* An array to map CSD bus widths to host cap bits */
13877798f6dbSAndy Fleming 		static unsigned ext_to_hostcaps[] = {
1388786e8f81SAndrew Gabbasov 			[EXT_CSD_DDR_BUS_WIDTH_4] =
1389786e8f81SAndrew Gabbasov 				MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
1390786e8f81SAndrew Gabbasov 			[EXT_CSD_DDR_BUS_WIDTH_8] =
1391786e8f81SAndrew Gabbasov 				MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
13927798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
13937798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
13947798f6dbSAndy Fleming 		};
13957798f6dbSAndy Fleming 
13967798f6dbSAndy Fleming 		/* An array to map chosen bus width to an integer */
13977798f6dbSAndy Fleming 		static unsigned widths[] = {
1398d22e3d46SJaehoon Chung 			8, 4, 8, 4, 1,
13997798f6dbSAndy Fleming 		};
14007798f6dbSAndy Fleming 
14017798f6dbSAndy Fleming 		for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
14027798f6dbSAndy Fleming 			unsigned int extw = ext_csd_bits[idx];
1403786e8f81SAndrew Gabbasov 			unsigned int caps = ext_to_hostcaps[extw];
14047798f6dbSAndy Fleming 
14057798f6dbSAndy Fleming 			/*
1406bf477073SAndrew Gabbasov 			 * If the bus width is still not changed,
1407bf477073SAndrew Gabbasov 			 * don't try to set the default again.
1408bf477073SAndrew Gabbasov 			 * Otherwise, recover from switch attempts
1409bf477073SAndrew Gabbasov 			 * by switching to 1-bit bus width.
1410bf477073SAndrew Gabbasov 			 */
1411bf477073SAndrew Gabbasov 			if (extw == EXT_CSD_BUS_WIDTH_1 &&
1412bf477073SAndrew Gabbasov 					mmc->bus_width == 1) {
1413bf477073SAndrew Gabbasov 				err = 0;
1414bf477073SAndrew Gabbasov 				break;
1415bf477073SAndrew Gabbasov 			}
1416bf477073SAndrew Gabbasov 
1417bf477073SAndrew Gabbasov 			/*
1418786e8f81SAndrew Gabbasov 			 * Check to make sure the card and controller support
1419786e8f81SAndrew Gabbasov 			 * these capabilities
14207798f6dbSAndy Fleming 			 */
1421786e8f81SAndrew Gabbasov 			if ((mmc->card_caps & caps) != caps)
14227798f6dbSAndy Fleming 				continue;
14237798f6dbSAndy Fleming 
1424272cc70bSAndy Fleming 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
14257798f6dbSAndy Fleming 					EXT_CSD_BUS_WIDTH, extw);
1426272cc70bSAndy Fleming 
1427272cc70bSAndy Fleming 			if (err)
14284137894eSLei Wen 				continue;
1429272cc70bSAndy Fleming 
1430786e8f81SAndrew Gabbasov 			mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
14317798f6dbSAndy Fleming 			mmc_set_bus_width(mmc, widths[idx]);
1432272cc70bSAndy Fleming 
14334137894eSLei Wen 			err = mmc_send_ext_csd(mmc, test_csd);
1434272cc70bSAndy Fleming 
1435786e8f81SAndrew Gabbasov 			if (err)
1436786e8f81SAndrew Gabbasov 				continue;
1437786e8f81SAndrew Gabbasov 
1438786e8f81SAndrew Gabbasov 			/* Only compare read only fields */
1439786e8f81SAndrew Gabbasov 			if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
1440786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
1441786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
1442786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
1443786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_REV]
1444786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_REV] &&
1445786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1446786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
1447786e8f81SAndrew Gabbasov 			    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
1448786e8f81SAndrew Gabbasov 				   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
14494137894eSLei Wen 				break;
1450786e8f81SAndrew Gabbasov 			else
1451786e8f81SAndrew Gabbasov 				err = SWITCH_ERR;
14524137894eSLei Wen 		}
1453786e8f81SAndrew Gabbasov 
1454786e8f81SAndrew Gabbasov 		if (err)
1455786e8f81SAndrew Gabbasov 			return err;
1456272cc70bSAndy Fleming 
1457272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS) {
1458272cc70bSAndy Fleming 			if (mmc->card_caps & MMC_MODE_HS_52MHz)
1459ad5fd922SJaehoon Chung 				mmc->tran_speed = 52000000;
1460272cc70bSAndy Fleming 			else
1461ad5fd922SJaehoon Chung 				mmc->tran_speed = 26000000;
1462272cc70bSAndy Fleming 		}
1463ad5fd922SJaehoon Chung 	}
1464ad5fd922SJaehoon Chung 
1465ad5fd922SJaehoon Chung 	mmc_set_clock(mmc, mmc->tran_speed);
1466272cc70bSAndy Fleming 
14675af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
14685af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
14695af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
14705af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
14715af8f45cSAndrew Gabbasov 	}
14725af8f45cSAndrew Gabbasov 
1473272cc70bSAndy Fleming 	/* fill in device description */
1474272cc70bSAndy Fleming 	mmc->block_dev.lun = 0;
1475873cc1d7SStephen Warren 	mmc->block_dev.hwpart = 0;
1476272cc70bSAndy Fleming 	mmc->block_dev.type = 0;
1477272cc70bSAndy Fleming 	mmc->block_dev.blksz = mmc->read_bl_len;
14780472fbfdSEgbert Eich 	mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz);
14799b1f942cSRabin Vincent 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
1480fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1481fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1482fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1483babce5f6STaylor Hutt 	sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x",
1484babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1485babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1486babce5f6STaylor Hutt 	sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
14870b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1488babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1489babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1490babce5f6STaylor Hutt 	sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1491babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
149256196826SPaul Burton #else
149356196826SPaul Burton 	mmc->block_dev.vendor[0] = 0;
149456196826SPaul Burton 	mmc->block_dev.product[0] = 0;
149556196826SPaul Burton 	mmc->block_dev.revision[0] = 0;
149656196826SPaul Burton #endif
1497122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1498272cc70bSAndy Fleming 	init_part(&mmc->block_dev);
1499122efd43SMikhail Kshevetskiy #endif
1500272cc70bSAndy Fleming 
1501272cc70bSAndy Fleming 	return 0;
1502272cc70bSAndy Fleming }
1503272cc70bSAndy Fleming 
1504fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1505272cc70bSAndy Fleming {
1506272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1507272cc70bSAndy Fleming 	int err;
1508272cc70bSAndy Fleming 
1509272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1510272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
151193bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1512272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1513272cc70bSAndy Fleming 
1514272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1515272cc70bSAndy Fleming 
1516272cc70bSAndy Fleming 	if (err)
1517272cc70bSAndy Fleming 		return err;
1518272cc70bSAndy Fleming 
1519998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1520272cc70bSAndy Fleming 		return UNUSABLE_ERR;
1521272cc70bSAndy Fleming 	else
1522272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1523272cc70bSAndy Fleming 
1524272cc70bSAndy Fleming 	return 0;
1525272cc70bSAndy Fleming }
1526272cc70bSAndy Fleming 
152793bfd616SPantelis Antoniou /* not used any more */
152893bfd616SPantelis Antoniou int __deprecated mmc_register(struct mmc *mmc)
1529272cc70bSAndy Fleming {
153093bfd616SPantelis Antoniou #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
153193bfd616SPantelis Antoniou 	printf("%s is deprecated! use mmc_create() instead.\n", __func__);
153293bfd616SPantelis Antoniou #endif
153393bfd616SPantelis Antoniou 	return -1;
153493bfd616SPantelis Antoniou }
153593bfd616SPantelis Antoniou 
153693bfd616SPantelis Antoniou struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
153793bfd616SPantelis Antoniou {
153893bfd616SPantelis Antoniou 	struct mmc *mmc;
153993bfd616SPantelis Antoniou 
154093bfd616SPantelis Antoniou 	/* quick validation */
154193bfd616SPantelis Antoniou 	if (cfg == NULL || cfg->ops == NULL || cfg->ops->send_cmd == NULL ||
154293bfd616SPantelis Antoniou 			cfg->f_min == 0 || cfg->f_max == 0 || cfg->b_max == 0)
154393bfd616SPantelis Antoniou 		return NULL;
154493bfd616SPantelis Antoniou 
154593bfd616SPantelis Antoniou 	mmc = calloc(1, sizeof(*mmc));
154693bfd616SPantelis Antoniou 	if (mmc == NULL)
154793bfd616SPantelis Antoniou 		return NULL;
154893bfd616SPantelis Antoniou 
154993bfd616SPantelis Antoniou 	mmc->cfg = cfg;
155093bfd616SPantelis Antoniou 	mmc->priv = priv;
155193bfd616SPantelis Antoniou 
155293bfd616SPantelis Antoniou 	/* the following chunk was mmc_register() */
155393bfd616SPantelis Antoniou 
1554ab71188cSMarkus Niebel 	/* Setup dsr related values */
1555ab71188cSMarkus Niebel 	mmc->dsr_imp = 0;
1556ab71188cSMarkus Niebel 	mmc->dsr = 0xffffffff;
1557272cc70bSAndy Fleming 	/* Setup the universal parts of the block interface just once */
1558272cc70bSAndy Fleming 	mmc->block_dev.if_type = IF_TYPE_MMC;
1559272cc70bSAndy Fleming 	mmc->block_dev.dev = cur_dev_num++;
1560272cc70bSAndy Fleming 	mmc->block_dev.removable = 1;
1561272cc70bSAndy Fleming 	mmc->block_dev.block_read = mmc_bread;
1562272cc70bSAndy Fleming 	mmc->block_dev.block_write = mmc_bwrite;
1563e6f99a56SLei Wen 	mmc->block_dev.block_erase = mmc_berase;
156493bfd616SPantelis Antoniou 
156593bfd616SPantelis Antoniou 	/* setup initial part type */
156693bfd616SPantelis Antoniou 	mmc->block_dev.part_type = mmc->cfg->part_type;
1567272cc70bSAndy Fleming 
1568272cc70bSAndy Fleming 	INIT_LIST_HEAD(&mmc->link);
1569272cc70bSAndy Fleming 
1570272cc70bSAndy Fleming 	list_add_tail(&mmc->link, &mmc_devices);
1571272cc70bSAndy Fleming 
157293bfd616SPantelis Antoniou 	return mmc;
157393bfd616SPantelis Antoniou }
157493bfd616SPantelis Antoniou 
157593bfd616SPantelis Antoniou void mmc_destroy(struct mmc *mmc)
157693bfd616SPantelis Antoniou {
157793bfd616SPantelis Antoniou 	/* only freeing memory for now */
157893bfd616SPantelis Antoniou 	free(mmc);
1579272cc70bSAndy Fleming }
1580272cc70bSAndy Fleming 
1581df3fc526SMatthew McClintock #ifdef CONFIG_PARTITIONS
1582272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev)
1583272cc70bSAndy Fleming {
1584272cc70bSAndy Fleming 	struct mmc *mmc = find_mmc_device(dev);
15856bb4b4bcSBenoît Thébaudeau 	if (!mmc || mmc_init(mmc))
158640242bc3SŁukasz Majewski 		return NULL;
1587272cc70bSAndy Fleming 
158840242bc3SŁukasz Majewski 	return &mmc->block_dev;
1589272cc70bSAndy Fleming }
1590df3fc526SMatthew McClintock #endif
1591272cc70bSAndy Fleming 
159295de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
159395de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
159495de9ab2SPaul Kocialkowski {
159595de9ab2SPaul Kocialkowski }
159695de9ab2SPaul Kocialkowski 
1597e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1598272cc70bSAndy Fleming {
1599afd5932bSMacpaul Lin 	int err;
1600272cc70bSAndy Fleming 
1601ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
160293bfd616SPantelis Antoniou 	if (mmc_getcd(mmc) == 0 || mmc->cfg->ops->init == NULL) {
160348972d90SThierry Reding 		mmc->has_init = 0;
160456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
160548972d90SThierry Reding 		printf("MMC: no card present\n");
160656196826SPaul Burton #endif
160748972d90SThierry Reding 		return NO_CARD_ERR;
160848972d90SThierry Reding 	}
160948972d90SThierry Reding 
1610bc897b1dSLei Wen 	if (mmc->has_init)
1611bc897b1dSLei Wen 		return 0;
1612bc897b1dSLei Wen 
16135a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
16145a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
16155a8dbdc6SYangbo Lu #endif
161695de9ab2SPaul Kocialkowski 	board_mmc_power_init();
161795de9ab2SPaul Kocialkowski 
1618ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
161993bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
1620272cc70bSAndy Fleming 
1621272cc70bSAndy Fleming 	if (err)
1622272cc70bSAndy Fleming 		return err;
1623272cc70bSAndy Fleming 
1624786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
1625b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1626b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1627b86b85e2SIlya Yanok 
1628272cc70bSAndy Fleming 	/* Reset the Card */
1629272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1630272cc70bSAndy Fleming 
1631272cc70bSAndy Fleming 	if (err)
1632272cc70bSAndy Fleming 		return err;
1633272cc70bSAndy Fleming 
1634bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1635873cc1d7SStephen Warren 	mmc->block_dev.hwpart = 0;
1636bc897b1dSLei Wen 
1637272cc70bSAndy Fleming 	/* Test for SD version 2 */
1638272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1639272cc70bSAndy Fleming 
1640272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1641272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1642272cc70bSAndy Fleming 
1643272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1644272cc70bSAndy Fleming 	if (err == TIMEOUT) {
1645272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1646272cc70bSAndy Fleming 
1647bd47c135SAndrew Gabbasov 		if (err) {
164856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1649272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
165056196826SPaul Burton #endif
1651272cc70bSAndy Fleming 			return UNUSABLE_ERR;
1652272cc70bSAndy Fleming 		}
1653272cc70bSAndy Fleming 	}
1654272cc70bSAndy Fleming 
1655bd47c135SAndrew Gabbasov 	if (!err)
1656e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
1657e9550449SChe-Liang Chiou 
1658e9550449SChe-Liang Chiou 	return err;
1659e9550449SChe-Liang Chiou }
1660e9550449SChe-Liang Chiou 
1661e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
1662e9550449SChe-Liang Chiou {
1663e9550449SChe-Liang Chiou 	int err = 0;
1664e9550449SChe-Liang Chiou 
1665bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
1666e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
1667e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
1668e9550449SChe-Liang Chiou 
1669e9550449SChe-Liang Chiou 	if (!err)
1670bc897b1dSLei Wen 		err = mmc_startup(mmc);
1671bc897b1dSLei Wen 	if (err)
1672bc897b1dSLei Wen 		mmc->has_init = 0;
1673bc897b1dSLei Wen 	else
1674bc897b1dSLei Wen 		mmc->has_init = 1;
1675e9550449SChe-Liang Chiou 	return err;
1676e9550449SChe-Liang Chiou }
1677e9550449SChe-Liang Chiou 
1678e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
1679e9550449SChe-Liang Chiou {
1680bd47c135SAndrew Gabbasov 	int err = 0;
1681d803fea5SMateusz Zalega 	unsigned start;
1682e9550449SChe-Liang Chiou 
1683e9550449SChe-Liang Chiou 	if (mmc->has_init)
1684e9550449SChe-Liang Chiou 		return 0;
1685d803fea5SMateusz Zalega 
1686d803fea5SMateusz Zalega 	start = get_timer(0);
1687d803fea5SMateusz Zalega 
1688e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
1689e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
1690e9550449SChe-Liang Chiou 
1691bd47c135SAndrew Gabbasov 	if (!err)
1692e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
1693e9550449SChe-Liang Chiou 	debug("%s: %d, time %lu\n", __func__, err, get_timer(start));
1694bc897b1dSLei Wen 	return err;
1695272cc70bSAndy Fleming }
1696272cc70bSAndy Fleming 
1697ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
1698ab71188cSMarkus Niebel {
1699ab71188cSMarkus Niebel 	mmc->dsr = val;
1700ab71188cSMarkus Niebel 	return 0;
1701ab71188cSMarkus Niebel }
1702ab71188cSMarkus Niebel 
1703cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
1704cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
1705272cc70bSAndy Fleming {
1706272cc70bSAndy Fleming 	return -1;
1707272cc70bSAndy Fleming }
1708272cc70bSAndy Fleming 
1709cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
1710cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
1711cee9ab7cSJeroen Hofstee {
1712cee9ab7cSJeroen Hofstee 	return -1;
1713cee9ab7cSJeroen Hofstee }
1714272cc70bSAndy Fleming 
171556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
171656196826SPaul Burton 
1717272cc70bSAndy Fleming void print_mmc_devices(char separator)
1718272cc70bSAndy Fleming {
1719272cc70bSAndy Fleming 	struct mmc *m;
1720272cc70bSAndy Fleming 	struct list_head *entry;
172134dd9284SPrzemyslaw Marczak 	char *mmc_type;
1722272cc70bSAndy Fleming 
1723272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
1724272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
1725272cc70bSAndy Fleming 
172634dd9284SPrzemyslaw Marczak 		if (m->has_init)
172734dd9284SPrzemyslaw Marczak 			mmc_type = IS_SD(m) ? "SD" : "eMMC";
172834dd9284SPrzemyslaw Marczak 		else
172934dd9284SPrzemyslaw Marczak 			mmc_type = NULL;
173034dd9284SPrzemyslaw Marczak 
173193bfd616SPantelis Antoniou 		printf("%s: %d", m->cfg->name, m->block_dev.dev);
173234dd9284SPrzemyslaw Marczak 		if (mmc_type)
173334dd9284SPrzemyslaw Marczak 			printf(" (%s)", mmc_type);
1734272cc70bSAndy Fleming 
1735e75eaf10SLubomir Popov 		if (entry->next != &mmc_devices) {
1736272cc70bSAndy Fleming 			printf("%c", separator);
1737e75eaf10SLubomir Popov 			if (separator != '\n')
1738e75eaf10SLubomir Popov 				puts (" ");
1739e75eaf10SLubomir Popov 		}
1740272cc70bSAndy Fleming 	}
1741272cc70bSAndy Fleming 
1742272cc70bSAndy Fleming 	printf("\n");
1743272cc70bSAndy Fleming }
1744272cc70bSAndy Fleming 
174556196826SPaul Burton #else
174656196826SPaul Burton void print_mmc_devices(char separator) { }
174756196826SPaul Burton #endif
174856196826SPaul Burton 
1749ea6ebe21SLei Wen int get_mmc_num(void)
1750ea6ebe21SLei Wen {
1751ea6ebe21SLei Wen 	return cur_dev_num;
1752ea6ebe21SLei Wen }
1753ea6ebe21SLei Wen 
1754e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
1755e9550449SChe-Liang Chiou {
1756e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
1757e9550449SChe-Liang Chiou }
1758e9550449SChe-Liang Chiou 
1759e9550449SChe-Liang Chiou static void do_preinit(void)
1760e9550449SChe-Liang Chiou {
1761e9550449SChe-Liang Chiou 	struct mmc *m;
1762e9550449SChe-Liang Chiou 	struct list_head *entry;
1763e9550449SChe-Liang Chiou 
1764e9550449SChe-Liang Chiou 	list_for_each(entry, &mmc_devices) {
1765e9550449SChe-Liang Chiou 		m = list_entry(entry, struct mmc, link);
1766e9550449SChe-Liang Chiou 
17675a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
17685a8dbdc6SYangbo Lu 		mmc_set_preinit(m, 1);
17695a8dbdc6SYangbo Lu #endif
1770e9550449SChe-Liang Chiou 		if (m->preinit)
1771e9550449SChe-Liang Chiou 			mmc_start_init(m);
1772e9550449SChe-Liang Chiou 	}
1773e9550449SChe-Liang Chiou }
1774e9550449SChe-Liang Chiou 
17758e3332e2SSjoerd Simons #if defined(CONFIG_DM_MMC) && defined(CONFIG_SPL_BUILD)
17768e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
17778e3332e2SSjoerd Simons {
17788e3332e2SSjoerd Simons 	return 0;
17798e3332e2SSjoerd Simons }
17808e3332e2SSjoerd Simons #elif defined(CONFIG_DM_MMC)
17818e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
17828e3332e2SSjoerd Simons {
1783*4a1db6d8SSimon Glass 	int ret, i;
17848e3332e2SSjoerd Simons 	struct uclass *uc;
1785*4a1db6d8SSimon Glass 	struct udevice *dev;
17868e3332e2SSjoerd Simons 
17878e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
17888e3332e2SSjoerd Simons 	if (ret)
17898e3332e2SSjoerd Simons 		return ret;
17908e3332e2SSjoerd Simons 
1791*4a1db6d8SSimon Glass 	/*
1792*4a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
1793*4a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
1794*4a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
1795*4a1db6d8SSimon Glass 	 */
1796*4a1db6d8SSimon Glass 	for (i = 0; ; i++) {
1797*4a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
1798*4a1db6d8SSimon Glass 		if (ret == -ENODEV)
1799*4a1db6d8SSimon Glass 			break;
1800*4a1db6d8SSimon Glass 	}
1801*4a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
1802*4a1db6d8SSimon Glass 		ret = device_probe(dev);
18038e3332e2SSjoerd Simons 		if (ret)
1804*4a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
18058e3332e2SSjoerd Simons 	}
18068e3332e2SSjoerd Simons 
18078e3332e2SSjoerd Simons 	return 0;
18088e3332e2SSjoerd Simons }
18098e3332e2SSjoerd Simons #else
18108e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
18118e3332e2SSjoerd Simons {
18128e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
18138e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
18148e3332e2SSjoerd Simons 
18158e3332e2SSjoerd Simons 	return 0;
18168e3332e2SSjoerd Simons }
18178e3332e2SSjoerd Simons #endif
1818e9550449SChe-Liang Chiou 
1819272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1820272cc70bSAndy Fleming {
18211b26bab1SDaniel Kochmański 	static int initialized = 0;
18228e3332e2SSjoerd Simons 	int ret;
18231b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
18241b26bab1SDaniel Kochmański 		return 0;
18251b26bab1SDaniel Kochmański 	initialized = 1;
18261b26bab1SDaniel Kochmański 
1827272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc_devices);
1828272cc70bSAndy Fleming 	cur_dev_num = 0;
1829272cc70bSAndy Fleming 
18308e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
18318e3332e2SSjoerd Simons 	if (ret)
18328e3332e2SSjoerd Simons 		return ret;
1833272cc70bSAndy Fleming 
1834bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
1835272cc70bSAndy Fleming 	print_mmc_devices(',');
1836bb0dc108SYing Zhang #endif
1837272cc70bSAndy Fleming 
1838e9550449SChe-Liang Chiou 	do_preinit();
1839272cc70bSAndy Fleming 	return 0;
1840272cc70bSAndy Fleming }
18413690d6d6SAmar 
18423690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT
18433690d6d6SAmar /*
18443690d6d6SAmar  * This function changes the size of boot partition and the size of rpmb
18453690d6d6SAmar  * partition present on EMMC devices.
18463690d6d6SAmar  *
18473690d6d6SAmar  * Input Parameters:
18483690d6d6SAmar  * struct *mmc: pointer for the mmc device strcuture
18493690d6d6SAmar  * bootsize: size of boot partition
18503690d6d6SAmar  * rpmbsize: size of rpmb partition
18513690d6d6SAmar  *
18523690d6d6SAmar  * Returns 0 on success.
18533690d6d6SAmar  */
18543690d6d6SAmar 
18553690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
18563690d6d6SAmar 				unsigned long rpmbsize)
18573690d6d6SAmar {
18583690d6d6SAmar 	int err;
18593690d6d6SAmar 	struct mmc_cmd cmd;
18603690d6d6SAmar 
18613690d6d6SAmar 	/* Only use this command for raw EMMC moviNAND. Enter backdoor mode */
18623690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18633690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18643690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG1;
18653690d6d6SAmar 
18663690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18673690d6d6SAmar 	if (err) {
18683690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error1 = %d\n", err);
18693690d6d6SAmar 		return err;
18703690d6d6SAmar 	}
18713690d6d6SAmar 
18723690d6d6SAmar 	/* Boot partition changing mode */
18733690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18743690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18753690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG2;
18763690d6d6SAmar 
18773690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18783690d6d6SAmar 	if (err) {
18793690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error2 = %d\n", err);
18803690d6d6SAmar 		return err;
18813690d6d6SAmar 	}
18823690d6d6SAmar 	/* boot partition size is multiple of 128KB */
18833690d6d6SAmar 	bootsize = (bootsize * 1024) / 128;
18843690d6d6SAmar 
18853690d6d6SAmar 	/* Arg: boot partition size */
18863690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18873690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18883690d6d6SAmar 	cmd.cmdarg = bootsize;
18893690d6d6SAmar 
18903690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18913690d6d6SAmar 	if (err) {
18923690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error3 = %d\n", err);
18933690d6d6SAmar 		return err;
18943690d6d6SAmar 	}
18953690d6d6SAmar 	/* RPMB partition size is multiple of 128KB */
18963690d6d6SAmar 	rpmbsize = (rpmbsize * 1024) / 128;
18973690d6d6SAmar 	/* Arg: RPMB partition size */
18983690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18993690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
19003690d6d6SAmar 	cmd.cmdarg = rpmbsize;
19013690d6d6SAmar 
19023690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
19033690d6d6SAmar 	if (err) {
19043690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error4 = %d\n", err);
19053690d6d6SAmar 		return err;
19063690d6d6SAmar 	}
19073690d6d6SAmar 	return 0;
19083690d6d6SAmar }
19093690d6d6SAmar 
19103690d6d6SAmar /*
19115a99b9deSTom Rini  * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH
19125a99b9deSTom Rini  * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH
19135a99b9deSTom Rini  * and BOOT_MODE.
19145a99b9deSTom Rini  *
19155a99b9deSTom Rini  * Returns 0 on success.
19165a99b9deSTom Rini  */
19175a99b9deSTom Rini int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode)
19185a99b9deSTom Rini {
19195a99b9deSTom Rini 	int err;
19205a99b9deSTom Rini 
19215a99b9deSTom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH,
19225a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) |
19235a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) |
19245a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width));
19255a99b9deSTom Rini 
19265a99b9deSTom Rini 	if (err)
19275a99b9deSTom Rini 		return err;
19285a99b9deSTom Rini 	return 0;
19295a99b9deSTom Rini }
19305a99b9deSTom Rini 
19315a99b9deSTom Rini /*
1932792970b0STom Rini  * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG)
1933792970b0STom Rini  * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and
1934792970b0STom Rini  * PARTITION_ACCESS.
1935792970b0STom Rini  *
1936792970b0STom Rini  * Returns 0 on success.
1937792970b0STom Rini  */
1938792970b0STom Rini int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access)
1939792970b0STom Rini {
1940792970b0STom Rini 	int err;
1941792970b0STom Rini 
1942792970b0STom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
1943792970b0STom Rini 			 EXT_CSD_BOOT_ACK(ack) |
1944792970b0STom Rini 			 EXT_CSD_BOOT_PART_NUM(part_num) |
1945792970b0STom Rini 			 EXT_CSD_PARTITION_ACCESS(access));
1946792970b0STom Rini 
1947792970b0STom Rini 	if (err)
1948792970b0STom Rini 		return err;
1949792970b0STom Rini 	return 0;
1950792970b0STom Rini }
195133ace362STom Rini 
195233ace362STom Rini /*
195333ace362STom Rini  * Modify EXT_CSD[162] which is RST_n_FUNCTION based on the given value
195433ace362STom Rini  * for enable.  Note that this is a write-once field for non-zero values.
195533ace362STom Rini  *
195633ace362STom Rini  * Returns 0 on success.
195733ace362STom Rini  */
195833ace362STom Rini int mmc_set_rst_n_function(struct mmc *mmc, u8 enable)
195933ace362STom Rini {
196033ace362STom Rini 	return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_RST_N_FUNCTION,
196133ace362STom Rini 			  enable);
196233ace362STom Rini }
19633690d6d6SAmar #endif
1964