xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 7c4213f6)
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 
237*7c4213f6SStephen Warren static ulong mmc_bread(block_dev_desc_t *block_dev, lbaint_t start,
238*7c4213f6SStephen Warren 		       lbaint_t blkcnt, void *dst)
239272cc70bSAndy Fleming {
240*7c4213f6SStephen Warren 	int dev_num = block_dev->dev;
2414a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
242272cc70bSAndy Fleming 
2434a1a06bcSAlagu Sankar 	if (blkcnt == 0)
2444a1a06bcSAlagu Sankar 		return 0;
2454a1a06bcSAlagu Sankar 
2464a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
247272cc70bSAndy Fleming 	if (!mmc)
248272cc70bSAndy Fleming 		return 0;
249272cc70bSAndy Fleming 
250d2bf29e3SLei Wen 	if ((start + blkcnt) > mmc->block_dev.lba) {
25156196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
252ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
253d2bf29e3SLei Wen 			start + blkcnt, mmc->block_dev.lba);
25456196826SPaul Burton #endif
255d2bf29e3SLei Wen 		return 0;
256d2bf29e3SLei Wen 	}
257272cc70bSAndy Fleming 
25811692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
25911692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
260272cc70bSAndy Fleming 		return 0;
26111692991SSimon Glass 	}
262272cc70bSAndy Fleming 
2634a1a06bcSAlagu Sankar 	do {
26493bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
26593bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
26611692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
26711692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
2684a1a06bcSAlagu Sankar 			return 0;
26911692991SSimon Glass 		}
2704a1a06bcSAlagu Sankar 		blocks_todo -= cur;
2714a1a06bcSAlagu Sankar 		start += cur;
2724a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
2734a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
274272cc70bSAndy Fleming 
275272cc70bSAndy Fleming 	return blkcnt;
276272cc70bSAndy Fleming }
277272cc70bSAndy Fleming 
278fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
279272cc70bSAndy Fleming {
280272cc70bSAndy Fleming 	struct mmc_cmd cmd;
281272cc70bSAndy Fleming 	int err;
282272cc70bSAndy Fleming 
283272cc70bSAndy Fleming 	udelay(1000);
284272cc70bSAndy Fleming 
285272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
286272cc70bSAndy Fleming 	cmd.cmdarg = 0;
287272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
288272cc70bSAndy Fleming 
289272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
290272cc70bSAndy Fleming 
291272cc70bSAndy Fleming 	if (err)
292272cc70bSAndy Fleming 		return err;
293272cc70bSAndy Fleming 
294272cc70bSAndy Fleming 	udelay(2000);
295272cc70bSAndy Fleming 
296272cc70bSAndy Fleming 	return 0;
297272cc70bSAndy Fleming }
298272cc70bSAndy Fleming 
299fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
300272cc70bSAndy Fleming {
301272cc70bSAndy Fleming 	int timeout = 1000;
302272cc70bSAndy Fleming 	int err;
303272cc70bSAndy Fleming 	struct mmc_cmd cmd;
304272cc70bSAndy Fleming 
3051677eef4SAndrew Gabbasov 	while (1) {
306272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
307272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
308272cc70bSAndy Fleming 		cmd.cmdarg = 0;
309272cc70bSAndy Fleming 
310272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
311272cc70bSAndy Fleming 
312272cc70bSAndy Fleming 		if (err)
313272cc70bSAndy Fleming 			return err;
314272cc70bSAndy Fleming 
315272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
316272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
317250de12bSStefano Babic 
318250de12bSStefano Babic 		/*
319250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
320250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
321250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
322250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
323250de12bSStefano Babic 		 * specified.
324250de12bSStefano Babic 		 */
325d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
32693bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
327272cc70bSAndy Fleming 
328272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
329272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
330272cc70bSAndy Fleming 
331272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
332272cc70bSAndy Fleming 
333272cc70bSAndy Fleming 		if (err)
334272cc70bSAndy Fleming 			return err;
335272cc70bSAndy Fleming 
3361677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
3371677eef4SAndrew Gabbasov 			break;
338272cc70bSAndy Fleming 
3391677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
340272cc70bSAndy Fleming 			return UNUSABLE_ERR;
341272cc70bSAndy Fleming 
3421677eef4SAndrew Gabbasov 		udelay(1000);
3431677eef4SAndrew Gabbasov 	}
3441677eef4SAndrew Gabbasov 
345272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
346272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
347272cc70bSAndy Fleming 
348d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
349d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
350d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
351d52ebf10SThomas Chou 		cmd.cmdarg = 0;
352d52ebf10SThomas Chou 
353d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
354d52ebf10SThomas Chou 
355d52ebf10SThomas Chou 		if (err)
356d52ebf10SThomas Chou 			return err;
357d52ebf10SThomas Chou 	}
358d52ebf10SThomas Chou 
359998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
360272cc70bSAndy Fleming 
361272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
362272cc70bSAndy Fleming 	mmc->rca = 0;
363272cc70bSAndy Fleming 
364272cc70bSAndy Fleming 	return 0;
365272cc70bSAndy Fleming }
366272cc70bSAndy Fleming 
3675289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
368272cc70bSAndy Fleming {
3695289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
370272cc70bSAndy Fleming 	int err;
371272cc70bSAndy Fleming 
3725289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
3735289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
3745289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
3755a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
3765a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
37793bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
378a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
379a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
380e9550449SChe-Liang Chiou 
3815289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
382e9550449SChe-Liang Chiou 	if (err)
383e9550449SChe-Liang Chiou 		return err;
3845289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
385e9550449SChe-Liang Chiou 	return 0;
386e9550449SChe-Liang Chiou }
387e9550449SChe-Liang Chiou 
388750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
389e9550449SChe-Liang Chiou {
390e9550449SChe-Liang Chiou 	int err, i;
391e9550449SChe-Liang Chiou 
392272cc70bSAndy Fleming 	/* Some cards seem to need this */
393272cc70bSAndy Fleming 	mmc_go_idle(mmc);
394272cc70bSAndy Fleming 
39531cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
396e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
3975289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
39831cacbabSRaffaele Recalcati 		if (err)
39931cacbabSRaffaele Recalcati 			return err;
40031cacbabSRaffaele Recalcati 
401e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
402a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
403bd47c135SAndrew Gabbasov 			break;
404e9550449SChe-Liang Chiou 	}
405bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
406bd47c135SAndrew Gabbasov 	return 0;
407e9550449SChe-Liang Chiou }
40831cacbabSRaffaele Recalcati 
409750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
410e9550449SChe-Liang Chiou {
411e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
412e9550449SChe-Liang Chiou 	int timeout = 1000;
413e9550449SChe-Liang Chiou 	uint start;
414e9550449SChe-Liang Chiou 	int err;
415e9550449SChe-Liang Chiou 
416e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
417cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
418e9550449SChe-Liang Chiou 		start = get_timer(0);
4191677eef4SAndrew Gabbasov 		while (1) {
4205289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
421272cc70bSAndy Fleming 			if (err)
422272cc70bSAndy Fleming 				return err;
4231677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
4241677eef4SAndrew Gabbasov 				break;
425e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
426272cc70bSAndy Fleming 				return UNUSABLE_ERR;
427e9550449SChe-Liang Chiou 			udelay(100);
4281677eef4SAndrew Gabbasov 		}
429cc17c01fSAndrew Gabbasov 	}
430272cc70bSAndy Fleming 
431d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
432d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
433d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
434d52ebf10SThomas Chou 		cmd.cmdarg = 0;
435d52ebf10SThomas Chou 
436d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
437d52ebf10SThomas Chou 
438d52ebf10SThomas Chou 		if (err)
439d52ebf10SThomas Chou 			return err;
440a626c8d4SAndrew Gabbasov 
441a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
442d52ebf10SThomas Chou 	}
443d52ebf10SThomas Chou 
444272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
445272cc70bSAndy Fleming 
446272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
447def816a2SStephen Warren 	mmc->rca = 1;
448272cc70bSAndy Fleming 
449272cc70bSAndy Fleming 	return 0;
450272cc70bSAndy Fleming }
451272cc70bSAndy Fleming 
452272cc70bSAndy Fleming 
453fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
454272cc70bSAndy Fleming {
455272cc70bSAndy Fleming 	struct mmc_cmd cmd;
456272cc70bSAndy Fleming 	struct mmc_data data;
457272cc70bSAndy Fleming 	int err;
458272cc70bSAndy Fleming 
459272cc70bSAndy Fleming 	/* Get the Card Status Register */
460272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
461272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
462272cc70bSAndy Fleming 	cmd.cmdarg = 0;
463272cc70bSAndy Fleming 
464cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
465272cc70bSAndy Fleming 	data.blocks = 1;
4668bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
467272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
468272cc70bSAndy Fleming 
469272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
470272cc70bSAndy Fleming 
471272cc70bSAndy Fleming 	return err;
472272cc70bSAndy Fleming }
473272cc70bSAndy Fleming 
474272cc70bSAndy Fleming 
475fdbb873eSKim Phillips static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
476272cc70bSAndy Fleming {
477272cc70bSAndy Fleming 	struct mmc_cmd cmd;
4785d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
4795d4fc8d9SRaffaele Recalcati 	int ret;
480272cc70bSAndy Fleming 
481272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
482272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
483272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
484272cc70bSAndy Fleming 				 (index << 16) |
485272cc70bSAndy Fleming 				 (value << 8);
486272cc70bSAndy Fleming 
4875d4fc8d9SRaffaele Recalcati 	ret = mmc_send_cmd(mmc, &cmd, NULL);
4885d4fc8d9SRaffaele Recalcati 
4895d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
49093ad0d18SJan Kloetzke 	if (!ret)
49193ad0d18SJan Kloetzke 		ret = mmc_send_status(mmc, timeout);
4925d4fc8d9SRaffaele Recalcati 
4935d4fc8d9SRaffaele Recalcati 	return ret;
4945d4fc8d9SRaffaele Recalcati 
495272cc70bSAndy Fleming }
496272cc70bSAndy Fleming 
497fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
498272cc70bSAndy Fleming {
4998bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
500272cc70bSAndy Fleming 	char cardtype;
501272cc70bSAndy Fleming 	int err;
502272cc70bSAndy Fleming 
503fc5b32fbSAndrew Gabbasov 	mmc->card_caps = 0;
504272cc70bSAndy Fleming 
505d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
506d52ebf10SThomas Chou 		return 0;
507d52ebf10SThomas Chou 
508272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
509272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
510272cc70bSAndy Fleming 		return 0;
511272cc70bSAndy Fleming 
512fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
513fc5b32fbSAndrew Gabbasov 
514272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
515272cc70bSAndy Fleming 
516272cc70bSAndy Fleming 	if (err)
517272cc70bSAndy Fleming 		return err;
518272cc70bSAndy Fleming 
5190560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
520272cc70bSAndy Fleming 
521272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
522272cc70bSAndy Fleming 
523272cc70bSAndy Fleming 	if (err)
5246b2221b0SAndrew Gabbasov 		return err == SWITCH_ERR ? 0 : err;
525272cc70bSAndy Fleming 
526272cc70bSAndy Fleming 	/* Now check to see that it worked */
527272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
528272cc70bSAndy Fleming 
529272cc70bSAndy Fleming 	if (err)
530272cc70bSAndy Fleming 		return err;
531272cc70bSAndy Fleming 
532272cc70bSAndy Fleming 	/* No high-speed support */
5330560db18SLei Wen 	if (!ext_csd[EXT_CSD_HS_TIMING])
534272cc70bSAndy Fleming 		return 0;
535272cc70bSAndy Fleming 
536272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
537d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
538201d5ac4SAndrew Gabbasov 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
539d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
540272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
541d22e3d46SJaehoon Chung 	} else {
542272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
543d22e3d46SJaehoon Chung 	}
544272cc70bSAndy Fleming 
545272cc70bSAndy Fleming 	return 0;
546272cc70bSAndy Fleming }
547272cc70bSAndy Fleming 
548f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
549f866a46dSStephen Warren {
550f866a46dSStephen Warren 	switch (part_num) {
551f866a46dSStephen Warren 	case 0:
552f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
553f866a46dSStephen Warren 		break;
554f866a46dSStephen Warren 	case 1:
555f866a46dSStephen Warren 	case 2:
556f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
557f866a46dSStephen Warren 		break;
558f866a46dSStephen Warren 	case 3:
559f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
560f866a46dSStephen Warren 		break;
561f866a46dSStephen Warren 	case 4:
562f866a46dSStephen Warren 	case 5:
563f866a46dSStephen Warren 	case 6:
564f866a46dSStephen Warren 	case 7:
565f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
566f866a46dSStephen Warren 		break;
567f866a46dSStephen Warren 	default:
568f866a46dSStephen Warren 		return -1;
569f866a46dSStephen Warren 	}
570f866a46dSStephen Warren 
571f866a46dSStephen Warren 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
572f866a46dSStephen Warren 
573f866a46dSStephen Warren 	return 0;
574f866a46dSStephen Warren }
575f866a46dSStephen Warren 
576d2356284SStephen Warren int mmc_select_hwpart(int dev_num, int hwpart)
577d2356284SStephen Warren {
578d2356284SStephen Warren 	struct mmc *mmc = find_mmc_device(dev_num);
579d2356284SStephen Warren 	int ret;
580d2356284SStephen Warren 
581d2356284SStephen Warren 	if (!mmc)
582d4622df3SStephen Warren 		return -ENODEV;
583d2356284SStephen Warren 
584d2356284SStephen Warren 	if (mmc->part_num == hwpart)
585d2356284SStephen Warren 		return 0;
586d2356284SStephen Warren 
587d2356284SStephen Warren 	if (mmc->part_config == MMCPART_NOAVAILABLE) {
588d2356284SStephen Warren 		printf("Card doesn't support part_switch\n");
589d4622df3SStephen Warren 		return -EMEDIUMTYPE;
590d2356284SStephen Warren 	}
591d2356284SStephen Warren 
592d2356284SStephen Warren 	ret = mmc_switch_part(dev_num, hwpart);
593d2356284SStephen Warren 	if (ret)
594d4622df3SStephen Warren 		return ret;
595d2356284SStephen Warren 
596d2356284SStephen Warren 	mmc->part_num = hwpart;
597d2356284SStephen Warren 
598d2356284SStephen Warren 	return 0;
599d2356284SStephen Warren }
600d2356284SStephen Warren 
601d2356284SStephen Warren 
602bc897b1dSLei Wen int mmc_switch_part(int dev_num, unsigned int part_num)
603bc897b1dSLei Wen {
604bc897b1dSLei Wen 	struct mmc *mmc = find_mmc_device(dev_num);
605f866a46dSStephen Warren 	int ret;
606bc897b1dSLei Wen 
607bc897b1dSLei Wen 	if (!mmc)
608bc897b1dSLei Wen 		return -1;
609bc897b1dSLei Wen 
610f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
611bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
612bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
613f866a46dSStephen Warren 
6146dc93e70SPeter Bigot 	/*
6156dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
6166dc93e70SPeter Bigot 	 * to return to representing the raw device.
6176dc93e70SPeter Bigot 	 */
6186dc93e70SPeter Bigot 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0)))
6196dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
6206dc93e70SPeter Bigot 
6216dc93e70SPeter Bigot 	return ret;
622bc897b1dSLei Wen }
623bc897b1dSLei Wen 
624ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
625ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
626ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
627ac9da0e0SDiego Santa Cruz {
628ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
629ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
630ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
631ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
632ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
633ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
6348dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
635ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
636ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
637ac9da0e0SDiego Santa Cruz 
638ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
639ac9da0e0SDiego Santa Cruz 		return -EINVAL;
640ac9da0e0SDiego Santa Cruz 
641ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
642ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
643ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
644ac9da0e0SDiego Santa Cruz 	}
645ac9da0e0SDiego Santa Cruz 
646ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
647ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
648ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
649ac9da0e0SDiego Santa Cruz 	}
650ac9da0e0SDiego Santa Cruz 
651ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
652ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
653ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
654ac9da0e0SDiego Santa Cruz 	}
655ac9da0e0SDiego Santa Cruz 
656ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
657ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
658ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
659ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
660ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
661ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
662ac9da0e0SDiego Santa Cruz 			return -EINVAL;
663ac9da0e0SDiego Santa Cruz 		}
664ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
665ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
666ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
667ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
668ac9da0e0SDiego Santa Cruz 		} else {
669ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
670ac9da0e0SDiego Santa Cruz 		}
671ac9da0e0SDiego Santa Cruz 	} else {
672ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
673ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
674ac9da0e0SDiego Santa Cruz 	}
675ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
676ac9da0e0SDiego Santa Cruz 
677ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
678ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
679ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
680ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
681ac9da0e0SDiego Santa Cruz 			return -EINVAL;
682ac9da0e0SDiego Santa Cruz 		}
683ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
684ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
685ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
686ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
687ac9da0e0SDiego Santa Cruz 		}
688ac9da0e0SDiego Santa Cruz 	}
689ac9da0e0SDiego Santa Cruz 
690ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
691ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
692ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
693ac9da0e0SDiego Santa Cruz 	}
694ac9da0e0SDiego Santa Cruz 
695ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
696ac9da0e0SDiego Santa Cruz 	if (err)
697ac9da0e0SDiego Santa Cruz 		return err;
698ac9da0e0SDiego Santa Cruz 
699ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
700ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
701ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
702ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
703ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
704ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
705ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
706ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
707ac9da0e0SDiego Santa Cruz 	}
708ac9da0e0SDiego Santa Cruz 
7098dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
7108dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
7118dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
7128dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
7138dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
7148dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
7158dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
7168dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
7178dda5b0eSDiego Santa Cruz 		else
7188dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
7198dda5b0eSDiego Santa Cruz 	}
7208dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
7218dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
7228dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
7238dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
7248dda5b0eSDiego Santa Cruz 			else
7258dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
7268dda5b0eSDiego Santa Cruz 		}
7278dda5b0eSDiego Santa Cruz 	}
7288dda5b0eSDiego Santa Cruz 
7298dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
7308dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
7318dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
7328dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
7338dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
7348dda5b0eSDiego Santa Cruz 	}
7358dda5b0eSDiego Santa Cruz 
736ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
737ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
738ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
739ac9da0e0SDiego Santa Cruz 		return -EPERM;
740ac9da0e0SDiego Santa Cruz 	}
741ac9da0e0SDiego Santa Cruz 
742ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
743ac9da0e0SDiego Santa Cruz 		return 0;
744ac9da0e0SDiego Santa Cruz 
745ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
746ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
747ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
748ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
749ac9da0e0SDiego Santa Cruz 
750ac9da0e0SDiego Santa Cruz 		if (err)
751ac9da0e0SDiego Santa Cruz 			return err;
752ac9da0e0SDiego Santa Cruz 
753ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
754ac9da0e0SDiego Santa Cruz 
755ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
756ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
757ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
758ac9da0e0SDiego Santa Cruz 
759ac9da0e0SDiego Santa Cruz 	}
760ac9da0e0SDiego Santa Cruz 
761ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
762ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
763ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
764ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
765ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
766ac9da0e0SDiego Santa Cruz 		if (err)
767ac9da0e0SDiego Santa Cruz 			return err;
768ac9da0e0SDiego Santa Cruz 	}
769ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
770ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
771ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
772ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
773ac9da0e0SDiego Santa Cruz 		if (err)
774ac9da0e0SDiego Santa Cruz 			return err;
775ac9da0e0SDiego Santa Cruz 	}
776ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
777ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
778ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
779ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
780ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
781ac9da0e0SDiego Santa Cruz 			if (err)
782ac9da0e0SDiego Santa Cruz 				return err;
783ac9da0e0SDiego Santa Cruz 		}
784ac9da0e0SDiego Santa Cruz 	}
785ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
786ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
787ac9da0e0SDiego Santa Cruz 	if (err)
788ac9da0e0SDiego Santa Cruz 		return err;
789ac9da0e0SDiego Santa Cruz 
790ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
791ac9da0e0SDiego Santa Cruz 		return 0;
792ac9da0e0SDiego Santa Cruz 
7938dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
7948dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
7958dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
7968dda5b0eSDiego Santa Cruz 	 * partitioning. */
7978dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
7988dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
7998dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
8008dda5b0eSDiego Santa Cruz 		if (err)
8018dda5b0eSDiego Santa Cruz 			return err;
8028dda5b0eSDiego Santa Cruz 	}
8038dda5b0eSDiego Santa Cruz 
804ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
805ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
806ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
807ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
808ac9da0e0SDiego Santa Cruz 
809ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
810ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
811ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
812ac9da0e0SDiego Santa Cruz 	if (err)
813ac9da0e0SDiego Santa Cruz 		return err;
814ac9da0e0SDiego Santa Cruz 
815ac9da0e0SDiego Santa Cruz 	return 0;
816ac9da0e0SDiego Santa Cruz }
817ac9da0e0SDiego Santa Cruz 
81848972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
81948972d90SThierry Reding {
82048972d90SThierry Reding 	int cd;
82148972d90SThierry Reding 
82248972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
82348972d90SThierry Reding 
824d4e1da4eSPeter Korsgaard 	if (cd < 0) {
82593bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
82693bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
827d4e1da4eSPeter Korsgaard 		else
828d4e1da4eSPeter Korsgaard 			cd = 1;
829d4e1da4eSPeter Korsgaard 	}
83048972d90SThierry Reding 
83148972d90SThierry Reding 	return cd;
83248972d90SThierry Reding }
83348972d90SThierry Reding 
834fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
835272cc70bSAndy Fleming {
836272cc70bSAndy Fleming 	struct mmc_cmd cmd;
837272cc70bSAndy Fleming 	struct mmc_data data;
838272cc70bSAndy Fleming 
839272cc70bSAndy Fleming 	/* Switch the frequency */
840272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
841272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
842272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
843272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
844272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
845272cc70bSAndy Fleming 
846272cc70bSAndy Fleming 	data.dest = (char *)resp;
847272cc70bSAndy Fleming 	data.blocksize = 64;
848272cc70bSAndy Fleming 	data.blocks = 1;
849272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
850272cc70bSAndy Fleming 
851272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
852272cc70bSAndy Fleming }
853272cc70bSAndy Fleming 
854272cc70bSAndy Fleming 
855fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
856272cc70bSAndy Fleming {
857272cc70bSAndy Fleming 	int err;
858272cc70bSAndy Fleming 	struct mmc_cmd cmd;
859f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
860f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
861272cc70bSAndy Fleming 	struct mmc_data data;
862272cc70bSAndy Fleming 	int timeout;
863272cc70bSAndy Fleming 
864272cc70bSAndy Fleming 	mmc->card_caps = 0;
865272cc70bSAndy Fleming 
866d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
867d52ebf10SThomas Chou 		return 0;
868d52ebf10SThomas Chou 
869272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
870272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
871272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
872272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
873272cc70bSAndy Fleming 
874272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
875272cc70bSAndy Fleming 
876272cc70bSAndy Fleming 	if (err)
877272cc70bSAndy Fleming 		return err;
878272cc70bSAndy Fleming 
879272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
880272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
881272cc70bSAndy Fleming 	cmd.cmdarg = 0;
882272cc70bSAndy Fleming 
883272cc70bSAndy Fleming 	timeout = 3;
884272cc70bSAndy Fleming 
885272cc70bSAndy Fleming retry_scr:
886f781dd38SAnton staaf 	data.dest = (char *)scr;
887272cc70bSAndy Fleming 	data.blocksize = 8;
888272cc70bSAndy Fleming 	data.blocks = 1;
889272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
890272cc70bSAndy Fleming 
891272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
892272cc70bSAndy Fleming 
893272cc70bSAndy Fleming 	if (err) {
894272cc70bSAndy Fleming 		if (timeout--)
895272cc70bSAndy Fleming 			goto retry_scr;
896272cc70bSAndy Fleming 
897272cc70bSAndy Fleming 		return err;
898272cc70bSAndy Fleming 	}
899272cc70bSAndy Fleming 
9004e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
9014e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
902272cc70bSAndy Fleming 
903272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
904272cc70bSAndy Fleming 		case 0:
905272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
906272cc70bSAndy Fleming 			break;
907272cc70bSAndy Fleming 		case 1:
908272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_10;
909272cc70bSAndy Fleming 			break;
910272cc70bSAndy Fleming 		case 2:
911272cc70bSAndy Fleming 			mmc->version = SD_VERSION_2;
9121741c64dSJaehoon Chung 			if ((mmc->scr[0] >> 15) & 0x1)
9131741c64dSJaehoon Chung 				mmc->version = SD_VERSION_3;
914272cc70bSAndy Fleming 			break;
915272cc70bSAndy Fleming 		default:
916272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
917272cc70bSAndy Fleming 			break;
918272cc70bSAndy Fleming 	}
919272cc70bSAndy Fleming 
920b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
921b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
922b44c7083SAlagu Sankar 
923272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
924272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
925272cc70bSAndy Fleming 		return 0;
926272cc70bSAndy Fleming 
927272cc70bSAndy Fleming 	timeout = 4;
928272cc70bSAndy Fleming 	while (timeout--) {
929272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
930f781dd38SAnton staaf 				(u8 *)switch_status);
931272cc70bSAndy Fleming 
932272cc70bSAndy Fleming 		if (err)
933272cc70bSAndy Fleming 			return err;
934272cc70bSAndy Fleming 
935272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
9364e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
937272cc70bSAndy Fleming 			break;
938272cc70bSAndy Fleming 	}
939272cc70bSAndy Fleming 
940272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
9414e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
942272cc70bSAndy Fleming 		return 0;
943272cc70bSAndy Fleming 
9442c3fbf4cSMacpaul Lin 	/*
9452c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
9462c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
9472c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
9482c3fbf4cSMacpaul Lin 	 * mode between the host.
9492c3fbf4cSMacpaul Lin 	 */
95093bfd616SPantelis Antoniou 	if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
95193bfd616SPantelis Antoniou 		(mmc->cfg->host_caps & MMC_MODE_HS)))
9522c3fbf4cSMacpaul Lin 		return 0;
9532c3fbf4cSMacpaul Lin 
954f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
955272cc70bSAndy Fleming 
956272cc70bSAndy Fleming 	if (err)
957272cc70bSAndy Fleming 		return err;
958272cc70bSAndy Fleming 
9594e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
960272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
961272cc70bSAndy Fleming 
962272cc70bSAndy Fleming 	return 0;
963272cc70bSAndy Fleming }
964272cc70bSAndy Fleming 
965272cc70bSAndy Fleming /* frequency bases */
966272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
9675f837c2cSMike Frysinger static const int fbase[] = {
968272cc70bSAndy Fleming 	10000,
969272cc70bSAndy Fleming 	100000,
970272cc70bSAndy Fleming 	1000000,
971272cc70bSAndy Fleming 	10000000,
972272cc70bSAndy Fleming };
973272cc70bSAndy Fleming 
974272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
975272cc70bSAndy Fleming  * to platforms without floating point.
976272cc70bSAndy Fleming  */
9775f837c2cSMike Frysinger static const int multipliers[] = {
978272cc70bSAndy Fleming 	0,	/* reserved */
979272cc70bSAndy Fleming 	10,
980272cc70bSAndy Fleming 	12,
981272cc70bSAndy Fleming 	13,
982272cc70bSAndy Fleming 	15,
983272cc70bSAndy Fleming 	20,
984272cc70bSAndy Fleming 	25,
985272cc70bSAndy Fleming 	30,
986272cc70bSAndy Fleming 	35,
987272cc70bSAndy Fleming 	40,
988272cc70bSAndy Fleming 	45,
989272cc70bSAndy Fleming 	50,
990272cc70bSAndy Fleming 	55,
991272cc70bSAndy Fleming 	60,
992272cc70bSAndy Fleming 	70,
993272cc70bSAndy Fleming 	80,
994272cc70bSAndy Fleming };
995272cc70bSAndy Fleming 
996fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
997272cc70bSAndy Fleming {
99893bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
99993bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
1000272cc70bSAndy Fleming }
1001272cc70bSAndy Fleming 
1002272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
1003272cc70bSAndy Fleming {
100493bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
100593bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1006272cc70bSAndy Fleming 
100793bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
100893bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1009272cc70bSAndy Fleming 
1010272cc70bSAndy Fleming 	mmc->clock = clock;
1011272cc70bSAndy Fleming 
1012272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1013272cc70bSAndy Fleming }
1014272cc70bSAndy Fleming 
1015fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width)
1016272cc70bSAndy Fleming {
1017272cc70bSAndy Fleming 	mmc->bus_width = width;
1018272cc70bSAndy Fleming 
1019272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1020272cc70bSAndy Fleming }
1021272cc70bSAndy Fleming 
1022fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1023272cc70bSAndy Fleming {
1024f866a46dSStephen Warren 	int err, i;
1025272cc70bSAndy Fleming 	uint mult, freq;
1026639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
1027272cc70bSAndy Fleming 	struct mmc_cmd cmd;
10288bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
10298bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
10305d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
10310c453bb7SDiego Santa Cruz 	bool has_parts = false;
10328a0cf490SDiego Santa Cruz 	bool part_completed;
1033272cc70bSAndy Fleming 
1034d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1035d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1036d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1037d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1038d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1039d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1040d52ebf10SThomas Chou 
1041d52ebf10SThomas Chou 		if (err)
1042d52ebf10SThomas Chou 			return err;
1043d52ebf10SThomas Chou 	}
1044d52ebf10SThomas Chou #endif
1045d52ebf10SThomas Chou 
1046272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1047d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1048d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1049272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1050272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1051272cc70bSAndy Fleming 
1052272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1053272cc70bSAndy Fleming 
1054272cc70bSAndy Fleming 	if (err)
1055272cc70bSAndy Fleming 		return err;
1056272cc70bSAndy Fleming 
1057272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1058272cc70bSAndy Fleming 
1059272cc70bSAndy Fleming 	/*
1060272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1061272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1062272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1063272cc70bSAndy Fleming 	 */
1064d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1065272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1066272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1067272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1068272cc70bSAndy Fleming 
1069272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1070272cc70bSAndy Fleming 
1071272cc70bSAndy Fleming 		if (err)
1072272cc70bSAndy Fleming 			return err;
1073272cc70bSAndy Fleming 
1074272cc70bSAndy Fleming 		if (IS_SD(mmc))
1075998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1076d52ebf10SThomas Chou 	}
1077272cc70bSAndy Fleming 
1078272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1079272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1080272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1081272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1082272cc70bSAndy Fleming 
1083272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1084272cc70bSAndy Fleming 
10855d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
10865d4fc8d9SRaffaele Recalcati 	mmc_send_status(mmc, timeout);
10875d4fc8d9SRaffaele Recalcati 
1088272cc70bSAndy Fleming 	if (err)
1089272cc70bSAndy Fleming 		return err;
1090272cc70bSAndy Fleming 
1091998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1092998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1093998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1094998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1095272cc70bSAndy Fleming 
1096272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
10970b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1098272cc70bSAndy Fleming 
1099272cc70bSAndy Fleming 		switch (version) {
1100272cc70bSAndy Fleming 			case 0:
1101272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
1102272cc70bSAndy Fleming 				break;
1103272cc70bSAndy Fleming 			case 1:
1104272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_4;
1105272cc70bSAndy Fleming 				break;
1106272cc70bSAndy Fleming 			case 2:
1107272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_2_2;
1108272cc70bSAndy Fleming 				break;
1109272cc70bSAndy Fleming 			case 3:
1110272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_3;
1111272cc70bSAndy Fleming 				break;
1112272cc70bSAndy Fleming 			case 4:
1113272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_4;
1114272cc70bSAndy Fleming 				break;
1115272cc70bSAndy Fleming 			default:
1116272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
1117272cc70bSAndy Fleming 				break;
1118272cc70bSAndy Fleming 		}
1119272cc70bSAndy Fleming 	}
1120272cc70bSAndy Fleming 
1121272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
11220b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
11230b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1124272cc70bSAndy Fleming 
1125272cc70bSAndy Fleming 	mmc->tran_speed = freq * mult;
1126272cc70bSAndy Fleming 
1127ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1128998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1129272cc70bSAndy Fleming 
1130272cc70bSAndy Fleming 	if (IS_SD(mmc))
1131272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1132272cc70bSAndy Fleming 	else
1133998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1134272cc70bSAndy Fleming 
1135272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1136272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1137272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1138272cc70bSAndy Fleming 		cmult = 8;
1139272cc70bSAndy Fleming 	} else {
1140272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1141272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1142272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1143272cc70bSAndy Fleming 	}
1144272cc70bSAndy Fleming 
1145f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1146f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1147f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1148f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1149f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1150f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1151272cc70bSAndy Fleming 
11528bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
11538bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1154272cc70bSAndy Fleming 
11558bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
11568bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1157272cc70bSAndy Fleming 
1158ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1159ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1160ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1161ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1162ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1163ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1164ab71188cSMarkus Niebel 	}
1165ab71188cSMarkus Niebel 
1166272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1167d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1168272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1169fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1170272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1171272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1172272cc70bSAndy Fleming 
1173272cc70bSAndy Fleming 		if (err)
1174272cc70bSAndy Fleming 			return err;
1175d52ebf10SThomas Chou 	}
1176272cc70bSAndy Fleming 
1177e6f99a56SLei Wen 	/*
1178e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1179e6f99a56SLei Wen 	 */
1180e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1181bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1182d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
1183d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
1184d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
11859cf199ebSDiego Santa Cruz 		if (err)
11869cf199ebSDiego Santa Cruz 			return err;
11879cf199ebSDiego Santa Cruz 		if (ext_csd[EXT_CSD_REV] >= 2) {
1188639b7827SYoshihiro Shimoda 			/*
1189639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
1190639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
1191639b7827SYoshihiro Shimoda 			 * than 2GB
1192639b7827SYoshihiro Shimoda 			 */
11930560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
11940560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
11950560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
11960560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
11978bfa195eSSimon Glass 			capacity *= MMC_MAX_BLOCK_LEN;
1198b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
1199f866a46dSStephen Warren 				mmc->capacity_user = capacity;
1200d23e2c09SSukumar Ghorai 		}
1201bc897b1dSLei Wen 
120264f4a619SJaehoon Chung 		switch (ext_csd[EXT_CSD_REV]) {
120364f4a619SJaehoon Chung 		case 1:
120464f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_1;
120564f4a619SJaehoon Chung 			break;
120664f4a619SJaehoon Chung 		case 2:
120764f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_2;
120864f4a619SJaehoon Chung 			break;
120964f4a619SJaehoon Chung 		case 3:
121064f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_3;
121164f4a619SJaehoon Chung 			break;
121264f4a619SJaehoon Chung 		case 5:
121364f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_41;
121464f4a619SJaehoon Chung 			break;
121564f4a619SJaehoon Chung 		case 6:
121664f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_5;
121764f4a619SJaehoon Chung 			break;
1218edab723bSMarkus Niebel 		case 7:
1219edab723bSMarkus Niebel 			mmc->version = MMC_VERSION_5_0;
1220edab723bSMarkus Niebel 			break;
122164f4a619SJaehoon Chung 		}
122264f4a619SJaehoon Chung 
12238a0cf490SDiego Santa Cruz 		/* The partition data may be non-zero but it is only
12248a0cf490SDiego Santa Cruz 		 * effective if PARTITION_SETTING_COMPLETED is set in
12258a0cf490SDiego Santa Cruz 		 * EXT_CSD, so ignore any data if this bit is not set,
12268a0cf490SDiego Santa Cruz 		 * except for enabling the high-capacity group size
12278a0cf490SDiego Santa Cruz 		 * definition (see below). */
12288a0cf490SDiego Santa Cruz 		part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
12298a0cf490SDiego Santa Cruz 				    EXT_CSD_PARTITION_SETTING_COMPLETED);
12308a0cf490SDiego Santa Cruz 
12310c453bb7SDiego Santa Cruz 		/* store the partition info of emmc */
12320c453bb7SDiego Santa Cruz 		mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
12330c453bb7SDiego Santa Cruz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
12340c453bb7SDiego Santa Cruz 		    ext_csd[EXT_CSD_BOOT_MULT])
12350c453bb7SDiego Santa Cruz 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
12368a0cf490SDiego Santa Cruz 		if (part_completed &&
12378a0cf490SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
12380c453bb7SDiego Santa Cruz 			mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
12390c453bb7SDiego Santa Cruz 
12400c453bb7SDiego Santa Cruz 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
12410c453bb7SDiego Santa Cruz 
12420c453bb7SDiego Santa Cruz 		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
12430c453bb7SDiego Santa Cruz 
12440c453bb7SDiego Santa Cruz 		for (i = 0; i < 4; i++) {
12450c453bb7SDiego Santa Cruz 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
12468a0cf490SDiego Santa Cruz 			uint mult = (ext_csd[idx + 2] << 16) +
12470c453bb7SDiego Santa Cruz 				(ext_csd[idx + 1] << 8) + ext_csd[idx];
12488a0cf490SDiego Santa Cruz 			if (mult)
12498a0cf490SDiego Santa Cruz 				has_parts = true;
12508a0cf490SDiego Santa Cruz 			if (!part_completed)
12518a0cf490SDiego Santa Cruz 				continue;
12528a0cf490SDiego Santa Cruz 			mmc->capacity_gp[i] = mult;
12530c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *=
12540c453bb7SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
12550c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1256f8e89d67SDiego Santa Cruz 			mmc->capacity_gp[i] <<= 19;
12570c453bb7SDiego Santa Cruz 		}
12580c453bb7SDiego Santa Cruz 
12598a0cf490SDiego Santa Cruz 		if (part_completed) {
1260a7f852b6SDiego Santa Cruz 			mmc->enh_user_size =
1261a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
1262a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
1263a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_SIZE_MULT];
1264a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1265a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1266a7f852b6SDiego Santa Cruz 			mmc->enh_user_size <<= 19;
1267a7f852b6SDiego Santa Cruz 			mmc->enh_user_start =
1268a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
1269a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
1270a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
1271a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_START_ADDR];
1272a7f852b6SDiego Santa Cruz 			if (mmc->high_capacity)
1273a7f852b6SDiego Santa Cruz 				mmc->enh_user_start <<= 9;
12748a0cf490SDiego Santa Cruz 		}
1275a7f852b6SDiego Santa Cruz 
1276e6f99a56SLei Wen 		/*
12771937e5aaSOliver Metz 		 * Host needs to enable ERASE_GRP_DEF bit if device is
12781937e5aaSOliver Metz 		 * partitioned. This bit will be lost every time after a reset
12791937e5aaSOliver Metz 		 * or power off. This will affect erase size.
1280e6f99a56SLei Wen 		 */
12818a0cf490SDiego Santa Cruz 		if (part_completed)
12820c453bb7SDiego Santa Cruz 			has_parts = true;
12831937e5aaSOliver Metz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
12840c453bb7SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
12850c453bb7SDiego Santa Cruz 			has_parts = true;
12860c453bb7SDiego Santa Cruz 		if (has_parts) {
12871937e5aaSOliver Metz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
12881937e5aaSOliver Metz 				EXT_CSD_ERASE_GROUP_DEF, 1);
12891937e5aaSOliver Metz 
12901937e5aaSOliver Metz 			if (err)
12911937e5aaSOliver Metz 				return err;
1292021a8055SHannes Petermaier 			else
1293021a8055SHannes Petermaier 				ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1294037dc0abSDiego Santa Cruz 		}
12951937e5aaSOliver Metz 
1296037dc0abSDiego Santa Cruz 		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
12971937e5aaSOliver Metz 			/* Read out group size from ext_csd */
12980560db18SLei Wen 			mmc->erase_grp_size =
1299a4ff9f83SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1300d7b29129SMarkus Niebel 			/*
1301d7b29129SMarkus Niebel 			 * if high capacity and partition setting completed
1302d7b29129SMarkus Niebel 			 * SEC_COUNT is valid even if it is smaller than 2 GiB
1303d7b29129SMarkus Niebel 			 * JEDEC Standard JESD84-B45, 6.2.4
1304d7b29129SMarkus Niebel 			 */
13058a0cf490SDiego Santa Cruz 			if (mmc->high_capacity && part_completed) {
1306d7b29129SMarkus Niebel 				capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1307d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1308d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1309d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1310d7b29129SMarkus Niebel 				capacity *= MMC_MAX_BLOCK_LEN;
1311d7b29129SMarkus Niebel 				mmc->capacity_user = capacity;
1312d7b29129SMarkus Niebel 			}
13138bfa195eSSimon Glass 		} else {
13141937e5aaSOliver Metz 			/* Calculate the group size from the csd value. */
1315e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
1316e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1317e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1318e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
1319e6f99a56SLei Wen 				* (erase_gmul + 1);
1320e6f99a56SLei Wen 		}
1321037dc0abSDiego Santa Cruz 
1322037dc0abSDiego Santa Cruz 		mmc->hc_wp_grp_size = 1024
1323037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1324037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
13259e41a00bSDiego Santa Cruz 
13269e41a00bSDiego Santa Cruz 		mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1327f866a46dSStephen Warren 	}
1328f866a46dSStephen Warren 
1329f866a46dSStephen Warren 	err = mmc_set_capacity(mmc, mmc->part_num);
1330f866a46dSStephen Warren 	if (err)
1331f866a46dSStephen Warren 		return err;
1332d23e2c09SSukumar Ghorai 
1333272cc70bSAndy Fleming 	if (IS_SD(mmc))
1334272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1335272cc70bSAndy Fleming 	else
1336272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1337272cc70bSAndy Fleming 
1338272cc70bSAndy Fleming 	if (err)
1339272cc70bSAndy Fleming 		return err;
1340272cc70bSAndy Fleming 
1341272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
134293bfd616SPantelis Antoniou 	mmc->card_caps &= mmc->cfg->host_caps;
1343272cc70bSAndy Fleming 
1344272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1345272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1346272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1347272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1348272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1349272cc70bSAndy Fleming 
1350272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1351272cc70bSAndy Fleming 			if (err)
1352272cc70bSAndy Fleming 				return err;
1353272cc70bSAndy Fleming 
1354272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1355272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1356272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1357272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1358272cc70bSAndy Fleming 			if (err)
1359272cc70bSAndy Fleming 				return err;
1360272cc70bSAndy Fleming 
1361272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1362272cc70bSAndy Fleming 		}
1363272cc70bSAndy Fleming 
1364272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
1365ad5fd922SJaehoon Chung 			mmc->tran_speed = 50000000;
1366272cc70bSAndy Fleming 		else
1367ad5fd922SJaehoon Chung 			mmc->tran_speed = 25000000;
1368fc5b32fbSAndrew Gabbasov 	} else if (mmc->version >= MMC_VERSION_4) {
1369fc5b32fbSAndrew Gabbasov 		/* Only version 4 of MMC supports wider bus widths */
13707798f6dbSAndy Fleming 		int idx;
13717798f6dbSAndy Fleming 
13727798f6dbSAndy Fleming 		/* An array of possible bus widths in order of preference */
13737798f6dbSAndy Fleming 		static unsigned ext_csd_bits[] = {
1374d22e3d46SJaehoon Chung 			EXT_CSD_DDR_BUS_WIDTH_8,
1375d22e3d46SJaehoon Chung 			EXT_CSD_DDR_BUS_WIDTH_4,
13767798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_8,
13777798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_4,
13787798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_1,
13797798f6dbSAndy Fleming 		};
13807798f6dbSAndy Fleming 
13817798f6dbSAndy Fleming 		/* An array to map CSD bus widths to host cap bits */
13827798f6dbSAndy Fleming 		static unsigned ext_to_hostcaps[] = {
1383786e8f81SAndrew Gabbasov 			[EXT_CSD_DDR_BUS_WIDTH_4] =
1384786e8f81SAndrew Gabbasov 				MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
1385786e8f81SAndrew Gabbasov 			[EXT_CSD_DDR_BUS_WIDTH_8] =
1386786e8f81SAndrew Gabbasov 				MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
13877798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
13887798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
13897798f6dbSAndy Fleming 		};
13907798f6dbSAndy Fleming 
13917798f6dbSAndy Fleming 		/* An array to map chosen bus width to an integer */
13927798f6dbSAndy Fleming 		static unsigned widths[] = {
1393d22e3d46SJaehoon Chung 			8, 4, 8, 4, 1,
13947798f6dbSAndy Fleming 		};
13957798f6dbSAndy Fleming 
13967798f6dbSAndy Fleming 		for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
13977798f6dbSAndy Fleming 			unsigned int extw = ext_csd_bits[idx];
1398786e8f81SAndrew Gabbasov 			unsigned int caps = ext_to_hostcaps[extw];
13997798f6dbSAndy Fleming 
14007798f6dbSAndy Fleming 			/*
1401bf477073SAndrew Gabbasov 			 * If the bus width is still not changed,
1402bf477073SAndrew Gabbasov 			 * don't try to set the default again.
1403bf477073SAndrew Gabbasov 			 * Otherwise, recover from switch attempts
1404bf477073SAndrew Gabbasov 			 * by switching to 1-bit bus width.
1405bf477073SAndrew Gabbasov 			 */
1406bf477073SAndrew Gabbasov 			if (extw == EXT_CSD_BUS_WIDTH_1 &&
1407bf477073SAndrew Gabbasov 					mmc->bus_width == 1) {
1408bf477073SAndrew Gabbasov 				err = 0;
1409bf477073SAndrew Gabbasov 				break;
1410bf477073SAndrew Gabbasov 			}
1411bf477073SAndrew Gabbasov 
1412bf477073SAndrew Gabbasov 			/*
1413786e8f81SAndrew Gabbasov 			 * Check to make sure the card and controller support
1414786e8f81SAndrew Gabbasov 			 * these capabilities
14157798f6dbSAndy Fleming 			 */
1416786e8f81SAndrew Gabbasov 			if ((mmc->card_caps & caps) != caps)
14177798f6dbSAndy Fleming 				continue;
14187798f6dbSAndy Fleming 
1419272cc70bSAndy Fleming 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
14207798f6dbSAndy Fleming 					EXT_CSD_BUS_WIDTH, extw);
1421272cc70bSAndy Fleming 
1422272cc70bSAndy Fleming 			if (err)
14234137894eSLei Wen 				continue;
1424272cc70bSAndy Fleming 
1425786e8f81SAndrew Gabbasov 			mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
14267798f6dbSAndy Fleming 			mmc_set_bus_width(mmc, widths[idx]);
1427272cc70bSAndy Fleming 
14284137894eSLei Wen 			err = mmc_send_ext_csd(mmc, test_csd);
1429272cc70bSAndy Fleming 
1430786e8f81SAndrew Gabbasov 			if (err)
1431786e8f81SAndrew Gabbasov 				continue;
1432786e8f81SAndrew Gabbasov 
1433786e8f81SAndrew Gabbasov 			/* Only compare read only fields */
1434786e8f81SAndrew Gabbasov 			if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
1435786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
1436786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
1437786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
1438786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_REV]
1439786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_REV] &&
1440786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1441786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
1442786e8f81SAndrew Gabbasov 			    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
1443786e8f81SAndrew Gabbasov 				   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
14444137894eSLei Wen 				break;
1445786e8f81SAndrew Gabbasov 			else
1446786e8f81SAndrew Gabbasov 				err = SWITCH_ERR;
14474137894eSLei Wen 		}
1448786e8f81SAndrew Gabbasov 
1449786e8f81SAndrew Gabbasov 		if (err)
1450786e8f81SAndrew Gabbasov 			return err;
1451272cc70bSAndy Fleming 
1452272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS) {
1453272cc70bSAndy Fleming 			if (mmc->card_caps & MMC_MODE_HS_52MHz)
1454ad5fd922SJaehoon Chung 				mmc->tran_speed = 52000000;
1455272cc70bSAndy Fleming 			else
1456ad5fd922SJaehoon Chung 				mmc->tran_speed = 26000000;
1457272cc70bSAndy Fleming 		}
1458ad5fd922SJaehoon Chung 	}
1459ad5fd922SJaehoon Chung 
1460ad5fd922SJaehoon Chung 	mmc_set_clock(mmc, mmc->tran_speed);
1461272cc70bSAndy Fleming 
14625af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
14635af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
14645af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
14655af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
14665af8f45cSAndrew Gabbasov 	}
14675af8f45cSAndrew Gabbasov 
1468272cc70bSAndy Fleming 	/* fill in device description */
1469272cc70bSAndy Fleming 	mmc->block_dev.lun = 0;
1470272cc70bSAndy Fleming 	mmc->block_dev.type = 0;
1471272cc70bSAndy Fleming 	mmc->block_dev.blksz = mmc->read_bl_len;
14720472fbfdSEgbert Eich 	mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz);
14739b1f942cSRabin Vincent 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
1474fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1475fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1476fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1477babce5f6STaylor Hutt 	sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x",
1478babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1479babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1480babce5f6STaylor Hutt 	sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
14810b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1482babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1483babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1484babce5f6STaylor Hutt 	sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1485babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
148656196826SPaul Burton #else
148756196826SPaul Burton 	mmc->block_dev.vendor[0] = 0;
148856196826SPaul Burton 	mmc->block_dev.product[0] = 0;
148956196826SPaul Burton 	mmc->block_dev.revision[0] = 0;
149056196826SPaul Burton #endif
1491122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1492272cc70bSAndy Fleming 	init_part(&mmc->block_dev);
1493122efd43SMikhail Kshevetskiy #endif
1494272cc70bSAndy Fleming 
1495272cc70bSAndy Fleming 	return 0;
1496272cc70bSAndy Fleming }
1497272cc70bSAndy Fleming 
1498fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1499272cc70bSAndy Fleming {
1500272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1501272cc70bSAndy Fleming 	int err;
1502272cc70bSAndy Fleming 
1503272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1504272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
150593bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1506272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1507272cc70bSAndy Fleming 
1508272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1509272cc70bSAndy Fleming 
1510272cc70bSAndy Fleming 	if (err)
1511272cc70bSAndy Fleming 		return err;
1512272cc70bSAndy Fleming 
1513998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1514272cc70bSAndy Fleming 		return UNUSABLE_ERR;
1515272cc70bSAndy Fleming 	else
1516272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1517272cc70bSAndy Fleming 
1518272cc70bSAndy Fleming 	return 0;
1519272cc70bSAndy Fleming }
1520272cc70bSAndy Fleming 
152193bfd616SPantelis Antoniou /* not used any more */
152293bfd616SPantelis Antoniou int __deprecated mmc_register(struct mmc *mmc)
1523272cc70bSAndy Fleming {
152493bfd616SPantelis Antoniou #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
152593bfd616SPantelis Antoniou 	printf("%s is deprecated! use mmc_create() instead.\n", __func__);
152693bfd616SPantelis Antoniou #endif
152793bfd616SPantelis Antoniou 	return -1;
152893bfd616SPantelis Antoniou }
152993bfd616SPantelis Antoniou 
153093bfd616SPantelis Antoniou struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
153193bfd616SPantelis Antoniou {
153293bfd616SPantelis Antoniou 	struct mmc *mmc;
153393bfd616SPantelis Antoniou 
153493bfd616SPantelis Antoniou 	/* quick validation */
153593bfd616SPantelis Antoniou 	if (cfg == NULL || cfg->ops == NULL || cfg->ops->send_cmd == NULL ||
153693bfd616SPantelis Antoniou 			cfg->f_min == 0 || cfg->f_max == 0 || cfg->b_max == 0)
153793bfd616SPantelis Antoniou 		return NULL;
153893bfd616SPantelis Antoniou 
153993bfd616SPantelis Antoniou 	mmc = calloc(1, sizeof(*mmc));
154093bfd616SPantelis Antoniou 	if (mmc == NULL)
154193bfd616SPantelis Antoniou 		return NULL;
154293bfd616SPantelis Antoniou 
154393bfd616SPantelis Antoniou 	mmc->cfg = cfg;
154493bfd616SPantelis Antoniou 	mmc->priv = priv;
154593bfd616SPantelis Antoniou 
154693bfd616SPantelis Antoniou 	/* the following chunk was mmc_register() */
154793bfd616SPantelis Antoniou 
1548ab71188cSMarkus Niebel 	/* Setup dsr related values */
1549ab71188cSMarkus Niebel 	mmc->dsr_imp = 0;
1550ab71188cSMarkus Niebel 	mmc->dsr = 0xffffffff;
1551272cc70bSAndy Fleming 	/* Setup the universal parts of the block interface just once */
1552272cc70bSAndy Fleming 	mmc->block_dev.if_type = IF_TYPE_MMC;
1553272cc70bSAndy Fleming 	mmc->block_dev.dev = cur_dev_num++;
1554272cc70bSAndy Fleming 	mmc->block_dev.removable = 1;
1555272cc70bSAndy Fleming 	mmc->block_dev.block_read = mmc_bread;
1556272cc70bSAndy Fleming 	mmc->block_dev.block_write = mmc_bwrite;
1557e6f99a56SLei Wen 	mmc->block_dev.block_erase = mmc_berase;
155893bfd616SPantelis Antoniou 
155993bfd616SPantelis Antoniou 	/* setup initial part type */
156093bfd616SPantelis Antoniou 	mmc->block_dev.part_type = mmc->cfg->part_type;
1561272cc70bSAndy Fleming 
1562272cc70bSAndy Fleming 	INIT_LIST_HEAD(&mmc->link);
1563272cc70bSAndy Fleming 
1564272cc70bSAndy Fleming 	list_add_tail(&mmc->link, &mmc_devices);
1565272cc70bSAndy Fleming 
156693bfd616SPantelis Antoniou 	return mmc;
156793bfd616SPantelis Antoniou }
156893bfd616SPantelis Antoniou 
156993bfd616SPantelis Antoniou void mmc_destroy(struct mmc *mmc)
157093bfd616SPantelis Antoniou {
157193bfd616SPantelis Antoniou 	/* only freeing memory for now */
157293bfd616SPantelis Antoniou 	free(mmc);
1573272cc70bSAndy Fleming }
1574272cc70bSAndy Fleming 
1575df3fc526SMatthew McClintock #ifdef CONFIG_PARTITIONS
1576272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev)
1577272cc70bSAndy Fleming {
1578272cc70bSAndy Fleming 	struct mmc *mmc = find_mmc_device(dev);
15796bb4b4bcSBenoît Thébaudeau 	if (!mmc || mmc_init(mmc))
158040242bc3SŁukasz Majewski 		return NULL;
1581272cc70bSAndy Fleming 
158240242bc3SŁukasz Majewski 	return &mmc->block_dev;
1583272cc70bSAndy Fleming }
1584df3fc526SMatthew McClintock #endif
1585272cc70bSAndy Fleming 
158695de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
158795de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
158895de9ab2SPaul Kocialkowski {
158995de9ab2SPaul Kocialkowski }
159095de9ab2SPaul Kocialkowski 
1591e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1592272cc70bSAndy Fleming {
1593afd5932bSMacpaul Lin 	int err;
1594272cc70bSAndy Fleming 
1595ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
159693bfd616SPantelis Antoniou 	if (mmc_getcd(mmc) == 0 || mmc->cfg->ops->init == NULL) {
159748972d90SThierry Reding 		mmc->has_init = 0;
159856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
159948972d90SThierry Reding 		printf("MMC: no card present\n");
160056196826SPaul Burton #endif
160148972d90SThierry Reding 		return NO_CARD_ERR;
160248972d90SThierry Reding 	}
160348972d90SThierry Reding 
1604bc897b1dSLei Wen 	if (mmc->has_init)
1605bc897b1dSLei Wen 		return 0;
1606bc897b1dSLei Wen 
16075a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
16085a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
16095a8dbdc6SYangbo Lu #endif
161095de9ab2SPaul Kocialkowski 	board_mmc_power_init();
161195de9ab2SPaul Kocialkowski 
1612ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
161393bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
1614272cc70bSAndy Fleming 
1615272cc70bSAndy Fleming 	if (err)
1616272cc70bSAndy Fleming 		return err;
1617272cc70bSAndy Fleming 
1618786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
1619b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1620b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1621b86b85e2SIlya Yanok 
1622272cc70bSAndy Fleming 	/* Reset the Card */
1623272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1624272cc70bSAndy Fleming 
1625272cc70bSAndy Fleming 	if (err)
1626272cc70bSAndy Fleming 		return err;
1627272cc70bSAndy Fleming 
1628bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1629bc897b1dSLei Wen 	mmc->part_num = 0;
1630bc897b1dSLei Wen 
1631272cc70bSAndy Fleming 	/* Test for SD version 2 */
1632272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1633272cc70bSAndy Fleming 
1634272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1635272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1636272cc70bSAndy Fleming 
1637272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1638272cc70bSAndy Fleming 	if (err == TIMEOUT) {
1639272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1640272cc70bSAndy Fleming 
1641bd47c135SAndrew Gabbasov 		if (err) {
164256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1643272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
164456196826SPaul Burton #endif
1645272cc70bSAndy Fleming 			return UNUSABLE_ERR;
1646272cc70bSAndy Fleming 		}
1647272cc70bSAndy Fleming 	}
1648272cc70bSAndy Fleming 
1649bd47c135SAndrew Gabbasov 	if (!err)
1650e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
1651e9550449SChe-Liang Chiou 
1652e9550449SChe-Liang Chiou 	return err;
1653e9550449SChe-Liang Chiou }
1654e9550449SChe-Liang Chiou 
1655e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
1656e9550449SChe-Liang Chiou {
1657e9550449SChe-Liang Chiou 	int err = 0;
1658e9550449SChe-Liang Chiou 
1659bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
1660e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
1661e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
1662e9550449SChe-Liang Chiou 
1663e9550449SChe-Liang Chiou 	if (!err)
1664bc897b1dSLei Wen 		err = mmc_startup(mmc);
1665bc897b1dSLei Wen 	if (err)
1666bc897b1dSLei Wen 		mmc->has_init = 0;
1667bc897b1dSLei Wen 	else
1668bc897b1dSLei Wen 		mmc->has_init = 1;
1669e9550449SChe-Liang Chiou 	return err;
1670e9550449SChe-Liang Chiou }
1671e9550449SChe-Liang Chiou 
1672e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
1673e9550449SChe-Liang Chiou {
1674bd47c135SAndrew Gabbasov 	int err = 0;
1675d803fea5SMateusz Zalega 	unsigned start;
1676e9550449SChe-Liang Chiou 
1677e9550449SChe-Liang Chiou 	if (mmc->has_init)
1678e9550449SChe-Liang Chiou 		return 0;
1679d803fea5SMateusz Zalega 
1680d803fea5SMateusz Zalega 	start = get_timer(0);
1681d803fea5SMateusz Zalega 
1682e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
1683e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
1684e9550449SChe-Liang Chiou 
1685bd47c135SAndrew Gabbasov 	if (!err)
1686e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
1687e9550449SChe-Liang Chiou 	debug("%s: %d, time %lu\n", __func__, err, get_timer(start));
1688bc897b1dSLei Wen 	return err;
1689272cc70bSAndy Fleming }
1690272cc70bSAndy Fleming 
1691ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
1692ab71188cSMarkus Niebel {
1693ab71188cSMarkus Niebel 	mmc->dsr = val;
1694ab71188cSMarkus Niebel 	return 0;
1695ab71188cSMarkus Niebel }
1696ab71188cSMarkus Niebel 
1697cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
1698cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
1699272cc70bSAndy Fleming {
1700272cc70bSAndy Fleming 	return -1;
1701272cc70bSAndy Fleming }
1702272cc70bSAndy Fleming 
1703cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
1704cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
1705cee9ab7cSJeroen Hofstee {
1706cee9ab7cSJeroen Hofstee 	return -1;
1707cee9ab7cSJeroen Hofstee }
1708272cc70bSAndy Fleming 
170956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
171056196826SPaul Burton 
1711272cc70bSAndy Fleming void print_mmc_devices(char separator)
1712272cc70bSAndy Fleming {
1713272cc70bSAndy Fleming 	struct mmc *m;
1714272cc70bSAndy Fleming 	struct list_head *entry;
171534dd9284SPrzemyslaw Marczak 	char *mmc_type;
1716272cc70bSAndy Fleming 
1717272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
1718272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
1719272cc70bSAndy Fleming 
172034dd9284SPrzemyslaw Marczak 		if (m->has_init)
172134dd9284SPrzemyslaw Marczak 			mmc_type = IS_SD(m) ? "SD" : "eMMC";
172234dd9284SPrzemyslaw Marczak 		else
172334dd9284SPrzemyslaw Marczak 			mmc_type = NULL;
172434dd9284SPrzemyslaw Marczak 
172593bfd616SPantelis Antoniou 		printf("%s: %d", m->cfg->name, m->block_dev.dev);
172634dd9284SPrzemyslaw Marczak 		if (mmc_type)
172734dd9284SPrzemyslaw Marczak 			printf(" (%s)", mmc_type);
1728272cc70bSAndy Fleming 
1729e75eaf10SLubomir Popov 		if (entry->next != &mmc_devices) {
1730272cc70bSAndy Fleming 			printf("%c", separator);
1731e75eaf10SLubomir Popov 			if (separator != '\n')
1732e75eaf10SLubomir Popov 				puts (" ");
1733e75eaf10SLubomir Popov 		}
1734272cc70bSAndy Fleming 	}
1735272cc70bSAndy Fleming 
1736272cc70bSAndy Fleming 	printf("\n");
1737272cc70bSAndy Fleming }
1738272cc70bSAndy Fleming 
173956196826SPaul Burton #else
174056196826SPaul Burton void print_mmc_devices(char separator) { }
174156196826SPaul Burton #endif
174256196826SPaul Burton 
1743ea6ebe21SLei Wen int get_mmc_num(void)
1744ea6ebe21SLei Wen {
1745ea6ebe21SLei Wen 	return cur_dev_num;
1746ea6ebe21SLei Wen }
1747ea6ebe21SLei Wen 
1748e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
1749e9550449SChe-Liang Chiou {
1750e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
1751e9550449SChe-Liang Chiou }
1752e9550449SChe-Liang Chiou 
1753e9550449SChe-Liang Chiou static void do_preinit(void)
1754e9550449SChe-Liang Chiou {
1755e9550449SChe-Liang Chiou 	struct mmc *m;
1756e9550449SChe-Liang Chiou 	struct list_head *entry;
1757e9550449SChe-Liang Chiou 
1758e9550449SChe-Liang Chiou 	list_for_each(entry, &mmc_devices) {
1759e9550449SChe-Liang Chiou 		m = list_entry(entry, struct mmc, link);
1760e9550449SChe-Liang Chiou 
17615a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
17625a8dbdc6SYangbo Lu 		mmc_set_preinit(m, 1);
17635a8dbdc6SYangbo Lu #endif
1764e9550449SChe-Liang Chiou 		if (m->preinit)
1765e9550449SChe-Liang Chiou 			mmc_start_init(m);
1766e9550449SChe-Liang Chiou 	}
1767e9550449SChe-Liang Chiou }
1768e9550449SChe-Liang Chiou 
17698e3332e2SSjoerd Simons #if defined(CONFIG_DM_MMC) && defined(CONFIG_SPL_BUILD)
17708e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
17718e3332e2SSjoerd Simons {
17728e3332e2SSjoerd Simons 	return 0;
17738e3332e2SSjoerd Simons }
17748e3332e2SSjoerd Simons #elif defined(CONFIG_DM_MMC)
17758e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
17768e3332e2SSjoerd Simons {
17778e3332e2SSjoerd Simons 	int ret;
17788e3332e2SSjoerd Simons 	struct uclass *uc;
17798e3332e2SSjoerd Simons 	struct udevice *m;
17808e3332e2SSjoerd Simons 
17818e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
17828e3332e2SSjoerd Simons 	if (ret)
17838e3332e2SSjoerd Simons 		return ret;
17848e3332e2SSjoerd Simons 
17858e3332e2SSjoerd Simons 	uclass_foreach_dev(m, uc) {
17868e3332e2SSjoerd Simons 		ret = device_probe(m);
17878e3332e2SSjoerd Simons 		if (ret)
17888e3332e2SSjoerd Simons 			printf("%s - probe failed: %d\n", m->name, ret);
17898e3332e2SSjoerd Simons 	}
17908e3332e2SSjoerd Simons 
17918e3332e2SSjoerd Simons 	return 0;
17928e3332e2SSjoerd Simons }
17938e3332e2SSjoerd Simons #else
17948e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
17958e3332e2SSjoerd Simons {
17968e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
17978e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
17988e3332e2SSjoerd Simons 
17998e3332e2SSjoerd Simons 	return 0;
18008e3332e2SSjoerd Simons }
18018e3332e2SSjoerd Simons #endif
1802e9550449SChe-Liang Chiou 
1803272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1804272cc70bSAndy Fleming {
18051b26bab1SDaniel Kochmański 	static int initialized = 0;
18068e3332e2SSjoerd Simons 	int ret;
18071b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
18081b26bab1SDaniel Kochmański 		return 0;
18091b26bab1SDaniel Kochmański 	initialized = 1;
18101b26bab1SDaniel Kochmański 
1811272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc_devices);
1812272cc70bSAndy Fleming 	cur_dev_num = 0;
1813272cc70bSAndy Fleming 
18148e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
18158e3332e2SSjoerd Simons 	if (ret)
18168e3332e2SSjoerd Simons 		return ret;
1817272cc70bSAndy Fleming 
1818bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
1819272cc70bSAndy Fleming 	print_mmc_devices(',');
1820bb0dc108SYing Zhang #endif
1821272cc70bSAndy Fleming 
1822e9550449SChe-Liang Chiou 	do_preinit();
1823272cc70bSAndy Fleming 	return 0;
1824272cc70bSAndy Fleming }
18253690d6d6SAmar 
18263690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT
18273690d6d6SAmar /*
18283690d6d6SAmar  * This function changes the size of boot partition and the size of rpmb
18293690d6d6SAmar  * partition present on EMMC devices.
18303690d6d6SAmar  *
18313690d6d6SAmar  * Input Parameters:
18323690d6d6SAmar  * struct *mmc: pointer for the mmc device strcuture
18333690d6d6SAmar  * bootsize: size of boot partition
18343690d6d6SAmar  * rpmbsize: size of rpmb partition
18353690d6d6SAmar  *
18363690d6d6SAmar  * Returns 0 on success.
18373690d6d6SAmar  */
18383690d6d6SAmar 
18393690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
18403690d6d6SAmar 				unsigned long rpmbsize)
18413690d6d6SAmar {
18423690d6d6SAmar 	int err;
18433690d6d6SAmar 	struct mmc_cmd cmd;
18443690d6d6SAmar 
18453690d6d6SAmar 	/* Only use this command for raw EMMC moviNAND. Enter backdoor mode */
18463690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18473690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18483690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG1;
18493690d6d6SAmar 
18503690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18513690d6d6SAmar 	if (err) {
18523690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error1 = %d\n", err);
18533690d6d6SAmar 		return err;
18543690d6d6SAmar 	}
18553690d6d6SAmar 
18563690d6d6SAmar 	/* Boot partition changing mode */
18573690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18583690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18593690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG2;
18603690d6d6SAmar 
18613690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18623690d6d6SAmar 	if (err) {
18633690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error2 = %d\n", err);
18643690d6d6SAmar 		return err;
18653690d6d6SAmar 	}
18663690d6d6SAmar 	/* boot partition size is multiple of 128KB */
18673690d6d6SAmar 	bootsize = (bootsize * 1024) / 128;
18683690d6d6SAmar 
18693690d6d6SAmar 	/* Arg: boot partition size */
18703690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18713690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18723690d6d6SAmar 	cmd.cmdarg = bootsize;
18733690d6d6SAmar 
18743690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18753690d6d6SAmar 	if (err) {
18763690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error3 = %d\n", err);
18773690d6d6SAmar 		return err;
18783690d6d6SAmar 	}
18793690d6d6SAmar 	/* RPMB partition size is multiple of 128KB */
18803690d6d6SAmar 	rpmbsize = (rpmbsize * 1024) / 128;
18813690d6d6SAmar 	/* Arg: RPMB partition size */
18823690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18833690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18843690d6d6SAmar 	cmd.cmdarg = rpmbsize;
18853690d6d6SAmar 
18863690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18873690d6d6SAmar 	if (err) {
18883690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error4 = %d\n", err);
18893690d6d6SAmar 		return err;
18903690d6d6SAmar 	}
18913690d6d6SAmar 	return 0;
18923690d6d6SAmar }
18933690d6d6SAmar 
18943690d6d6SAmar /*
18955a99b9deSTom Rini  * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH
18965a99b9deSTom Rini  * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH
18975a99b9deSTom Rini  * and BOOT_MODE.
18985a99b9deSTom Rini  *
18995a99b9deSTom Rini  * Returns 0 on success.
19005a99b9deSTom Rini  */
19015a99b9deSTom Rini int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode)
19025a99b9deSTom Rini {
19035a99b9deSTom Rini 	int err;
19045a99b9deSTom Rini 
19055a99b9deSTom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH,
19065a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) |
19075a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) |
19085a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width));
19095a99b9deSTom Rini 
19105a99b9deSTom Rini 	if (err)
19115a99b9deSTom Rini 		return err;
19125a99b9deSTom Rini 	return 0;
19135a99b9deSTom Rini }
19145a99b9deSTom Rini 
19155a99b9deSTom Rini /*
1916792970b0STom Rini  * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG)
1917792970b0STom Rini  * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and
1918792970b0STom Rini  * PARTITION_ACCESS.
1919792970b0STom Rini  *
1920792970b0STom Rini  * Returns 0 on success.
1921792970b0STom Rini  */
1922792970b0STom Rini int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access)
1923792970b0STom Rini {
1924792970b0STom Rini 	int err;
1925792970b0STom Rini 
1926792970b0STom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
1927792970b0STom Rini 			 EXT_CSD_BOOT_ACK(ack) |
1928792970b0STom Rini 			 EXT_CSD_BOOT_PART_NUM(part_num) |
1929792970b0STom Rini 			 EXT_CSD_PARTITION_ACCESS(access));
1930792970b0STom Rini 
1931792970b0STom Rini 	if (err)
1932792970b0STom Rini 		return err;
1933792970b0STom Rini 	return 0;
1934792970b0STom Rini }
193533ace362STom Rini 
193633ace362STom Rini /*
193733ace362STom Rini  * Modify EXT_CSD[162] which is RST_n_FUNCTION based on the given value
193833ace362STom Rini  * for enable.  Note that this is a write-once field for non-zero values.
193933ace362STom Rini  *
194033ace362STom Rini  * Returns 0 on success.
194133ace362STom Rini  */
194233ace362STom Rini int mmc_set_rst_n_function(struct mmc *mmc, u8 enable)
194333ace362STom Rini {
194433ace362STom Rini 	return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_RST_N_FUNCTION,
194533ace362STom Rini 			  enable);
194633ace362STom Rini }
19473690d6d6SAmar #endif
1948