xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision bd47c13583f2c4bbd29914063d2bf3a98fcdf5cb)
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>
13d4622df3SStephen Warren #include <errno.h>
14272cc70bSAndy Fleming #include <mmc.h>
15272cc70bSAndy Fleming #include <part.h>
16272cc70bSAndy Fleming #include <malloc.h>
17272cc70bSAndy Fleming #include <linux/list.h>
189b1f942cSRabin Vincent #include <div64.h>
19da61fa5fSPaul Burton #include "mmc_private.h"
20272cc70bSAndy Fleming 
21272cc70bSAndy Fleming static struct list_head mmc_devices;
22272cc70bSAndy Fleming static int cur_dev_num = -1;
23272cc70bSAndy Fleming 
24750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
25d23d8d7eSNikita Kiryanov {
26d23d8d7eSNikita Kiryanov 	return -1;
27d23d8d7eSNikita Kiryanov }
28d23d8d7eSNikita Kiryanov 
29d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
30d23d8d7eSNikita Kiryanov {
31d23d8d7eSNikita Kiryanov 	int wp;
32d23d8d7eSNikita Kiryanov 
33d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
34d23d8d7eSNikita Kiryanov 
35d4e1da4eSPeter Korsgaard 	if (wp < 0) {
3693bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
3793bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
38d4e1da4eSPeter Korsgaard 		else
39d4e1da4eSPeter Korsgaard 			wp = 0;
40d4e1da4eSPeter Korsgaard 	}
41d23d8d7eSNikita Kiryanov 
42d23d8d7eSNikita Kiryanov 	return wp;
43d23d8d7eSNikita Kiryanov }
44d23d8d7eSNikita Kiryanov 
45cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc)
46cee9ab7cSJeroen Hofstee {
4711fdade2SStefano Babic 	return -1;
4811fdade2SStefano Babic }
4911fdade2SStefano Babic 
50da61fa5fSPaul Burton int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
51272cc70bSAndy Fleming {
525db2fe3aSRaffaele Recalcati 	int ret;
538635ff9eSMarek Vasut 
548635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
555db2fe3aSRaffaele Recalcati 	int i;
565db2fe3aSRaffaele Recalcati 	u8 *ptr;
575db2fe3aSRaffaele Recalcati 
585db2fe3aSRaffaele Recalcati 	printf("CMD_SEND:%d\n", cmd->cmdidx);
595db2fe3aSRaffaele Recalcati 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
6093bfd616SPantelis Antoniou 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
615db2fe3aSRaffaele Recalcati 	switch (cmd->resp_type) {
625db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
635db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
645db2fe3aSRaffaele Recalcati 			break;
655db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
665db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
675db2fe3aSRaffaele Recalcati 				cmd->response[0]);
685db2fe3aSRaffaele Recalcati 			break;
695db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
705db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
715db2fe3aSRaffaele Recalcati 				cmd->response[0]);
725db2fe3aSRaffaele Recalcati 			break;
735db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
745db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
755db2fe3aSRaffaele Recalcati 				cmd->response[0]);
765db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
775db2fe3aSRaffaele Recalcati 				cmd->response[1]);
785db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
795db2fe3aSRaffaele Recalcati 				cmd->response[2]);
805db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
815db2fe3aSRaffaele Recalcati 				cmd->response[3]);
825db2fe3aSRaffaele Recalcati 			printf("\n");
835db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
845db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
855db2fe3aSRaffaele Recalcati 				int j;
865db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
87146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
885db2fe3aSRaffaele Recalcati 				ptr += 3;
895db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
905db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
915db2fe3aSRaffaele Recalcati 				printf("\n");
925db2fe3aSRaffaele Recalcati 			}
935db2fe3aSRaffaele Recalcati 			break;
945db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
955db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
965db2fe3aSRaffaele Recalcati 				cmd->response[0]);
975db2fe3aSRaffaele Recalcati 			break;
985db2fe3aSRaffaele Recalcati 		default:
995db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1005db2fe3aSRaffaele Recalcati 			break;
1015db2fe3aSRaffaele Recalcati 	}
1025db2fe3aSRaffaele Recalcati #else
10393bfd616SPantelis Antoniou 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
1045db2fe3aSRaffaele Recalcati #endif
1058635ff9eSMarek Vasut 	return ret;
106272cc70bSAndy Fleming }
107272cc70bSAndy Fleming 
108da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
1095d4fc8d9SRaffaele Recalcati {
1105d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
111d617c426SJan Kloetzke 	int err, retries = 5;
1125d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
1135d4fc8d9SRaffaele Recalcati 	int status;
1145d4fc8d9SRaffaele Recalcati #endif
1155d4fc8d9SRaffaele Recalcati 
1165d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
1175d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
118aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
119aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
1205d4fc8d9SRaffaele Recalcati 
1211677eef4SAndrew Gabbasov 	while (1) {
1225d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
123d617c426SJan Kloetzke 		if (!err) {
124d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
125d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
126d617c426SJan Kloetzke 			     MMC_STATE_PRG)
1275d4fc8d9SRaffaele Recalcati 				break;
128d617c426SJan Kloetzke 			else if (cmd.response[0] & MMC_STATUS_MASK) {
12956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
130d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
131d617c426SJan Kloetzke 					cmd.response[0]);
13256196826SPaul Burton #endif
133d617c426SJan Kloetzke 				return COMM_ERR;
134d617c426SJan Kloetzke 			}
135d617c426SJan Kloetzke 		} else if (--retries < 0)
136d617c426SJan Kloetzke 			return err;
1375d4fc8d9SRaffaele Recalcati 
1381677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
1391677eef4SAndrew Gabbasov 			break;
1405d4fc8d9SRaffaele Recalcati 
1411677eef4SAndrew Gabbasov 		udelay(1000);
1421677eef4SAndrew Gabbasov 	}
1435d4fc8d9SRaffaele Recalcati 
1445db2fe3aSRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
1455db2fe3aSRaffaele Recalcati 	status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9;
1465db2fe3aSRaffaele Recalcati 	printf("CURR STATE:%d\n", status);
1475db2fe3aSRaffaele Recalcati #endif
1485b0c942fSJongman Heo 	if (timeout <= 0) {
14956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1505d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
15156196826SPaul Burton #endif
1525d4fc8d9SRaffaele Recalcati 		return TIMEOUT;
1535d4fc8d9SRaffaele Recalcati 	}
1546b2221b0SAndrew Gabbasov 	if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR)
1556b2221b0SAndrew Gabbasov 		return SWITCH_ERR;
1565d4fc8d9SRaffaele Recalcati 
1575d4fc8d9SRaffaele Recalcati 	return 0;
1585d4fc8d9SRaffaele Recalcati }
1595d4fc8d9SRaffaele Recalcati 
160da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
161272cc70bSAndy Fleming {
162272cc70bSAndy Fleming 	struct mmc_cmd cmd;
163272cc70bSAndy Fleming 
164786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
165d22e3d46SJaehoon Chung 		return 0;
166d22e3d46SJaehoon Chung 
167272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
168272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
169272cc70bSAndy Fleming 	cmd.cmdarg = len;
170272cc70bSAndy Fleming 
171272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
172272cc70bSAndy Fleming }
173272cc70bSAndy Fleming 
174272cc70bSAndy Fleming struct mmc *find_mmc_device(int dev_num)
175272cc70bSAndy Fleming {
176272cc70bSAndy Fleming 	struct mmc *m;
177272cc70bSAndy Fleming 	struct list_head *entry;
178272cc70bSAndy Fleming 
179272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
180272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
181272cc70bSAndy Fleming 
182272cc70bSAndy Fleming 		if (m->block_dev.dev == dev_num)
183272cc70bSAndy Fleming 			return m;
184272cc70bSAndy Fleming 	}
185272cc70bSAndy Fleming 
18656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
187272cc70bSAndy Fleming 	printf("MMC Device %d not found\n", dev_num);
18856196826SPaul Burton #endif
189272cc70bSAndy Fleming 
190272cc70bSAndy Fleming 	return NULL;
191272cc70bSAndy Fleming }
192272cc70bSAndy Fleming 
193ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
194fdbb873eSKim Phillips 			   lbaint_t blkcnt)
195272cc70bSAndy Fleming {
196272cc70bSAndy Fleming 	struct mmc_cmd cmd;
197272cc70bSAndy Fleming 	struct mmc_data data;
198272cc70bSAndy Fleming 
1994a1a06bcSAlagu Sankar 	if (blkcnt > 1)
2004a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
2014a1a06bcSAlagu Sankar 	else
202272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
203272cc70bSAndy Fleming 
204272cc70bSAndy Fleming 	if (mmc->high_capacity)
2054a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
206272cc70bSAndy Fleming 	else
2074a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
208272cc70bSAndy Fleming 
209272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
210272cc70bSAndy Fleming 
211272cc70bSAndy Fleming 	data.dest = dst;
2124a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
213272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
214272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
215272cc70bSAndy Fleming 
2164a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
2174a1a06bcSAlagu Sankar 		return 0;
2184a1a06bcSAlagu Sankar 
2194a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
2204a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
2214a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
2224a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
2234a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
22456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2254a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
22656196826SPaul Burton #endif
2274a1a06bcSAlagu Sankar 			return 0;
2284a1a06bcSAlagu Sankar 		}
229272cc70bSAndy Fleming 	}
230272cc70bSAndy Fleming 
2314a1a06bcSAlagu Sankar 	return blkcnt;
232272cc70bSAndy Fleming }
233272cc70bSAndy Fleming 
234ff8fef56SSascha Silbe static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst)
235272cc70bSAndy Fleming {
2364a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
237272cc70bSAndy Fleming 
2384a1a06bcSAlagu Sankar 	if (blkcnt == 0)
2394a1a06bcSAlagu Sankar 		return 0;
2404a1a06bcSAlagu Sankar 
2414a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
242272cc70bSAndy Fleming 	if (!mmc)
243272cc70bSAndy Fleming 		return 0;
244272cc70bSAndy Fleming 
245d2bf29e3SLei Wen 	if ((start + blkcnt) > mmc->block_dev.lba) {
24656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
247ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
248d2bf29e3SLei Wen 			start + blkcnt, mmc->block_dev.lba);
24956196826SPaul Burton #endif
250d2bf29e3SLei Wen 		return 0;
251d2bf29e3SLei Wen 	}
252272cc70bSAndy Fleming 
2534a1a06bcSAlagu Sankar 	if (mmc_set_blocklen(mmc, mmc->read_bl_len))
254272cc70bSAndy Fleming 		return 0;
255272cc70bSAndy Fleming 
2564a1a06bcSAlagu Sankar 	do {
25793bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
25893bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
2594a1a06bcSAlagu Sankar 		if(mmc_read_blocks(mmc, dst, start, cur) != cur)
2604a1a06bcSAlagu Sankar 			return 0;
2614a1a06bcSAlagu Sankar 		blocks_todo -= cur;
2624a1a06bcSAlagu Sankar 		start += cur;
2634a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
2644a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
265272cc70bSAndy Fleming 
266272cc70bSAndy Fleming 	return blkcnt;
267272cc70bSAndy Fleming }
268272cc70bSAndy Fleming 
269fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
270272cc70bSAndy Fleming {
271272cc70bSAndy Fleming 	struct mmc_cmd cmd;
272272cc70bSAndy Fleming 	int err;
273272cc70bSAndy Fleming 
274272cc70bSAndy Fleming 	udelay(1000);
275272cc70bSAndy Fleming 
276272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
277272cc70bSAndy Fleming 	cmd.cmdarg = 0;
278272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
279272cc70bSAndy Fleming 
280272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
281272cc70bSAndy Fleming 
282272cc70bSAndy Fleming 	if (err)
283272cc70bSAndy Fleming 		return err;
284272cc70bSAndy Fleming 
285272cc70bSAndy Fleming 	udelay(2000);
286272cc70bSAndy Fleming 
287272cc70bSAndy Fleming 	return 0;
288272cc70bSAndy Fleming }
289272cc70bSAndy Fleming 
290fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
291272cc70bSAndy Fleming {
292272cc70bSAndy Fleming 	int timeout = 1000;
293272cc70bSAndy Fleming 	int err;
294272cc70bSAndy Fleming 	struct mmc_cmd cmd;
295272cc70bSAndy Fleming 
2961677eef4SAndrew Gabbasov 	while (1) {
297272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
298272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
299272cc70bSAndy Fleming 		cmd.cmdarg = 0;
300272cc70bSAndy Fleming 
301272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
302272cc70bSAndy Fleming 
303272cc70bSAndy Fleming 		if (err)
304272cc70bSAndy Fleming 			return err;
305272cc70bSAndy Fleming 
306272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
307272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
308250de12bSStefano Babic 
309250de12bSStefano Babic 		/*
310250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
311250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
312250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
313250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
314250de12bSStefano Babic 		 * specified.
315250de12bSStefano Babic 		 */
316d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
31793bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
318272cc70bSAndy Fleming 
319272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
320272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
321272cc70bSAndy Fleming 
322272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
323272cc70bSAndy Fleming 
324272cc70bSAndy Fleming 		if (err)
325272cc70bSAndy Fleming 			return err;
326272cc70bSAndy Fleming 
3271677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
3281677eef4SAndrew Gabbasov 			break;
329272cc70bSAndy Fleming 
3301677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
331272cc70bSAndy Fleming 			return UNUSABLE_ERR;
332272cc70bSAndy Fleming 
3331677eef4SAndrew Gabbasov 		udelay(1000);
3341677eef4SAndrew Gabbasov 	}
3351677eef4SAndrew Gabbasov 
336272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
337272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
338272cc70bSAndy Fleming 
339d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
340d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
341d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
342d52ebf10SThomas Chou 		cmd.cmdarg = 0;
343d52ebf10SThomas Chou 
344d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
345d52ebf10SThomas Chou 
346d52ebf10SThomas Chou 		if (err)
347d52ebf10SThomas Chou 			return err;
348d52ebf10SThomas Chou 	}
349d52ebf10SThomas Chou 
350998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
351272cc70bSAndy Fleming 
352272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
353272cc70bSAndy Fleming 	mmc->rca = 0;
354272cc70bSAndy Fleming 
355272cc70bSAndy Fleming 	return 0;
356272cc70bSAndy Fleming }
357272cc70bSAndy Fleming 
3585289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
359272cc70bSAndy Fleming {
3605289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
361272cc70bSAndy Fleming 	int err;
362272cc70bSAndy Fleming 
3635289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
3645289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
3655289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
366e9550449SChe-Liang Chiou 	if (use_arg && !mmc_host_is_spi(mmc)) {
3675289b535SAndrew Gabbasov 		cmd.cmdarg =
36893bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
369a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
370a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
371e9550449SChe-Liang Chiou 
37293bfd616SPantelis Antoniou 		if (mmc->cfg->host_caps & MMC_MODE_HC)
3735289b535SAndrew Gabbasov 			cmd.cmdarg |= OCR_HCS;
374e9550449SChe-Liang Chiou 	}
3755289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
376e9550449SChe-Liang Chiou 	if (err)
377e9550449SChe-Liang Chiou 		return err;
3785289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
379e9550449SChe-Liang Chiou 	return 0;
380e9550449SChe-Liang Chiou }
381e9550449SChe-Liang Chiou 
382750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
383e9550449SChe-Liang Chiou {
384e9550449SChe-Liang Chiou 	int err, i;
385e9550449SChe-Liang Chiou 
386272cc70bSAndy Fleming 	/* Some cards seem to need this */
387272cc70bSAndy Fleming 	mmc_go_idle(mmc);
388272cc70bSAndy Fleming 
38931cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
390e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
3915289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
39231cacbabSRaffaele Recalcati 		if (err)
39331cacbabSRaffaele Recalcati 			return err;
39431cacbabSRaffaele Recalcati 
395e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
396a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
397*bd47c135SAndrew Gabbasov 			break;
398e9550449SChe-Liang Chiou 	}
399*bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
400*bd47c135SAndrew Gabbasov 	return 0;
401e9550449SChe-Liang Chiou }
40231cacbabSRaffaele Recalcati 
403750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
404e9550449SChe-Liang Chiou {
405e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
406e9550449SChe-Liang Chiou 	int timeout = 1000;
407e9550449SChe-Liang Chiou 	uint start;
408e9550449SChe-Liang Chiou 	int err;
409e9550449SChe-Liang Chiou 
410e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
411cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
412e9550449SChe-Liang Chiou 		start = get_timer(0);
4131677eef4SAndrew Gabbasov 		while (1) {
4145289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
415272cc70bSAndy Fleming 			if (err)
416272cc70bSAndy Fleming 				return err;
4171677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
4181677eef4SAndrew Gabbasov 				break;
419e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
420272cc70bSAndy Fleming 				return UNUSABLE_ERR;
421e9550449SChe-Liang Chiou 			udelay(100);
4221677eef4SAndrew Gabbasov 		}
423cc17c01fSAndrew Gabbasov 	}
424272cc70bSAndy Fleming 
425d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
426d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
427d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
428d52ebf10SThomas Chou 		cmd.cmdarg = 0;
429d52ebf10SThomas Chou 
430d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
431d52ebf10SThomas Chou 
432d52ebf10SThomas Chou 		if (err)
433d52ebf10SThomas Chou 			return err;
434a626c8d4SAndrew Gabbasov 
435a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
436d52ebf10SThomas Chou 	}
437d52ebf10SThomas Chou 
438272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
439272cc70bSAndy Fleming 
440272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
441def816a2SStephen Warren 	mmc->rca = 1;
442272cc70bSAndy Fleming 
443272cc70bSAndy Fleming 	return 0;
444272cc70bSAndy Fleming }
445272cc70bSAndy Fleming 
446272cc70bSAndy Fleming 
447fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
448272cc70bSAndy Fleming {
449272cc70bSAndy Fleming 	struct mmc_cmd cmd;
450272cc70bSAndy Fleming 	struct mmc_data data;
451272cc70bSAndy Fleming 	int err;
452272cc70bSAndy Fleming 
453272cc70bSAndy Fleming 	/* Get the Card Status Register */
454272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
455272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
456272cc70bSAndy Fleming 	cmd.cmdarg = 0;
457272cc70bSAndy Fleming 
458cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
459272cc70bSAndy Fleming 	data.blocks = 1;
4608bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
461272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
462272cc70bSAndy Fleming 
463272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
464272cc70bSAndy Fleming 
465272cc70bSAndy Fleming 	return err;
466272cc70bSAndy Fleming }
467272cc70bSAndy Fleming 
468272cc70bSAndy Fleming 
469fdbb873eSKim Phillips static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
470272cc70bSAndy Fleming {
471272cc70bSAndy Fleming 	struct mmc_cmd cmd;
4725d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
4735d4fc8d9SRaffaele Recalcati 	int ret;
474272cc70bSAndy Fleming 
475272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
476272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
477272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
478272cc70bSAndy Fleming 				 (index << 16) |
479272cc70bSAndy Fleming 				 (value << 8);
480272cc70bSAndy Fleming 
4815d4fc8d9SRaffaele Recalcati 	ret = mmc_send_cmd(mmc, &cmd, NULL);
4825d4fc8d9SRaffaele Recalcati 
4835d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
48493ad0d18SJan Kloetzke 	if (!ret)
48593ad0d18SJan Kloetzke 		ret = mmc_send_status(mmc, timeout);
4865d4fc8d9SRaffaele Recalcati 
4875d4fc8d9SRaffaele Recalcati 	return ret;
4885d4fc8d9SRaffaele Recalcati 
489272cc70bSAndy Fleming }
490272cc70bSAndy Fleming 
491fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
492272cc70bSAndy Fleming {
4938bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
494272cc70bSAndy Fleming 	char cardtype;
495272cc70bSAndy Fleming 	int err;
496272cc70bSAndy Fleming 
497fc5b32fbSAndrew Gabbasov 	mmc->card_caps = 0;
498272cc70bSAndy Fleming 
499d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
500d52ebf10SThomas Chou 		return 0;
501d52ebf10SThomas Chou 
502272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
503272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
504272cc70bSAndy Fleming 		return 0;
505272cc70bSAndy Fleming 
506fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
507fc5b32fbSAndrew Gabbasov 
508272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
509272cc70bSAndy Fleming 
510272cc70bSAndy Fleming 	if (err)
511272cc70bSAndy Fleming 		return err;
512272cc70bSAndy Fleming 
5130560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
514272cc70bSAndy Fleming 
515272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
516272cc70bSAndy Fleming 
517272cc70bSAndy Fleming 	if (err)
5186b2221b0SAndrew Gabbasov 		return err == SWITCH_ERR ? 0 : err;
519272cc70bSAndy Fleming 
520272cc70bSAndy Fleming 	/* Now check to see that it worked */
521272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
522272cc70bSAndy Fleming 
523272cc70bSAndy Fleming 	if (err)
524272cc70bSAndy Fleming 		return err;
525272cc70bSAndy Fleming 
526272cc70bSAndy Fleming 	/* No high-speed support */
5270560db18SLei Wen 	if (!ext_csd[EXT_CSD_HS_TIMING])
528272cc70bSAndy Fleming 		return 0;
529272cc70bSAndy Fleming 
530272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
531d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
532201d5ac4SAndrew Gabbasov 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
533d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
534272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
535d22e3d46SJaehoon Chung 	} else {
536272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
537d22e3d46SJaehoon Chung 	}
538272cc70bSAndy Fleming 
539272cc70bSAndy Fleming 	return 0;
540272cc70bSAndy Fleming }
541272cc70bSAndy Fleming 
542f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
543f866a46dSStephen Warren {
544f866a46dSStephen Warren 	switch (part_num) {
545f866a46dSStephen Warren 	case 0:
546f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
547f866a46dSStephen Warren 		break;
548f866a46dSStephen Warren 	case 1:
549f866a46dSStephen Warren 	case 2:
550f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
551f866a46dSStephen Warren 		break;
552f866a46dSStephen Warren 	case 3:
553f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
554f866a46dSStephen Warren 		break;
555f866a46dSStephen Warren 	case 4:
556f866a46dSStephen Warren 	case 5:
557f866a46dSStephen Warren 	case 6:
558f866a46dSStephen Warren 	case 7:
559f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
560f866a46dSStephen Warren 		break;
561f866a46dSStephen Warren 	default:
562f866a46dSStephen Warren 		return -1;
563f866a46dSStephen Warren 	}
564f866a46dSStephen Warren 
565f866a46dSStephen Warren 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
566f866a46dSStephen Warren 
567f866a46dSStephen Warren 	return 0;
568f866a46dSStephen Warren }
569f866a46dSStephen Warren 
570d2356284SStephen Warren int mmc_select_hwpart(int dev_num, int hwpart)
571d2356284SStephen Warren {
572d2356284SStephen Warren 	struct mmc *mmc = find_mmc_device(dev_num);
573d2356284SStephen Warren 	int ret;
574d2356284SStephen Warren 
575d2356284SStephen Warren 	if (!mmc)
576d4622df3SStephen Warren 		return -ENODEV;
577d2356284SStephen Warren 
578d2356284SStephen Warren 	if (mmc->part_num == hwpart)
579d2356284SStephen Warren 		return 0;
580d2356284SStephen Warren 
581d2356284SStephen Warren 	if (mmc->part_config == MMCPART_NOAVAILABLE) {
582d2356284SStephen Warren 		printf("Card doesn't support part_switch\n");
583d4622df3SStephen Warren 		return -EMEDIUMTYPE;
584d2356284SStephen Warren 	}
585d2356284SStephen Warren 
586d2356284SStephen Warren 	ret = mmc_switch_part(dev_num, hwpart);
587d2356284SStephen Warren 	if (ret)
588d4622df3SStephen Warren 		return ret;
589d2356284SStephen Warren 
590d2356284SStephen Warren 	mmc->part_num = hwpart;
591d2356284SStephen Warren 
592d2356284SStephen Warren 	return 0;
593d2356284SStephen Warren }
594d2356284SStephen Warren 
595d2356284SStephen Warren 
596bc897b1dSLei Wen int mmc_switch_part(int dev_num, unsigned int part_num)
597bc897b1dSLei Wen {
598bc897b1dSLei Wen 	struct mmc *mmc = find_mmc_device(dev_num);
599f866a46dSStephen Warren 	int ret;
600bc897b1dSLei Wen 
601bc897b1dSLei Wen 	if (!mmc)
602bc897b1dSLei Wen 		return -1;
603bc897b1dSLei Wen 
604f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
605bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
606bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
607f866a46dSStephen Warren 
6086dc93e70SPeter Bigot 	/*
6096dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
6106dc93e70SPeter Bigot 	 * to return to representing the raw device.
6116dc93e70SPeter Bigot 	 */
6126dc93e70SPeter Bigot 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0)))
6136dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
6146dc93e70SPeter Bigot 
6156dc93e70SPeter Bigot 	return ret;
616bc897b1dSLei Wen }
617bc897b1dSLei Wen 
618ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
619ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
620ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
621ac9da0e0SDiego Santa Cruz {
622ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
623ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
624ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
625ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
626ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
627ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
6288dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
629ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
630ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
631ac9da0e0SDiego Santa Cruz 
632ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
633ac9da0e0SDiego Santa Cruz 		return -EINVAL;
634ac9da0e0SDiego Santa Cruz 
635ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
636ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
637ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
638ac9da0e0SDiego Santa Cruz 	}
639ac9da0e0SDiego Santa Cruz 
640ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
641ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
642ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
643ac9da0e0SDiego Santa Cruz 	}
644ac9da0e0SDiego Santa Cruz 
645ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
646ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
647ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
648ac9da0e0SDiego Santa Cruz 	}
649ac9da0e0SDiego Santa Cruz 
650ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
651ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
652ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
653ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
654ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
655ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
656ac9da0e0SDiego Santa Cruz 			return -EINVAL;
657ac9da0e0SDiego Santa Cruz 		}
658ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
659ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
660ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
661ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
662ac9da0e0SDiego Santa Cruz 		} else {
663ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
664ac9da0e0SDiego Santa Cruz 		}
665ac9da0e0SDiego Santa Cruz 	} else {
666ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
667ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
668ac9da0e0SDiego Santa Cruz 	}
669ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
670ac9da0e0SDiego Santa Cruz 
671ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
672ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
673ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
674ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
675ac9da0e0SDiego Santa Cruz 			return -EINVAL;
676ac9da0e0SDiego Santa Cruz 		}
677ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
678ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
679ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
680ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
681ac9da0e0SDiego Santa Cruz 		}
682ac9da0e0SDiego Santa Cruz 	}
683ac9da0e0SDiego Santa Cruz 
684ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
685ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
686ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
687ac9da0e0SDiego Santa Cruz 	}
688ac9da0e0SDiego Santa Cruz 
689ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
690ac9da0e0SDiego Santa Cruz 	if (err)
691ac9da0e0SDiego Santa Cruz 		return err;
692ac9da0e0SDiego Santa Cruz 
693ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
694ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
695ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
696ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
697ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
698ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
699ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
700ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
701ac9da0e0SDiego Santa Cruz 	}
702ac9da0e0SDiego Santa Cruz 
7038dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
7048dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
7058dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
7068dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
7078dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
7088dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
7098dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
7108dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
7118dda5b0eSDiego Santa Cruz 		else
7128dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
7138dda5b0eSDiego Santa Cruz 	}
7148dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
7158dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
7168dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
7178dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
7188dda5b0eSDiego Santa Cruz 			else
7198dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
7208dda5b0eSDiego Santa Cruz 		}
7218dda5b0eSDiego Santa Cruz 	}
7228dda5b0eSDiego Santa Cruz 
7238dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
7248dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
7258dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
7268dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
7278dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
7288dda5b0eSDiego Santa Cruz 	}
7298dda5b0eSDiego Santa Cruz 
730ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
731ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
732ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
733ac9da0e0SDiego Santa Cruz 		return -EPERM;
734ac9da0e0SDiego Santa Cruz 	}
735ac9da0e0SDiego Santa Cruz 
736ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
737ac9da0e0SDiego Santa Cruz 		return 0;
738ac9da0e0SDiego Santa Cruz 
739ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
740ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
741ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
742ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
743ac9da0e0SDiego Santa Cruz 
744ac9da0e0SDiego Santa Cruz 		if (err)
745ac9da0e0SDiego Santa Cruz 			return err;
746ac9da0e0SDiego Santa Cruz 
747ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
748ac9da0e0SDiego Santa Cruz 
749ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
750ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
751ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
752ac9da0e0SDiego Santa Cruz 
753ac9da0e0SDiego Santa Cruz 	}
754ac9da0e0SDiego Santa Cruz 
755ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
756ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
757ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
758ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
759ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
760ac9da0e0SDiego Santa Cruz 		if (err)
761ac9da0e0SDiego Santa Cruz 			return err;
762ac9da0e0SDiego Santa Cruz 	}
763ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
764ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
765ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
766ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
767ac9da0e0SDiego Santa Cruz 		if (err)
768ac9da0e0SDiego Santa Cruz 			return err;
769ac9da0e0SDiego Santa Cruz 	}
770ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
771ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
772ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
773ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
774ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
775ac9da0e0SDiego Santa Cruz 			if (err)
776ac9da0e0SDiego Santa Cruz 				return err;
777ac9da0e0SDiego Santa Cruz 		}
778ac9da0e0SDiego Santa Cruz 	}
779ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
780ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
781ac9da0e0SDiego Santa Cruz 	if (err)
782ac9da0e0SDiego Santa Cruz 		return err;
783ac9da0e0SDiego Santa Cruz 
784ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
785ac9da0e0SDiego Santa Cruz 		return 0;
786ac9da0e0SDiego Santa Cruz 
7878dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
7888dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
7898dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
7908dda5b0eSDiego Santa Cruz 	 * partitioning. */
7918dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
7928dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
7938dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
7948dda5b0eSDiego Santa Cruz 		if (err)
7958dda5b0eSDiego Santa Cruz 			return err;
7968dda5b0eSDiego Santa Cruz 	}
7978dda5b0eSDiego Santa Cruz 
798ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
799ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
800ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
801ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
802ac9da0e0SDiego Santa Cruz 
803ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
804ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
805ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
806ac9da0e0SDiego Santa Cruz 	if (err)
807ac9da0e0SDiego Santa Cruz 		return err;
808ac9da0e0SDiego Santa Cruz 
809ac9da0e0SDiego Santa Cruz 	return 0;
810ac9da0e0SDiego Santa Cruz }
811ac9da0e0SDiego Santa Cruz 
81248972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
81348972d90SThierry Reding {
81448972d90SThierry Reding 	int cd;
81548972d90SThierry Reding 
81648972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
81748972d90SThierry Reding 
818d4e1da4eSPeter Korsgaard 	if (cd < 0) {
81993bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
82093bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
821d4e1da4eSPeter Korsgaard 		else
822d4e1da4eSPeter Korsgaard 			cd = 1;
823d4e1da4eSPeter Korsgaard 	}
82448972d90SThierry Reding 
82548972d90SThierry Reding 	return cd;
82648972d90SThierry Reding }
82748972d90SThierry Reding 
828fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
829272cc70bSAndy Fleming {
830272cc70bSAndy Fleming 	struct mmc_cmd cmd;
831272cc70bSAndy Fleming 	struct mmc_data data;
832272cc70bSAndy Fleming 
833272cc70bSAndy Fleming 	/* Switch the frequency */
834272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
835272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
836272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
837272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
838272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
839272cc70bSAndy Fleming 
840272cc70bSAndy Fleming 	data.dest = (char *)resp;
841272cc70bSAndy Fleming 	data.blocksize = 64;
842272cc70bSAndy Fleming 	data.blocks = 1;
843272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
844272cc70bSAndy Fleming 
845272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
846272cc70bSAndy Fleming }
847272cc70bSAndy Fleming 
848272cc70bSAndy Fleming 
849fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
850272cc70bSAndy Fleming {
851272cc70bSAndy Fleming 	int err;
852272cc70bSAndy Fleming 	struct mmc_cmd cmd;
853f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
854f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
855272cc70bSAndy Fleming 	struct mmc_data data;
856272cc70bSAndy Fleming 	int timeout;
857272cc70bSAndy Fleming 
858272cc70bSAndy Fleming 	mmc->card_caps = 0;
859272cc70bSAndy Fleming 
860d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
861d52ebf10SThomas Chou 		return 0;
862d52ebf10SThomas Chou 
863272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
864272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
865272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
866272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
867272cc70bSAndy Fleming 
868272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
869272cc70bSAndy Fleming 
870272cc70bSAndy Fleming 	if (err)
871272cc70bSAndy Fleming 		return err;
872272cc70bSAndy Fleming 
873272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
874272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
875272cc70bSAndy Fleming 	cmd.cmdarg = 0;
876272cc70bSAndy Fleming 
877272cc70bSAndy Fleming 	timeout = 3;
878272cc70bSAndy Fleming 
879272cc70bSAndy Fleming retry_scr:
880f781dd38SAnton staaf 	data.dest = (char *)scr;
881272cc70bSAndy Fleming 	data.blocksize = 8;
882272cc70bSAndy Fleming 	data.blocks = 1;
883272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
884272cc70bSAndy Fleming 
885272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
886272cc70bSAndy Fleming 
887272cc70bSAndy Fleming 	if (err) {
888272cc70bSAndy Fleming 		if (timeout--)
889272cc70bSAndy Fleming 			goto retry_scr;
890272cc70bSAndy Fleming 
891272cc70bSAndy Fleming 		return err;
892272cc70bSAndy Fleming 	}
893272cc70bSAndy Fleming 
8944e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
8954e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
896272cc70bSAndy Fleming 
897272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
898272cc70bSAndy Fleming 		case 0:
899272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
900272cc70bSAndy Fleming 			break;
901272cc70bSAndy Fleming 		case 1:
902272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_10;
903272cc70bSAndy Fleming 			break;
904272cc70bSAndy Fleming 		case 2:
905272cc70bSAndy Fleming 			mmc->version = SD_VERSION_2;
9061741c64dSJaehoon Chung 			if ((mmc->scr[0] >> 15) & 0x1)
9071741c64dSJaehoon Chung 				mmc->version = SD_VERSION_3;
908272cc70bSAndy Fleming 			break;
909272cc70bSAndy Fleming 		default:
910272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
911272cc70bSAndy Fleming 			break;
912272cc70bSAndy Fleming 	}
913272cc70bSAndy Fleming 
914b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
915b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
916b44c7083SAlagu Sankar 
917272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
918272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
919272cc70bSAndy Fleming 		return 0;
920272cc70bSAndy Fleming 
921272cc70bSAndy Fleming 	timeout = 4;
922272cc70bSAndy Fleming 	while (timeout--) {
923272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
924f781dd38SAnton staaf 				(u8 *)switch_status);
925272cc70bSAndy Fleming 
926272cc70bSAndy Fleming 		if (err)
927272cc70bSAndy Fleming 			return err;
928272cc70bSAndy Fleming 
929272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
9304e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
931272cc70bSAndy Fleming 			break;
932272cc70bSAndy Fleming 	}
933272cc70bSAndy Fleming 
934272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
9354e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
936272cc70bSAndy Fleming 		return 0;
937272cc70bSAndy Fleming 
9382c3fbf4cSMacpaul Lin 	/*
9392c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
9402c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
9412c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
9422c3fbf4cSMacpaul Lin 	 * mode between the host.
9432c3fbf4cSMacpaul Lin 	 */
94493bfd616SPantelis Antoniou 	if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
94593bfd616SPantelis Antoniou 		(mmc->cfg->host_caps & MMC_MODE_HS)))
9462c3fbf4cSMacpaul Lin 		return 0;
9472c3fbf4cSMacpaul Lin 
948f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
949272cc70bSAndy Fleming 
950272cc70bSAndy Fleming 	if (err)
951272cc70bSAndy Fleming 		return err;
952272cc70bSAndy Fleming 
9534e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
954272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
955272cc70bSAndy Fleming 
956272cc70bSAndy Fleming 	return 0;
957272cc70bSAndy Fleming }
958272cc70bSAndy Fleming 
959272cc70bSAndy Fleming /* frequency bases */
960272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
9615f837c2cSMike Frysinger static const int fbase[] = {
962272cc70bSAndy Fleming 	10000,
963272cc70bSAndy Fleming 	100000,
964272cc70bSAndy Fleming 	1000000,
965272cc70bSAndy Fleming 	10000000,
966272cc70bSAndy Fleming };
967272cc70bSAndy Fleming 
968272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
969272cc70bSAndy Fleming  * to platforms without floating point.
970272cc70bSAndy Fleming  */
9715f837c2cSMike Frysinger static const int multipliers[] = {
972272cc70bSAndy Fleming 	0,	/* reserved */
973272cc70bSAndy Fleming 	10,
974272cc70bSAndy Fleming 	12,
975272cc70bSAndy Fleming 	13,
976272cc70bSAndy Fleming 	15,
977272cc70bSAndy Fleming 	20,
978272cc70bSAndy Fleming 	25,
979272cc70bSAndy Fleming 	30,
980272cc70bSAndy Fleming 	35,
981272cc70bSAndy Fleming 	40,
982272cc70bSAndy Fleming 	45,
983272cc70bSAndy Fleming 	50,
984272cc70bSAndy Fleming 	55,
985272cc70bSAndy Fleming 	60,
986272cc70bSAndy Fleming 	70,
987272cc70bSAndy Fleming 	80,
988272cc70bSAndy Fleming };
989272cc70bSAndy Fleming 
990fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
991272cc70bSAndy Fleming {
99293bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
99393bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
994272cc70bSAndy Fleming }
995272cc70bSAndy Fleming 
996272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
997272cc70bSAndy Fleming {
99893bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
99993bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1000272cc70bSAndy Fleming 
100193bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
100293bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1003272cc70bSAndy Fleming 
1004272cc70bSAndy Fleming 	mmc->clock = clock;
1005272cc70bSAndy Fleming 
1006272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1007272cc70bSAndy Fleming }
1008272cc70bSAndy Fleming 
1009fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width)
1010272cc70bSAndy Fleming {
1011272cc70bSAndy Fleming 	mmc->bus_width = width;
1012272cc70bSAndy Fleming 
1013272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1014272cc70bSAndy Fleming }
1015272cc70bSAndy Fleming 
1016fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1017272cc70bSAndy Fleming {
1018f866a46dSStephen Warren 	int err, i;
1019272cc70bSAndy Fleming 	uint mult, freq;
1020639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
1021272cc70bSAndy Fleming 	struct mmc_cmd cmd;
10228bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
10238bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
10245d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
10250c453bb7SDiego Santa Cruz 	bool has_parts = false;
10268a0cf490SDiego Santa Cruz 	bool part_completed;
1027272cc70bSAndy Fleming 
1028d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1029d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1030d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1031d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1032d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1033d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1034d52ebf10SThomas Chou 
1035d52ebf10SThomas Chou 		if (err)
1036d52ebf10SThomas Chou 			return err;
1037d52ebf10SThomas Chou 	}
1038d52ebf10SThomas Chou #endif
1039d52ebf10SThomas Chou 
1040272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1041d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1042d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1043272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1044272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1045272cc70bSAndy Fleming 
1046272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1047272cc70bSAndy Fleming 
1048272cc70bSAndy Fleming 	if (err)
1049272cc70bSAndy Fleming 		return err;
1050272cc70bSAndy Fleming 
1051272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1052272cc70bSAndy Fleming 
1053272cc70bSAndy Fleming 	/*
1054272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1055272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1056272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1057272cc70bSAndy Fleming 	 */
1058d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1059272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1060272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1061272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1062272cc70bSAndy Fleming 
1063272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1064272cc70bSAndy Fleming 
1065272cc70bSAndy Fleming 		if (err)
1066272cc70bSAndy Fleming 			return err;
1067272cc70bSAndy Fleming 
1068272cc70bSAndy Fleming 		if (IS_SD(mmc))
1069998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1070d52ebf10SThomas Chou 	}
1071272cc70bSAndy Fleming 
1072272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1073272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1074272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1075272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1076272cc70bSAndy Fleming 
1077272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1078272cc70bSAndy Fleming 
10795d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
10805d4fc8d9SRaffaele Recalcati 	mmc_send_status(mmc, timeout);
10815d4fc8d9SRaffaele Recalcati 
1082272cc70bSAndy Fleming 	if (err)
1083272cc70bSAndy Fleming 		return err;
1084272cc70bSAndy Fleming 
1085998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1086998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1087998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1088998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1089272cc70bSAndy Fleming 
1090272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
10910b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1092272cc70bSAndy Fleming 
1093272cc70bSAndy Fleming 		switch (version) {
1094272cc70bSAndy Fleming 			case 0:
1095272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
1096272cc70bSAndy Fleming 				break;
1097272cc70bSAndy Fleming 			case 1:
1098272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_4;
1099272cc70bSAndy Fleming 				break;
1100272cc70bSAndy Fleming 			case 2:
1101272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_2_2;
1102272cc70bSAndy Fleming 				break;
1103272cc70bSAndy Fleming 			case 3:
1104272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_3;
1105272cc70bSAndy Fleming 				break;
1106272cc70bSAndy Fleming 			case 4:
1107272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_4;
1108272cc70bSAndy Fleming 				break;
1109272cc70bSAndy Fleming 			default:
1110272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
1111272cc70bSAndy Fleming 				break;
1112272cc70bSAndy Fleming 		}
1113272cc70bSAndy Fleming 	}
1114272cc70bSAndy Fleming 
1115272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
11160b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
11170b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1118272cc70bSAndy Fleming 
1119272cc70bSAndy Fleming 	mmc->tran_speed = freq * mult;
1120272cc70bSAndy Fleming 
1121ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1122998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1123272cc70bSAndy Fleming 
1124272cc70bSAndy Fleming 	if (IS_SD(mmc))
1125272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1126272cc70bSAndy Fleming 	else
1127998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1128272cc70bSAndy Fleming 
1129272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1130272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1131272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1132272cc70bSAndy Fleming 		cmult = 8;
1133272cc70bSAndy Fleming 	} else {
1134272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1135272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1136272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1137272cc70bSAndy Fleming 	}
1138272cc70bSAndy Fleming 
1139f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1140f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1141f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1142f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1143f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1144f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1145272cc70bSAndy Fleming 
11468bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
11478bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1148272cc70bSAndy Fleming 
11498bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
11508bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1151272cc70bSAndy Fleming 
1152ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1153ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1154ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1155ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1156ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1157ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1158ab71188cSMarkus Niebel 	}
1159ab71188cSMarkus Niebel 
1160272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1161d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1162272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1163fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1164272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1165272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1166272cc70bSAndy Fleming 
1167272cc70bSAndy Fleming 		if (err)
1168272cc70bSAndy Fleming 			return err;
1169d52ebf10SThomas Chou 	}
1170272cc70bSAndy Fleming 
1171e6f99a56SLei Wen 	/*
1172e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1173e6f99a56SLei Wen 	 */
1174e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1175bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1176d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
1177d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
1178d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
11799cf199ebSDiego Santa Cruz 		if (err)
11809cf199ebSDiego Santa Cruz 			return err;
11819cf199ebSDiego Santa Cruz 		if (ext_csd[EXT_CSD_REV] >= 2) {
1182639b7827SYoshihiro Shimoda 			/*
1183639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
1184639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
1185639b7827SYoshihiro Shimoda 			 * than 2GB
1186639b7827SYoshihiro Shimoda 			 */
11870560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
11880560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
11890560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
11900560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
11918bfa195eSSimon Glass 			capacity *= MMC_MAX_BLOCK_LEN;
1192b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
1193f866a46dSStephen Warren 				mmc->capacity_user = capacity;
1194d23e2c09SSukumar Ghorai 		}
1195bc897b1dSLei Wen 
119664f4a619SJaehoon Chung 		switch (ext_csd[EXT_CSD_REV]) {
119764f4a619SJaehoon Chung 		case 1:
119864f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_1;
119964f4a619SJaehoon Chung 			break;
120064f4a619SJaehoon Chung 		case 2:
120164f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_2;
120264f4a619SJaehoon Chung 			break;
120364f4a619SJaehoon Chung 		case 3:
120464f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_3;
120564f4a619SJaehoon Chung 			break;
120664f4a619SJaehoon Chung 		case 5:
120764f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_41;
120864f4a619SJaehoon Chung 			break;
120964f4a619SJaehoon Chung 		case 6:
121064f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_5;
121164f4a619SJaehoon Chung 			break;
1212edab723bSMarkus Niebel 		case 7:
1213edab723bSMarkus Niebel 			mmc->version = MMC_VERSION_5_0;
1214edab723bSMarkus Niebel 			break;
121564f4a619SJaehoon Chung 		}
121664f4a619SJaehoon Chung 
12178a0cf490SDiego Santa Cruz 		/* The partition data may be non-zero but it is only
12188a0cf490SDiego Santa Cruz 		 * effective if PARTITION_SETTING_COMPLETED is set in
12198a0cf490SDiego Santa Cruz 		 * EXT_CSD, so ignore any data if this bit is not set,
12208a0cf490SDiego Santa Cruz 		 * except for enabling the high-capacity group size
12218a0cf490SDiego Santa Cruz 		 * definition (see below). */
12228a0cf490SDiego Santa Cruz 		part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
12238a0cf490SDiego Santa Cruz 				    EXT_CSD_PARTITION_SETTING_COMPLETED);
12248a0cf490SDiego Santa Cruz 
12250c453bb7SDiego Santa Cruz 		/* store the partition info of emmc */
12260c453bb7SDiego Santa Cruz 		mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
12270c453bb7SDiego Santa Cruz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
12280c453bb7SDiego Santa Cruz 		    ext_csd[EXT_CSD_BOOT_MULT])
12290c453bb7SDiego Santa Cruz 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
12308a0cf490SDiego Santa Cruz 		if (part_completed &&
12318a0cf490SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
12320c453bb7SDiego Santa Cruz 			mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
12330c453bb7SDiego Santa Cruz 
12340c453bb7SDiego Santa Cruz 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
12350c453bb7SDiego Santa Cruz 
12360c453bb7SDiego Santa Cruz 		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
12370c453bb7SDiego Santa Cruz 
12380c453bb7SDiego Santa Cruz 		for (i = 0; i < 4; i++) {
12390c453bb7SDiego Santa Cruz 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
12408a0cf490SDiego Santa Cruz 			uint mult = (ext_csd[idx + 2] << 16) +
12410c453bb7SDiego Santa Cruz 				(ext_csd[idx + 1] << 8) + ext_csd[idx];
12428a0cf490SDiego Santa Cruz 			if (mult)
12438a0cf490SDiego Santa Cruz 				has_parts = true;
12448a0cf490SDiego Santa Cruz 			if (!part_completed)
12458a0cf490SDiego Santa Cruz 				continue;
12468a0cf490SDiego Santa Cruz 			mmc->capacity_gp[i] = mult;
12470c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *=
12480c453bb7SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
12490c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1250f8e89d67SDiego Santa Cruz 			mmc->capacity_gp[i] <<= 19;
12510c453bb7SDiego Santa Cruz 		}
12520c453bb7SDiego Santa Cruz 
12538a0cf490SDiego Santa Cruz 		if (part_completed) {
1254a7f852b6SDiego Santa Cruz 			mmc->enh_user_size =
1255a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
1256a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
1257a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_SIZE_MULT];
1258a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1259a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1260a7f852b6SDiego Santa Cruz 			mmc->enh_user_size <<= 19;
1261a7f852b6SDiego Santa Cruz 			mmc->enh_user_start =
1262a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
1263a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
1264a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
1265a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_START_ADDR];
1266a7f852b6SDiego Santa Cruz 			if (mmc->high_capacity)
1267a7f852b6SDiego Santa Cruz 				mmc->enh_user_start <<= 9;
12688a0cf490SDiego Santa Cruz 		}
1269a7f852b6SDiego Santa Cruz 
1270e6f99a56SLei Wen 		/*
12711937e5aaSOliver Metz 		 * Host needs to enable ERASE_GRP_DEF bit if device is
12721937e5aaSOliver Metz 		 * partitioned. This bit will be lost every time after a reset
12731937e5aaSOliver Metz 		 * or power off. This will affect erase size.
1274e6f99a56SLei Wen 		 */
12758a0cf490SDiego Santa Cruz 		if (part_completed)
12760c453bb7SDiego Santa Cruz 			has_parts = true;
12771937e5aaSOliver Metz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
12780c453bb7SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
12790c453bb7SDiego Santa Cruz 			has_parts = true;
12800c453bb7SDiego Santa Cruz 		if (has_parts) {
12811937e5aaSOliver Metz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
12821937e5aaSOliver Metz 				EXT_CSD_ERASE_GROUP_DEF, 1);
12831937e5aaSOliver Metz 
12841937e5aaSOliver Metz 			if (err)
12851937e5aaSOliver Metz 				return err;
1286021a8055SHannes Petermaier 			else
1287021a8055SHannes Petermaier 				ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1288037dc0abSDiego Santa Cruz 		}
12891937e5aaSOliver Metz 
1290037dc0abSDiego Santa Cruz 		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
12911937e5aaSOliver Metz 			/* Read out group size from ext_csd */
12920560db18SLei Wen 			mmc->erase_grp_size =
1293a4ff9f83SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1294d7b29129SMarkus Niebel 			/*
1295d7b29129SMarkus Niebel 			 * if high capacity and partition setting completed
1296d7b29129SMarkus Niebel 			 * SEC_COUNT is valid even if it is smaller than 2 GiB
1297d7b29129SMarkus Niebel 			 * JEDEC Standard JESD84-B45, 6.2.4
1298d7b29129SMarkus Niebel 			 */
12998a0cf490SDiego Santa Cruz 			if (mmc->high_capacity && part_completed) {
1300d7b29129SMarkus Niebel 				capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1301d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1302d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1303d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1304d7b29129SMarkus Niebel 				capacity *= MMC_MAX_BLOCK_LEN;
1305d7b29129SMarkus Niebel 				mmc->capacity_user = capacity;
1306d7b29129SMarkus Niebel 			}
13078bfa195eSSimon Glass 		} else {
13081937e5aaSOliver Metz 			/* Calculate the group size from the csd value. */
1309e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
1310e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1311e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1312e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
1313e6f99a56SLei Wen 				* (erase_gmul + 1);
1314e6f99a56SLei Wen 		}
1315037dc0abSDiego Santa Cruz 
1316037dc0abSDiego Santa Cruz 		mmc->hc_wp_grp_size = 1024
1317037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1318037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
13199e41a00bSDiego Santa Cruz 
13209e41a00bSDiego Santa Cruz 		mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1321f866a46dSStephen Warren 	}
1322f866a46dSStephen Warren 
1323f866a46dSStephen Warren 	err = mmc_set_capacity(mmc, mmc->part_num);
1324f866a46dSStephen Warren 	if (err)
1325f866a46dSStephen Warren 		return err;
1326d23e2c09SSukumar Ghorai 
1327272cc70bSAndy Fleming 	if (IS_SD(mmc))
1328272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1329272cc70bSAndy Fleming 	else
1330272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1331272cc70bSAndy Fleming 
1332272cc70bSAndy Fleming 	if (err)
1333272cc70bSAndy Fleming 		return err;
1334272cc70bSAndy Fleming 
1335272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
133693bfd616SPantelis Antoniou 	mmc->card_caps &= mmc->cfg->host_caps;
1337272cc70bSAndy Fleming 
1338272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1339272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1340272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1341272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1342272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1343272cc70bSAndy Fleming 
1344272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1345272cc70bSAndy Fleming 			if (err)
1346272cc70bSAndy Fleming 				return err;
1347272cc70bSAndy Fleming 
1348272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1349272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1350272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1351272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1352272cc70bSAndy Fleming 			if (err)
1353272cc70bSAndy Fleming 				return err;
1354272cc70bSAndy Fleming 
1355272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1356272cc70bSAndy Fleming 		}
1357272cc70bSAndy Fleming 
1358272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
1359ad5fd922SJaehoon Chung 			mmc->tran_speed = 50000000;
1360272cc70bSAndy Fleming 		else
1361ad5fd922SJaehoon Chung 			mmc->tran_speed = 25000000;
1362fc5b32fbSAndrew Gabbasov 	} else if (mmc->version >= MMC_VERSION_4) {
1363fc5b32fbSAndrew Gabbasov 		/* Only version 4 of MMC supports wider bus widths */
13647798f6dbSAndy Fleming 		int idx;
13657798f6dbSAndy Fleming 
13667798f6dbSAndy Fleming 		/* An array of possible bus widths in order of preference */
13677798f6dbSAndy Fleming 		static unsigned ext_csd_bits[] = {
1368d22e3d46SJaehoon Chung 			EXT_CSD_DDR_BUS_WIDTH_8,
1369d22e3d46SJaehoon Chung 			EXT_CSD_DDR_BUS_WIDTH_4,
13707798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_8,
13717798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_4,
13727798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_1,
13737798f6dbSAndy Fleming 		};
13747798f6dbSAndy Fleming 
13757798f6dbSAndy Fleming 		/* An array to map CSD bus widths to host cap bits */
13767798f6dbSAndy Fleming 		static unsigned ext_to_hostcaps[] = {
1377786e8f81SAndrew Gabbasov 			[EXT_CSD_DDR_BUS_WIDTH_4] =
1378786e8f81SAndrew Gabbasov 				MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
1379786e8f81SAndrew Gabbasov 			[EXT_CSD_DDR_BUS_WIDTH_8] =
1380786e8f81SAndrew Gabbasov 				MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
13817798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
13827798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
13837798f6dbSAndy Fleming 		};
13847798f6dbSAndy Fleming 
13857798f6dbSAndy Fleming 		/* An array to map chosen bus width to an integer */
13867798f6dbSAndy Fleming 		static unsigned widths[] = {
1387d22e3d46SJaehoon Chung 			8, 4, 8, 4, 1,
13887798f6dbSAndy Fleming 		};
13897798f6dbSAndy Fleming 
13907798f6dbSAndy Fleming 		for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
13917798f6dbSAndy Fleming 			unsigned int extw = ext_csd_bits[idx];
1392786e8f81SAndrew Gabbasov 			unsigned int caps = ext_to_hostcaps[extw];
13937798f6dbSAndy Fleming 
13947798f6dbSAndy Fleming 			/*
1395bf477073SAndrew Gabbasov 			 * If the bus width is still not changed,
1396bf477073SAndrew Gabbasov 			 * don't try to set the default again.
1397bf477073SAndrew Gabbasov 			 * Otherwise, recover from switch attempts
1398bf477073SAndrew Gabbasov 			 * by switching to 1-bit bus width.
1399bf477073SAndrew Gabbasov 			 */
1400bf477073SAndrew Gabbasov 			if (extw == EXT_CSD_BUS_WIDTH_1 &&
1401bf477073SAndrew Gabbasov 					mmc->bus_width == 1) {
1402bf477073SAndrew Gabbasov 				err = 0;
1403bf477073SAndrew Gabbasov 				break;
1404bf477073SAndrew Gabbasov 			}
1405bf477073SAndrew Gabbasov 
1406bf477073SAndrew Gabbasov 			/*
1407786e8f81SAndrew Gabbasov 			 * Check to make sure the card and controller support
1408786e8f81SAndrew Gabbasov 			 * these capabilities
14097798f6dbSAndy Fleming 			 */
1410786e8f81SAndrew Gabbasov 			if ((mmc->card_caps & caps) != caps)
14117798f6dbSAndy Fleming 				continue;
14127798f6dbSAndy Fleming 
1413272cc70bSAndy Fleming 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
14147798f6dbSAndy Fleming 					EXT_CSD_BUS_WIDTH, extw);
1415272cc70bSAndy Fleming 
1416272cc70bSAndy Fleming 			if (err)
14174137894eSLei Wen 				continue;
1418272cc70bSAndy Fleming 
1419786e8f81SAndrew Gabbasov 			mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
14207798f6dbSAndy Fleming 			mmc_set_bus_width(mmc, widths[idx]);
1421272cc70bSAndy Fleming 
14224137894eSLei Wen 			err = mmc_send_ext_csd(mmc, test_csd);
1423272cc70bSAndy Fleming 
1424786e8f81SAndrew Gabbasov 			if (err)
1425786e8f81SAndrew Gabbasov 				continue;
1426786e8f81SAndrew Gabbasov 
1427786e8f81SAndrew Gabbasov 			/* Only compare read only fields */
1428786e8f81SAndrew Gabbasov 			if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
1429786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
1430786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
1431786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
1432786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_REV]
1433786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_REV] &&
1434786e8f81SAndrew Gabbasov 			    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1435786e8f81SAndrew Gabbasov 				== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
1436786e8f81SAndrew Gabbasov 			    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
1437786e8f81SAndrew Gabbasov 				   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
14384137894eSLei Wen 				break;
1439786e8f81SAndrew Gabbasov 			else
1440786e8f81SAndrew Gabbasov 				err = SWITCH_ERR;
14414137894eSLei Wen 		}
1442786e8f81SAndrew Gabbasov 
1443786e8f81SAndrew Gabbasov 		if (err)
1444786e8f81SAndrew Gabbasov 			return err;
1445272cc70bSAndy Fleming 
1446272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS) {
1447272cc70bSAndy Fleming 			if (mmc->card_caps & MMC_MODE_HS_52MHz)
1448ad5fd922SJaehoon Chung 				mmc->tran_speed = 52000000;
1449272cc70bSAndy Fleming 			else
1450ad5fd922SJaehoon Chung 				mmc->tran_speed = 26000000;
1451272cc70bSAndy Fleming 		}
1452ad5fd922SJaehoon Chung 	}
1453ad5fd922SJaehoon Chung 
1454ad5fd922SJaehoon Chung 	mmc_set_clock(mmc, mmc->tran_speed);
1455272cc70bSAndy Fleming 
14565af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
14575af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
14585af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
14595af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
14605af8f45cSAndrew Gabbasov 	}
14615af8f45cSAndrew Gabbasov 
1462272cc70bSAndy Fleming 	/* fill in device description */
1463272cc70bSAndy Fleming 	mmc->block_dev.lun = 0;
1464272cc70bSAndy Fleming 	mmc->block_dev.type = 0;
1465272cc70bSAndy Fleming 	mmc->block_dev.blksz = mmc->read_bl_len;
14660472fbfdSEgbert Eich 	mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz);
14679b1f942cSRabin Vincent 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
146856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1469babce5f6STaylor Hutt 	sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x",
1470babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1471babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1472babce5f6STaylor Hutt 	sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
14730b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1474babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1475babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1476babce5f6STaylor Hutt 	sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1477babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
147856196826SPaul Burton #else
147956196826SPaul Burton 	mmc->block_dev.vendor[0] = 0;
148056196826SPaul Burton 	mmc->block_dev.product[0] = 0;
148156196826SPaul Burton 	mmc->block_dev.revision[0] = 0;
148256196826SPaul Burton #endif
1483122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1484272cc70bSAndy Fleming 	init_part(&mmc->block_dev);
1485122efd43SMikhail Kshevetskiy #endif
1486272cc70bSAndy Fleming 
1487272cc70bSAndy Fleming 	return 0;
1488272cc70bSAndy Fleming }
1489272cc70bSAndy Fleming 
1490fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1491272cc70bSAndy Fleming {
1492272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1493272cc70bSAndy Fleming 	int err;
1494272cc70bSAndy Fleming 
1495272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1496272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
149793bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1498272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1499272cc70bSAndy Fleming 
1500272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1501272cc70bSAndy Fleming 
1502272cc70bSAndy Fleming 	if (err)
1503272cc70bSAndy Fleming 		return err;
1504272cc70bSAndy Fleming 
1505998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1506272cc70bSAndy Fleming 		return UNUSABLE_ERR;
1507272cc70bSAndy Fleming 	else
1508272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1509272cc70bSAndy Fleming 
1510272cc70bSAndy Fleming 	return 0;
1511272cc70bSAndy Fleming }
1512272cc70bSAndy Fleming 
151393bfd616SPantelis Antoniou /* not used any more */
151493bfd616SPantelis Antoniou int __deprecated mmc_register(struct mmc *mmc)
1515272cc70bSAndy Fleming {
151693bfd616SPantelis Antoniou #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
151793bfd616SPantelis Antoniou 	printf("%s is deprecated! use mmc_create() instead.\n", __func__);
151893bfd616SPantelis Antoniou #endif
151993bfd616SPantelis Antoniou 	return -1;
152093bfd616SPantelis Antoniou }
152193bfd616SPantelis Antoniou 
152293bfd616SPantelis Antoniou struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
152393bfd616SPantelis Antoniou {
152493bfd616SPantelis Antoniou 	struct mmc *mmc;
152593bfd616SPantelis Antoniou 
152693bfd616SPantelis Antoniou 	/* quick validation */
152793bfd616SPantelis Antoniou 	if (cfg == NULL || cfg->ops == NULL || cfg->ops->send_cmd == NULL ||
152893bfd616SPantelis Antoniou 			cfg->f_min == 0 || cfg->f_max == 0 || cfg->b_max == 0)
152993bfd616SPantelis Antoniou 		return NULL;
153093bfd616SPantelis Antoniou 
153193bfd616SPantelis Antoniou 	mmc = calloc(1, sizeof(*mmc));
153293bfd616SPantelis Antoniou 	if (mmc == NULL)
153393bfd616SPantelis Antoniou 		return NULL;
153493bfd616SPantelis Antoniou 
153593bfd616SPantelis Antoniou 	mmc->cfg = cfg;
153693bfd616SPantelis Antoniou 	mmc->priv = priv;
153793bfd616SPantelis Antoniou 
153893bfd616SPantelis Antoniou 	/* the following chunk was mmc_register() */
153993bfd616SPantelis Antoniou 
1540ab71188cSMarkus Niebel 	/* Setup dsr related values */
1541ab71188cSMarkus Niebel 	mmc->dsr_imp = 0;
1542ab71188cSMarkus Niebel 	mmc->dsr = 0xffffffff;
1543272cc70bSAndy Fleming 	/* Setup the universal parts of the block interface just once */
1544272cc70bSAndy Fleming 	mmc->block_dev.if_type = IF_TYPE_MMC;
1545272cc70bSAndy Fleming 	mmc->block_dev.dev = cur_dev_num++;
1546272cc70bSAndy Fleming 	mmc->block_dev.removable = 1;
1547272cc70bSAndy Fleming 	mmc->block_dev.block_read = mmc_bread;
1548272cc70bSAndy Fleming 	mmc->block_dev.block_write = mmc_bwrite;
1549e6f99a56SLei Wen 	mmc->block_dev.block_erase = mmc_berase;
155093bfd616SPantelis Antoniou 
155193bfd616SPantelis Antoniou 	/* setup initial part type */
155293bfd616SPantelis Antoniou 	mmc->block_dev.part_type = mmc->cfg->part_type;
1553272cc70bSAndy Fleming 
1554272cc70bSAndy Fleming 	INIT_LIST_HEAD(&mmc->link);
1555272cc70bSAndy Fleming 
1556272cc70bSAndy Fleming 	list_add_tail(&mmc->link, &mmc_devices);
1557272cc70bSAndy Fleming 
155893bfd616SPantelis Antoniou 	return mmc;
155993bfd616SPantelis Antoniou }
156093bfd616SPantelis Antoniou 
156193bfd616SPantelis Antoniou void mmc_destroy(struct mmc *mmc)
156293bfd616SPantelis Antoniou {
156393bfd616SPantelis Antoniou 	/* only freeing memory for now */
156493bfd616SPantelis Antoniou 	free(mmc);
1565272cc70bSAndy Fleming }
1566272cc70bSAndy Fleming 
1567df3fc526SMatthew McClintock #ifdef CONFIG_PARTITIONS
1568272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev)
1569272cc70bSAndy Fleming {
1570272cc70bSAndy Fleming 	struct mmc *mmc = find_mmc_device(dev);
15716bb4b4bcSBenoît Thébaudeau 	if (!mmc || mmc_init(mmc))
157240242bc3SŁukasz Majewski 		return NULL;
1573272cc70bSAndy Fleming 
157440242bc3SŁukasz Majewski 	return &mmc->block_dev;
1575272cc70bSAndy Fleming }
1576df3fc526SMatthew McClintock #endif
1577272cc70bSAndy Fleming 
157895de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
157995de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
158095de9ab2SPaul Kocialkowski {
158195de9ab2SPaul Kocialkowski }
158295de9ab2SPaul Kocialkowski 
1583e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1584272cc70bSAndy Fleming {
1585afd5932bSMacpaul Lin 	int err;
1586272cc70bSAndy Fleming 
1587ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
158893bfd616SPantelis Antoniou 	if (mmc_getcd(mmc) == 0 || mmc->cfg->ops->init == NULL) {
158948972d90SThierry Reding 		mmc->has_init = 0;
159056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
159148972d90SThierry Reding 		printf("MMC: no card present\n");
159256196826SPaul Burton #endif
159348972d90SThierry Reding 		return NO_CARD_ERR;
159448972d90SThierry Reding 	}
159548972d90SThierry Reding 
1596bc897b1dSLei Wen 	if (mmc->has_init)
1597bc897b1dSLei Wen 		return 0;
1598bc897b1dSLei Wen 
159995de9ab2SPaul Kocialkowski 	board_mmc_power_init();
160095de9ab2SPaul Kocialkowski 
1601ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
160293bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
1603272cc70bSAndy Fleming 
1604272cc70bSAndy Fleming 	if (err)
1605272cc70bSAndy Fleming 		return err;
1606272cc70bSAndy Fleming 
1607786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
1608b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1609b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1610b86b85e2SIlya Yanok 
1611272cc70bSAndy Fleming 	/* Reset the Card */
1612272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1613272cc70bSAndy Fleming 
1614272cc70bSAndy Fleming 	if (err)
1615272cc70bSAndy Fleming 		return err;
1616272cc70bSAndy Fleming 
1617bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1618bc897b1dSLei Wen 	mmc->part_num = 0;
1619bc897b1dSLei Wen 
1620272cc70bSAndy Fleming 	/* Test for SD version 2 */
1621272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1622272cc70bSAndy Fleming 
1623272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1624272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1625272cc70bSAndy Fleming 
1626272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1627272cc70bSAndy Fleming 	if (err == TIMEOUT) {
1628272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1629272cc70bSAndy Fleming 
1630*bd47c135SAndrew Gabbasov 		if (err) {
163156196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1632272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
163356196826SPaul Burton #endif
1634272cc70bSAndy Fleming 			return UNUSABLE_ERR;
1635272cc70bSAndy Fleming 		}
1636272cc70bSAndy Fleming 	}
1637272cc70bSAndy Fleming 
1638*bd47c135SAndrew Gabbasov 	if (!err)
1639e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
1640e9550449SChe-Liang Chiou 
1641e9550449SChe-Liang Chiou 	return err;
1642e9550449SChe-Liang Chiou }
1643e9550449SChe-Liang Chiou 
1644e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
1645e9550449SChe-Liang Chiou {
1646e9550449SChe-Liang Chiou 	int err = 0;
1647e9550449SChe-Liang Chiou 
1648*bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
1649e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
1650e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
1651e9550449SChe-Liang Chiou 
1652e9550449SChe-Liang Chiou 	if (!err)
1653bc897b1dSLei Wen 		err = mmc_startup(mmc);
1654bc897b1dSLei Wen 	if (err)
1655bc897b1dSLei Wen 		mmc->has_init = 0;
1656bc897b1dSLei Wen 	else
1657bc897b1dSLei Wen 		mmc->has_init = 1;
1658e9550449SChe-Liang Chiou 	return err;
1659e9550449SChe-Liang Chiou }
1660e9550449SChe-Liang Chiou 
1661e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
1662e9550449SChe-Liang Chiou {
1663*bd47c135SAndrew Gabbasov 	int err = 0;
1664d803fea5SMateusz Zalega 	unsigned start;
1665e9550449SChe-Liang Chiou 
1666e9550449SChe-Liang Chiou 	if (mmc->has_init)
1667e9550449SChe-Liang Chiou 		return 0;
1668d803fea5SMateusz Zalega 
1669d803fea5SMateusz Zalega 	start = get_timer(0);
1670d803fea5SMateusz Zalega 
1671e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
1672e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
1673e9550449SChe-Liang Chiou 
1674*bd47c135SAndrew Gabbasov 	if (!err)
1675e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
1676e9550449SChe-Liang Chiou 	debug("%s: %d, time %lu\n", __func__, err, get_timer(start));
1677bc897b1dSLei Wen 	return err;
1678272cc70bSAndy Fleming }
1679272cc70bSAndy Fleming 
1680ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
1681ab71188cSMarkus Niebel {
1682ab71188cSMarkus Niebel 	mmc->dsr = val;
1683ab71188cSMarkus Niebel 	return 0;
1684ab71188cSMarkus Niebel }
1685ab71188cSMarkus Niebel 
1686cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
1687cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
1688272cc70bSAndy Fleming {
1689272cc70bSAndy Fleming 	return -1;
1690272cc70bSAndy Fleming }
1691272cc70bSAndy Fleming 
1692cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
1693cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
1694cee9ab7cSJeroen Hofstee {
1695cee9ab7cSJeroen Hofstee 	return -1;
1696cee9ab7cSJeroen Hofstee }
1697272cc70bSAndy Fleming 
169856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
169956196826SPaul Burton 
1700272cc70bSAndy Fleming void print_mmc_devices(char separator)
1701272cc70bSAndy Fleming {
1702272cc70bSAndy Fleming 	struct mmc *m;
1703272cc70bSAndy Fleming 	struct list_head *entry;
170434dd9284SPrzemyslaw Marczak 	char *mmc_type;
1705272cc70bSAndy Fleming 
1706272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
1707272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
1708272cc70bSAndy Fleming 
170934dd9284SPrzemyslaw Marczak 		if (m->has_init)
171034dd9284SPrzemyslaw Marczak 			mmc_type = IS_SD(m) ? "SD" : "eMMC";
171134dd9284SPrzemyslaw Marczak 		else
171234dd9284SPrzemyslaw Marczak 			mmc_type = NULL;
171334dd9284SPrzemyslaw Marczak 
171493bfd616SPantelis Antoniou 		printf("%s: %d", m->cfg->name, m->block_dev.dev);
171534dd9284SPrzemyslaw Marczak 		if (mmc_type)
171634dd9284SPrzemyslaw Marczak 			printf(" (%s)", mmc_type);
1717272cc70bSAndy Fleming 
1718e75eaf10SLubomir Popov 		if (entry->next != &mmc_devices) {
1719272cc70bSAndy Fleming 			printf("%c", separator);
1720e75eaf10SLubomir Popov 			if (separator != '\n')
1721e75eaf10SLubomir Popov 				puts (" ");
1722e75eaf10SLubomir Popov 		}
1723272cc70bSAndy Fleming 	}
1724272cc70bSAndy Fleming 
1725272cc70bSAndy Fleming 	printf("\n");
1726272cc70bSAndy Fleming }
1727272cc70bSAndy Fleming 
172856196826SPaul Burton #else
172956196826SPaul Burton void print_mmc_devices(char separator) { }
173056196826SPaul Burton #endif
173156196826SPaul Burton 
1732ea6ebe21SLei Wen int get_mmc_num(void)
1733ea6ebe21SLei Wen {
1734ea6ebe21SLei Wen 	return cur_dev_num;
1735ea6ebe21SLei Wen }
1736ea6ebe21SLei Wen 
1737e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
1738e9550449SChe-Liang Chiou {
1739e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
1740e9550449SChe-Liang Chiou }
1741e9550449SChe-Liang Chiou 
1742e9550449SChe-Liang Chiou static void do_preinit(void)
1743e9550449SChe-Liang Chiou {
1744e9550449SChe-Liang Chiou 	struct mmc *m;
1745e9550449SChe-Liang Chiou 	struct list_head *entry;
1746e9550449SChe-Liang Chiou 
1747e9550449SChe-Liang Chiou 	list_for_each(entry, &mmc_devices) {
1748e9550449SChe-Liang Chiou 		m = list_entry(entry, struct mmc, link);
1749e9550449SChe-Liang Chiou 
1750e9550449SChe-Liang Chiou 		if (m->preinit)
1751e9550449SChe-Liang Chiou 			mmc_start_init(m);
1752e9550449SChe-Liang Chiou 	}
1753e9550449SChe-Liang Chiou }
1754e9550449SChe-Liang Chiou 
1755e9550449SChe-Liang Chiou 
1756272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1757272cc70bSAndy Fleming {
1758272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc_devices);
1759272cc70bSAndy Fleming 	cur_dev_num = 0;
1760272cc70bSAndy Fleming 
1761272cc70bSAndy Fleming 	if (board_mmc_init(bis) < 0)
1762272cc70bSAndy Fleming 		cpu_mmc_init(bis);
1763272cc70bSAndy Fleming 
1764bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
1765272cc70bSAndy Fleming 	print_mmc_devices(',');
1766bb0dc108SYing Zhang #endif
1767272cc70bSAndy Fleming 
1768e9550449SChe-Liang Chiou 	do_preinit();
1769272cc70bSAndy Fleming 	return 0;
1770272cc70bSAndy Fleming }
17713690d6d6SAmar 
17723690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT
17733690d6d6SAmar /*
17743690d6d6SAmar  * This function changes the size of boot partition and the size of rpmb
17753690d6d6SAmar  * partition present on EMMC devices.
17763690d6d6SAmar  *
17773690d6d6SAmar  * Input Parameters:
17783690d6d6SAmar  * struct *mmc: pointer for the mmc device strcuture
17793690d6d6SAmar  * bootsize: size of boot partition
17803690d6d6SAmar  * rpmbsize: size of rpmb partition
17813690d6d6SAmar  *
17823690d6d6SAmar  * Returns 0 on success.
17833690d6d6SAmar  */
17843690d6d6SAmar 
17853690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
17863690d6d6SAmar 				unsigned long rpmbsize)
17873690d6d6SAmar {
17883690d6d6SAmar 	int err;
17893690d6d6SAmar 	struct mmc_cmd cmd;
17903690d6d6SAmar 
17913690d6d6SAmar 	/* Only use this command for raw EMMC moviNAND. Enter backdoor mode */
17923690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
17933690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
17943690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG1;
17953690d6d6SAmar 
17963690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
17973690d6d6SAmar 	if (err) {
17983690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error1 = %d\n", err);
17993690d6d6SAmar 		return err;
18003690d6d6SAmar 	}
18013690d6d6SAmar 
18023690d6d6SAmar 	/* Boot partition changing mode */
18033690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18043690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18053690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG2;
18063690d6d6SAmar 
18073690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18083690d6d6SAmar 	if (err) {
18093690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error2 = %d\n", err);
18103690d6d6SAmar 		return err;
18113690d6d6SAmar 	}
18123690d6d6SAmar 	/* boot partition size is multiple of 128KB */
18133690d6d6SAmar 	bootsize = (bootsize * 1024) / 128;
18143690d6d6SAmar 
18153690d6d6SAmar 	/* Arg: boot partition size */
18163690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18173690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18183690d6d6SAmar 	cmd.cmdarg = bootsize;
18193690d6d6SAmar 
18203690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18213690d6d6SAmar 	if (err) {
18223690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error3 = %d\n", err);
18233690d6d6SAmar 		return err;
18243690d6d6SAmar 	}
18253690d6d6SAmar 	/* RPMB partition size is multiple of 128KB */
18263690d6d6SAmar 	rpmbsize = (rpmbsize * 1024) / 128;
18273690d6d6SAmar 	/* Arg: RPMB partition size */
18283690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
18293690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
18303690d6d6SAmar 	cmd.cmdarg = rpmbsize;
18313690d6d6SAmar 
18323690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
18333690d6d6SAmar 	if (err) {
18343690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error4 = %d\n", err);
18353690d6d6SAmar 		return err;
18363690d6d6SAmar 	}
18373690d6d6SAmar 	return 0;
18383690d6d6SAmar }
18393690d6d6SAmar 
18403690d6d6SAmar /*
18415a99b9deSTom Rini  * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH
18425a99b9deSTom Rini  * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH
18435a99b9deSTom Rini  * and BOOT_MODE.
18445a99b9deSTom Rini  *
18455a99b9deSTom Rini  * Returns 0 on success.
18465a99b9deSTom Rini  */
18475a99b9deSTom Rini int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode)
18485a99b9deSTom Rini {
18495a99b9deSTom Rini 	int err;
18505a99b9deSTom Rini 
18515a99b9deSTom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH,
18525a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) |
18535a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) |
18545a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width));
18555a99b9deSTom Rini 
18565a99b9deSTom Rini 	if (err)
18575a99b9deSTom Rini 		return err;
18585a99b9deSTom Rini 	return 0;
18595a99b9deSTom Rini }
18605a99b9deSTom Rini 
18615a99b9deSTom Rini /*
1862792970b0STom Rini  * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG)
1863792970b0STom Rini  * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and
1864792970b0STom Rini  * PARTITION_ACCESS.
1865792970b0STom Rini  *
1866792970b0STom Rini  * Returns 0 on success.
1867792970b0STom Rini  */
1868792970b0STom Rini int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access)
1869792970b0STom Rini {
1870792970b0STom Rini 	int err;
1871792970b0STom Rini 
1872792970b0STom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
1873792970b0STom Rini 			 EXT_CSD_BOOT_ACK(ack) |
1874792970b0STom Rini 			 EXT_CSD_BOOT_PART_NUM(part_num) |
1875792970b0STom Rini 			 EXT_CSD_PARTITION_ACCESS(access));
1876792970b0STom Rini 
1877792970b0STom Rini 	if (err)
1878792970b0STom Rini 		return err;
1879792970b0STom Rini 	return 0;
1880792970b0STom Rini }
188133ace362STom Rini 
188233ace362STom Rini /*
188333ace362STom Rini  * Modify EXT_CSD[162] which is RST_n_FUNCTION based on the given value
188433ace362STom Rini  * for enable.  Note that this is a write-once field for non-zero values.
188533ace362STom Rini  *
188633ace362STom Rini  * Returns 0 on success.
188733ace362STom Rini  */
188833ace362STom Rini int mmc_set_rst_n_function(struct mmc *mmc, u8 enable)
188933ace362STom Rini {
189033ace362STom Rini 	return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_RST_N_FUNCTION,
189133ace362STom Rini 			  enable);
189233ace362STom Rini }
18933690d6d6SAmar #endif
1894