xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 5a99b9de1a845bf254292ae4730633e6ca8a29c7)
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>
13272cc70bSAndy Fleming #include <mmc.h>
14272cc70bSAndy Fleming #include <part.h>
15272cc70bSAndy Fleming #include <malloc.h>
16272cc70bSAndy Fleming #include <linux/list.h>
179b1f942cSRabin Vincent #include <div64.h>
18da61fa5fSPaul Burton #include "mmc_private.h"
19272cc70bSAndy Fleming 
20ce0fbcd2SMatt Waddel /* Set block count limit because of 16 bit register limit on some hardware*/
21ce0fbcd2SMatt Waddel #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT
22ce0fbcd2SMatt Waddel #define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535
23ce0fbcd2SMatt Waddel #endif
24ce0fbcd2SMatt Waddel 
25272cc70bSAndy Fleming static struct list_head mmc_devices;
26272cc70bSAndy Fleming static int cur_dev_num = -1;
27272cc70bSAndy Fleming 
28d23d8d7eSNikita Kiryanov int __weak board_mmc_getwp(struct mmc *mmc)
29d23d8d7eSNikita Kiryanov {
30d23d8d7eSNikita Kiryanov 	return -1;
31d23d8d7eSNikita Kiryanov }
32d23d8d7eSNikita Kiryanov 
33d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
34d23d8d7eSNikita Kiryanov {
35d23d8d7eSNikita Kiryanov 	int wp;
36d23d8d7eSNikita Kiryanov 
37d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
38d23d8d7eSNikita Kiryanov 
39d4e1da4eSPeter Korsgaard 	if (wp < 0) {
40d4e1da4eSPeter Korsgaard 		if (mmc->getwp)
41d23d8d7eSNikita Kiryanov 			wp = mmc->getwp(mmc);
42d4e1da4eSPeter Korsgaard 		else
43d4e1da4eSPeter Korsgaard 			wp = 0;
44d4e1da4eSPeter Korsgaard 	}
45d23d8d7eSNikita Kiryanov 
46d23d8d7eSNikita Kiryanov 	return wp;
47d23d8d7eSNikita Kiryanov }
48d23d8d7eSNikita Kiryanov 
49314284b1SThierry Reding int __board_mmc_getcd(struct mmc *mmc) {
5011fdade2SStefano Babic 	return -1;
5111fdade2SStefano Babic }
5211fdade2SStefano Babic 
53314284b1SThierry Reding int board_mmc_getcd(struct mmc *mmc)__attribute__((weak,
5411fdade2SStefano Babic 	alias("__board_mmc_getcd")));
5511fdade2SStefano Babic 
56da61fa5fSPaul Burton int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
57272cc70bSAndy Fleming {
585db2fe3aSRaffaele Recalcati 	int ret;
598635ff9eSMarek Vasut 
608635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
615db2fe3aSRaffaele Recalcati 	int i;
625db2fe3aSRaffaele Recalcati 	u8 *ptr;
635db2fe3aSRaffaele Recalcati 
645db2fe3aSRaffaele Recalcati 	printf("CMD_SEND:%d\n", cmd->cmdidx);
655db2fe3aSRaffaele Recalcati 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
665db2fe3aSRaffaele Recalcati 	ret = mmc->send_cmd(mmc, cmd, data);
675db2fe3aSRaffaele Recalcati 	switch (cmd->resp_type) {
685db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
695db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
705db2fe3aSRaffaele Recalcati 			break;
715db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
725db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
735db2fe3aSRaffaele Recalcati 				cmd->response[0]);
745db2fe3aSRaffaele Recalcati 			break;
755db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
765db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
775db2fe3aSRaffaele Recalcati 				cmd->response[0]);
785db2fe3aSRaffaele Recalcati 			break;
795db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
805db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
815db2fe3aSRaffaele Recalcati 				cmd->response[0]);
825db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
835db2fe3aSRaffaele Recalcati 				cmd->response[1]);
845db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
855db2fe3aSRaffaele Recalcati 				cmd->response[2]);
865db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
875db2fe3aSRaffaele Recalcati 				cmd->response[3]);
885db2fe3aSRaffaele Recalcati 			printf("\n");
895db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
905db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
915db2fe3aSRaffaele Recalcati 				int j;
925db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
93146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
945db2fe3aSRaffaele Recalcati 				ptr += 3;
955db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
965db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
975db2fe3aSRaffaele Recalcati 				printf("\n");
985db2fe3aSRaffaele Recalcati 			}
995db2fe3aSRaffaele Recalcati 			break;
1005db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1015db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1025db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1035db2fe3aSRaffaele Recalcati 			break;
1045db2fe3aSRaffaele Recalcati 		default:
1055db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1065db2fe3aSRaffaele Recalcati 			break;
1075db2fe3aSRaffaele Recalcati 	}
1085db2fe3aSRaffaele Recalcati #else
1098635ff9eSMarek Vasut 	ret = mmc->send_cmd(mmc, cmd, data);
1105db2fe3aSRaffaele Recalcati #endif
1118635ff9eSMarek Vasut 	return ret;
112272cc70bSAndy Fleming }
113272cc70bSAndy Fleming 
114da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
1155d4fc8d9SRaffaele Recalcati {
1165d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
117d617c426SJan Kloetzke 	int err, retries = 5;
1185d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
1195d4fc8d9SRaffaele Recalcati 	int status;
1205d4fc8d9SRaffaele Recalcati #endif
1215d4fc8d9SRaffaele Recalcati 
1225d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
1235d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
124aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
125aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
1265d4fc8d9SRaffaele Recalcati 
1275d4fc8d9SRaffaele Recalcati 	do {
1285d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
129d617c426SJan Kloetzke 		if (!err) {
130d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
131d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
132d617c426SJan Kloetzke 			     MMC_STATE_PRG)
1335d4fc8d9SRaffaele Recalcati 				break;
134d617c426SJan Kloetzke 			else if (cmd.response[0] & MMC_STATUS_MASK) {
13556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
136d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
137d617c426SJan Kloetzke 					cmd.response[0]);
13856196826SPaul Burton #endif
139d617c426SJan Kloetzke 				return COMM_ERR;
140d617c426SJan Kloetzke 			}
141d617c426SJan Kloetzke 		} else if (--retries < 0)
142d617c426SJan Kloetzke 			return err;
1435d4fc8d9SRaffaele Recalcati 
1445d4fc8d9SRaffaele Recalcati 		udelay(1000);
1455d4fc8d9SRaffaele Recalcati 
1465d4fc8d9SRaffaele Recalcati 	} while (timeout--);
1475d4fc8d9SRaffaele Recalcati 
1485db2fe3aSRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
1495db2fe3aSRaffaele Recalcati 	status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9;
1505db2fe3aSRaffaele Recalcati 	printf("CURR STATE:%d\n", status);
1515db2fe3aSRaffaele Recalcati #endif
1525b0c942fSJongman Heo 	if (timeout <= 0) {
15356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1545d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
15556196826SPaul Burton #endif
1565d4fc8d9SRaffaele Recalcati 		return TIMEOUT;
1575d4fc8d9SRaffaele Recalcati 	}
1585d4fc8d9SRaffaele Recalcati 
1595d4fc8d9SRaffaele Recalcati 	return 0;
1605d4fc8d9SRaffaele Recalcati }
1615d4fc8d9SRaffaele Recalcati 
162da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
163272cc70bSAndy Fleming {
164272cc70bSAndy Fleming 	struct mmc_cmd cmd;
165272cc70bSAndy Fleming 
166272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
167272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
168272cc70bSAndy Fleming 	cmd.cmdarg = len;
169272cc70bSAndy Fleming 
170272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
171272cc70bSAndy Fleming }
172272cc70bSAndy Fleming 
173272cc70bSAndy Fleming struct mmc *find_mmc_device(int dev_num)
174272cc70bSAndy Fleming {
175272cc70bSAndy Fleming 	struct mmc *m;
176272cc70bSAndy Fleming 	struct list_head *entry;
177272cc70bSAndy Fleming 
178272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
179272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
180272cc70bSAndy Fleming 
181272cc70bSAndy Fleming 		if (m->block_dev.dev == dev_num)
182272cc70bSAndy Fleming 			return m;
183272cc70bSAndy Fleming 	}
184272cc70bSAndy Fleming 
18556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
186272cc70bSAndy Fleming 	printf("MMC Device %d not found\n", dev_num);
18756196826SPaul Burton #endif
188272cc70bSAndy Fleming 
189272cc70bSAndy Fleming 	return NULL;
190272cc70bSAndy Fleming }
191272cc70bSAndy Fleming 
192ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
193fdbb873eSKim Phillips 			   lbaint_t blkcnt)
194272cc70bSAndy Fleming {
195272cc70bSAndy Fleming 	struct mmc_cmd cmd;
196272cc70bSAndy Fleming 	struct mmc_data data;
197272cc70bSAndy Fleming 
1984a1a06bcSAlagu Sankar 	if (blkcnt > 1)
1994a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
2004a1a06bcSAlagu Sankar 	else
201272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
202272cc70bSAndy Fleming 
203272cc70bSAndy Fleming 	if (mmc->high_capacity)
2044a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
205272cc70bSAndy Fleming 	else
2064a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
207272cc70bSAndy Fleming 
208272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
209272cc70bSAndy Fleming 
210272cc70bSAndy Fleming 	data.dest = dst;
2114a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
212272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
213272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
214272cc70bSAndy Fleming 
2154a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
2164a1a06bcSAlagu Sankar 		return 0;
2174a1a06bcSAlagu Sankar 
2184a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
2194a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
2204a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
2214a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
2224a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
22356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2244a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
22556196826SPaul Burton #endif
2264a1a06bcSAlagu Sankar 			return 0;
2274a1a06bcSAlagu Sankar 		}
228272cc70bSAndy Fleming 	}
229272cc70bSAndy Fleming 
2304a1a06bcSAlagu Sankar 	return blkcnt;
231272cc70bSAndy Fleming }
232272cc70bSAndy Fleming 
233ff8fef56SSascha Silbe static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst)
234272cc70bSAndy Fleming {
2354a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
236272cc70bSAndy Fleming 
2374a1a06bcSAlagu Sankar 	if (blkcnt == 0)
2384a1a06bcSAlagu Sankar 		return 0;
2394a1a06bcSAlagu Sankar 
2404a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
241272cc70bSAndy Fleming 	if (!mmc)
242272cc70bSAndy Fleming 		return 0;
243272cc70bSAndy Fleming 
244d2bf29e3SLei Wen 	if ((start + blkcnt) > mmc->block_dev.lba) {
24556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
246ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
247d2bf29e3SLei Wen 			start + blkcnt, mmc->block_dev.lba);
24856196826SPaul Burton #endif
249d2bf29e3SLei Wen 		return 0;
250d2bf29e3SLei Wen 	}
251272cc70bSAndy Fleming 
2524a1a06bcSAlagu Sankar 	if (mmc_set_blocklen(mmc, mmc->read_bl_len))
253272cc70bSAndy Fleming 		return 0;
254272cc70bSAndy Fleming 
2554a1a06bcSAlagu Sankar 	do {
2568feafcc4SJohn Rigby 		cur = (blocks_todo > mmc->b_max) ?  mmc->b_max : blocks_todo;
2574a1a06bcSAlagu Sankar 		if(mmc_read_blocks(mmc, dst, start, cur) != cur)
2584a1a06bcSAlagu Sankar 			return 0;
2594a1a06bcSAlagu Sankar 		blocks_todo -= cur;
2604a1a06bcSAlagu Sankar 		start += cur;
2614a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
2624a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
263272cc70bSAndy Fleming 
264272cc70bSAndy Fleming 	return blkcnt;
265272cc70bSAndy Fleming }
266272cc70bSAndy Fleming 
267fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
268272cc70bSAndy Fleming {
269272cc70bSAndy Fleming 	struct mmc_cmd cmd;
270272cc70bSAndy Fleming 	int err;
271272cc70bSAndy Fleming 
272272cc70bSAndy Fleming 	udelay(1000);
273272cc70bSAndy Fleming 
274272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
275272cc70bSAndy Fleming 	cmd.cmdarg = 0;
276272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
277272cc70bSAndy Fleming 
278272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
279272cc70bSAndy Fleming 
280272cc70bSAndy Fleming 	if (err)
281272cc70bSAndy Fleming 		return err;
282272cc70bSAndy Fleming 
283272cc70bSAndy Fleming 	udelay(2000);
284272cc70bSAndy Fleming 
285272cc70bSAndy Fleming 	return 0;
286272cc70bSAndy Fleming }
287272cc70bSAndy Fleming 
288fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
289272cc70bSAndy Fleming {
290272cc70bSAndy Fleming 	int timeout = 1000;
291272cc70bSAndy Fleming 	int err;
292272cc70bSAndy Fleming 	struct mmc_cmd cmd;
293272cc70bSAndy Fleming 
294272cc70bSAndy Fleming 	do {
295272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
296272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
297272cc70bSAndy Fleming 		cmd.cmdarg = 0;
298272cc70bSAndy Fleming 
299272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
300272cc70bSAndy Fleming 
301272cc70bSAndy Fleming 		if (err)
302272cc70bSAndy Fleming 			return err;
303272cc70bSAndy Fleming 
304272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
305272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
306250de12bSStefano Babic 
307250de12bSStefano Babic 		/*
308250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
309250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
310250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
311250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
312250de12bSStefano Babic 		 * specified.
313250de12bSStefano Babic 		 */
314d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
315d52ebf10SThomas Chou 			(mmc->voltages & 0xff8000);
316272cc70bSAndy Fleming 
317272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
318272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
319272cc70bSAndy Fleming 
320272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
321272cc70bSAndy Fleming 
322272cc70bSAndy Fleming 		if (err)
323272cc70bSAndy Fleming 			return err;
324272cc70bSAndy Fleming 
325272cc70bSAndy Fleming 		udelay(1000);
326272cc70bSAndy Fleming 	} while ((!(cmd.response[0] & OCR_BUSY)) && timeout--);
327272cc70bSAndy Fleming 
328272cc70bSAndy Fleming 	if (timeout <= 0)
329272cc70bSAndy Fleming 		return UNUSABLE_ERR;
330272cc70bSAndy Fleming 
331272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
332272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
333272cc70bSAndy Fleming 
334d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
335d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
336d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
337d52ebf10SThomas Chou 		cmd.cmdarg = 0;
338d52ebf10SThomas Chou 
339d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
340d52ebf10SThomas Chou 
341d52ebf10SThomas Chou 		if (err)
342d52ebf10SThomas Chou 			return err;
343d52ebf10SThomas Chou 	}
344d52ebf10SThomas Chou 
345998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
346272cc70bSAndy Fleming 
347272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
348272cc70bSAndy Fleming 	mmc->rca = 0;
349272cc70bSAndy Fleming 
350272cc70bSAndy Fleming 	return 0;
351272cc70bSAndy Fleming }
352272cc70bSAndy Fleming 
353e9550449SChe-Liang Chiou /* We pass in the cmd since otherwise the init seems to fail */
354e9550449SChe-Liang Chiou static int mmc_send_op_cond_iter(struct mmc *mmc, struct mmc_cmd *cmd,
355e9550449SChe-Liang Chiou 		int use_arg)
356272cc70bSAndy Fleming {
357272cc70bSAndy Fleming 	int err;
358272cc70bSAndy Fleming 
359e9550449SChe-Liang Chiou 	cmd->cmdidx = MMC_CMD_SEND_OP_COND;
360e9550449SChe-Liang Chiou 	cmd->resp_type = MMC_RSP_R3;
361e9550449SChe-Liang Chiou 	cmd->cmdarg = 0;
362e9550449SChe-Liang Chiou 	if (use_arg && !mmc_host_is_spi(mmc)) {
363e9550449SChe-Liang Chiou 		cmd->cmdarg =
364e9550449SChe-Liang Chiou 			(mmc->voltages &
365e9550449SChe-Liang Chiou 			(mmc->op_cond_response & OCR_VOLTAGE_MASK)) |
366e9550449SChe-Liang Chiou 			(mmc->op_cond_response & OCR_ACCESS_MODE);
367e9550449SChe-Liang Chiou 
368e9550449SChe-Liang Chiou 		if (mmc->host_caps & MMC_MODE_HC)
369e9550449SChe-Liang Chiou 			cmd->cmdarg |= OCR_HCS;
370e9550449SChe-Liang Chiou 	}
371e9550449SChe-Liang Chiou 	err = mmc_send_cmd(mmc, cmd, NULL);
372e9550449SChe-Liang Chiou 	if (err)
373e9550449SChe-Liang Chiou 		return err;
374e9550449SChe-Liang Chiou 	mmc->op_cond_response = cmd->response[0];
375e9550449SChe-Liang Chiou 	return 0;
376e9550449SChe-Liang Chiou }
377e9550449SChe-Liang Chiou 
378e9550449SChe-Liang Chiou int mmc_send_op_cond(struct mmc *mmc)
379e9550449SChe-Liang Chiou {
380e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
381e9550449SChe-Liang Chiou 	int err, i;
382e9550449SChe-Liang Chiou 
383272cc70bSAndy Fleming 	/* Some cards seem to need this */
384272cc70bSAndy Fleming 	mmc_go_idle(mmc);
385272cc70bSAndy Fleming 
38631cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
387e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 1;
388e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
389e9550449SChe-Liang Chiou 		err = mmc_send_op_cond_iter(mmc, &cmd, i != 0);
39031cacbabSRaffaele Recalcati 		if (err)
39131cacbabSRaffaele Recalcati 			return err;
39231cacbabSRaffaele Recalcati 
393e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
394e9550449SChe-Liang Chiou 		if (mmc->op_cond_response & OCR_BUSY)
395e9550449SChe-Liang Chiou 			return 0;
396e9550449SChe-Liang Chiou 	}
397e9550449SChe-Liang Chiou 	return IN_PROGRESS;
398e9550449SChe-Liang Chiou }
39931cacbabSRaffaele Recalcati 
400e9550449SChe-Liang Chiou int mmc_complete_op_cond(struct mmc *mmc)
401e9550449SChe-Liang Chiou {
402e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
403e9550449SChe-Liang Chiou 	int timeout = 1000;
404e9550449SChe-Liang Chiou 	uint start;
405e9550449SChe-Liang Chiou 	int err;
406e9550449SChe-Liang Chiou 
407e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
408e9550449SChe-Liang Chiou 	start = get_timer(0);
409272cc70bSAndy Fleming 	do {
410e9550449SChe-Liang Chiou 		err = mmc_send_op_cond_iter(mmc, &cmd, 1);
411272cc70bSAndy Fleming 		if (err)
412272cc70bSAndy Fleming 			return err;
413e9550449SChe-Liang Chiou 		if (get_timer(start) > timeout)
414272cc70bSAndy Fleming 			return UNUSABLE_ERR;
415e9550449SChe-Liang Chiou 		udelay(100);
416e9550449SChe-Liang Chiou 	} while (!(mmc->op_cond_response & OCR_BUSY));
417272cc70bSAndy Fleming 
418d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
419d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
420d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
421d52ebf10SThomas Chou 		cmd.cmdarg = 0;
422d52ebf10SThomas Chou 
423d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
424d52ebf10SThomas Chou 
425d52ebf10SThomas Chou 		if (err)
426d52ebf10SThomas Chou 			return err;
427d52ebf10SThomas Chou 	}
428d52ebf10SThomas Chou 
429272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
430998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
431272cc70bSAndy Fleming 
432272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
433def816a2SStephen Warren 	mmc->rca = 1;
434272cc70bSAndy Fleming 
435272cc70bSAndy Fleming 	return 0;
436272cc70bSAndy Fleming }
437272cc70bSAndy Fleming 
438272cc70bSAndy Fleming 
439fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
440272cc70bSAndy Fleming {
441272cc70bSAndy Fleming 	struct mmc_cmd cmd;
442272cc70bSAndy Fleming 	struct mmc_data data;
443272cc70bSAndy Fleming 	int err;
444272cc70bSAndy Fleming 
445272cc70bSAndy Fleming 	/* Get the Card Status Register */
446272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
447272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
448272cc70bSAndy Fleming 	cmd.cmdarg = 0;
449272cc70bSAndy Fleming 
450cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
451272cc70bSAndy Fleming 	data.blocks = 1;
4528bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
453272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
454272cc70bSAndy Fleming 
455272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
456272cc70bSAndy Fleming 
457272cc70bSAndy Fleming 	return err;
458272cc70bSAndy Fleming }
459272cc70bSAndy Fleming 
460272cc70bSAndy Fleming 
461fdbb873eSKim Phillips static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
462272cc70bSAndy Fleming {
463272cc70bSAndy Fleming 	struct mmc_cmd cmd;
4645d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
4655d4fc8d9SRaffaele Recalcati 	int ret;
466272cc70bSAndy Fleming 
467272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
468272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
469272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
470272cc70bSAndy Fleming 				 (index << 16) |
471272cc70bSAndy Fleming 				 (value << 8);
472272cc70bSAndy Fleming 
4735d4fc8d9SRaffaele Recalcati 	ret = mmc_send_cmd(mmc, &cmd, NULL);
4745d4fc8d9SRaffaele Recalcati 
4755d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
47693ad0d18SJan Kloetzke 	if (!ret)
47793ad0d18SJan Kloetzke 		ret = mmc_send_status(mmc, timeout);
4785d4fc8d9SRaffaele Recalcati 
4795d4fc8d9SRaffaele Recalcati 	return ret;
4805d4fc8d9SRaffaele Recalcati 
481272cc70bSAndy Fleming }
482272cc70bSAndy Fleming 
483fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
484272cc70bSAndy Fleming {
4858bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
486272cc70bSAndy Fleming 	char cardtype;
487272cc70bSAndy Fleming 	int err;
488272cc70bSAndy Fleming 
489272cc70bSAndy Fleming 	mmc->card_caps = 0;
490272cc70bSAndy Fleming 
491d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
492d52ebf10SThomas Chou 		return 0;
493d52ebf10SThomas Chou 
494272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
495272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
496272cc70bSAndy Fleming 		return 0;
497272cc70bSAndy Fleming 
498272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
499272cc70bSAndy Fleming 
500272cc70bSAndy Fleming 	if (err)
501272cc70bSAndy Fleming 		return err;
502272cc70bSAndy Fleming 
5030560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
504272cc70bSAndy Fleming 
505272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
506272cc70bSAndy Fleming 
507272cc70bSAndy Fleming 	if (err)
508272cc70bSAndy Fleming 		return err;
509272cc70bSAndy Fleming 
510272cc70bSAndy Fleming 	/* Now check to see that it worked */
511272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
512272cc70bSAndy Fleming 
513272cc70bSAndy Fleming 	if (err)
514272cc70bSAndy Fleming 		return err;
515272cc70bSAndy Fleming 
516272cc70bSAndy Fleming 	/* No high-speed support */
5170560db18SLei Wen 	if (!ext_csd[EXT_CSD_HS_TIMING])
518272cc70bSAndy Fleming 		return 0;
519272cc70bSAndy Fleming 
520272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
521272cc70bSAndy Fleming 	if (cardtype & MMC_HS_52MHZ)
522272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
523272cc70bSAndy Fleming 	else
524272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
525272cc70bSAndy Fleming 
526272cc70bSAndy Fleming 	return 0;
527272cc70bSAndy Fleming }
528272cc70bSAndy Fleming 
529f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
530f866a46dSStephen Warren {
531f866a46dSStephen Warren 	switch (part_num) {
532f866a46dSStephen Warren 	case 0:
533f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
534f866a46dSStephen Warren 		break;
535f866a46dSStephen Warren 	case 1:
536f866a46dSStephen Warren 	case 2:
537f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
538f866a46dSStephen Warren 		break;
539f866a46dSStephen Warren 	case 3:
540f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
541f866a46dSStephen Warren 		break;
542f866a46dSStephen Warren 	case 4:
543f866a46dSStephen Warren 	case 5:
544f866a46dSStephen Warren 	case 6:
545f866a46dSStephen Warren 	case 7:
546f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
547f866a46dSStephen Warren 		break;
548f866a46dSStephen Warren 	default:
549f866a46dSStephen Warren 		return -1;
550f866a46dSStephen Warren 	}
551f866a46dSStephen Warren 
552f866a46dSStephen Warren 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
553f866a46dSStephen Warren 
554f866a46dSStephen Warren 	return 0;
555f866a46dSStephen Warren }
556f866a46dSStephen Warren 
557bc897b1dSLei Wen int mmc_switch_part(int dev_num, unsigned int part_num)
558bc897b1dSLei Wen {
559bc897b1dSLei Wen 	struct mmc *mmc = find_mmc_device(dev_num);
560f866a46dSStephen Warren 	int ret;
561bc897b1dSLei Wen 
562bc897b1dSLei Wen 	if (!mmc)
563bc897b1dSLei Wen 		return -1;
564bc897b1dSLei Wen 
565f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
566bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
567bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
568f866a46dSStephen Warren 	if (ret)
569f866a46dSStephen Warren 		return ret;
570f866a46dSStephen Warren 
571f866a46dSStephen Warren 	return mmc_set_capacity(mmc, part_num);
572bc897b1dSLei Wen }
573bc897b1dSLei Wen 
57448972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
57548972d90SThierry Reding {
57648972d90SThierry Reding 	int cd;
57748972d90SThierry Reding 
57848972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
57948972d90SThierry Reding 
580d4e1da4eSPeter Korsgaard 	if (cd < 0) {
581d4e1da4eSPeter Korsgaard 		if (mmc->getcd)
58248972d90SThierry Reding 			cd = mmc->getcd(mmc);
583d4e1da4eSPeter Korsgaard 		else
584d4e1da4eSPeter Korsgaard 			cd = 1;
585d4e1da4eSPeter Korsgaard 	}
58648972d90SThierry Reding 
58748972d90SThierry Reding 	return cd;
58848972d90SThierry Reding }
58948972d90SThierry Reding 
590fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
591272cc70bSAndy Fleming {
592272cc70bSAndy Fleming 	struct mmc_cmd cmd;
593272cc70bSAndy Fleming 	struct mmc_data data;
594272cc70bSAndy Fleming 
595272cc70bSAndy Fleming 	/* Switch the frequency */
596272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
597272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
598272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
599272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
600272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
601272cc70bSAndy Fleming 
602272cc70bSAndy Fleming 	data.dest = (char *)resp;
603272cc70bSAndy Fleming 	data.blocksize = 64;
604272cc70bSAndy Fleming 	data.blocks = 1;
605272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
606272cc70bSAndy Fleming 
607272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
608272cc70bSAndy Fleming }
609272cc70bSAndy Fleming 
610272cc70bSAndy Fleming 
611fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
612272cc70bSAndy Fleming {
613272cc70bSAndy Fleming 	int err;
614272cc70bSAndy Fleming 	struct mmc_cmd cmd;
615f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
616f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
617272cc70bSAndy Fleming 	struct mmc_data data;
618272cc70bSAndy Fleming 	int timeout;
619272cc70bSAndy Fleming 
620272cc70bSAndy Fleming 	mmc->card_caps = 0;
621272cc70bSAndy Fleming 
622d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
623d52ebf10SThomas Chou 		return 0;
624d52ebf10SThomas Chou 
625272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
626272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
627272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
628272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
629272cc70bSAndy Fleming 
630272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
631272cc70bSAndy Fleming 
632272cc70bSAndy Fleming 	if (err)
633272cc70bSAndy Fleming 		return err;
634272cc70bSAndy Fleming 
635272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
636272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
637272cc70bSAndy Fleming 	cmd.cmdarg = 0;
638272cc70bSAndy Fleming 
639272cc70bSAndy Fleming 	timeout = 3;
640272cc70bSAndy Fleming 
641272cc70bSAndy Fleming retry_scr:
642f781dd38SAnton staaf 	data.dest = (char *)scr;
643272cc70bSAndy Fleming 	data.blocksize = 8;
644272cc70bSAndy Fleming 	data.blocks = 1;
645272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
646272cc70bSAndy Fleming 
647272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
648272cc70bSAndy Fleming 
649272cc70bSAndy Fleming 	if (err) {
650272cc70bSAndy Fleming 		if (timeout--)
651272cc70bSAndy Fleming 			goto retry_scr;
652272cc70bSAndy Fleming 
653272cc70bSAndy Fleming 		return err;
654272cc70bSAndy Fleming 	}
655272cc70bSAndy Fleming 
6564e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
6574e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
658272cc70bSAndy Fleming 
659272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
660272cc70bSAndy Fleming 		case 0:
661272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
662272cc70bSAndy Fleming 			break;
663272cc70bSAndy Fleming 		case 1:
664272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_10;
665272cc70bSAndy Fleming 			break;
666272cc70bSAndy Fleming 		case 2:
667272cc70bSAndy Fleming 			mmc->version = SD_VERSION_2;
6681741c64dSJaehoon Chung 			if ((mmc->scr[0] >> 15) & 0x1)
6691741c64dSJaehoon Chung 				mmc->version = SD_VERSION_3;
670272cc70bSAndy Fleming 			break;
671272cc70bSAndy Fleming 		default:
672272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
673272cc70bSAndy Fleming 			break;
674272cc70bSAndy Fleming 	}
675272cc70bSAndy Fleming 
676b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
677b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
678b44c7083SAlagu Sankar 
679272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
680272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
681272cc70bSAndy Fleming 		return 0;
682272cc70bSAndy Fleming 
683272cc70bSAndy Fleming 	timeout = 4;
684272cc70bSAndy Fleming 	while (timeout--) {
685272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
686f781dd38SAnton staaf 				(u8 *)switch_status);
687272cc70bSAndy Fleming 
688272cc70bSAndy Fleming 		if (err)
689272cc70bSAndy Fleming 			return err;
690272cc70bSAndy Fleming 
691272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
6924e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
693272cc70bSAndy Fleming 			break;
694272cc70bSAndy Fleming 	}
695272cc70bSAndy Fleming 
696272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
6974e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
698272cc70bSAndy Fleming 		return 0;
699272cc70bSAndy Fleming 
7002c3fbf4cSMacpaul Lin 	/*
7012c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
7022c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
7032c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
7042c3fbf4cSMacpaul Lin 	 * mode between the host.
7052c3fbf4cSMacpaul Lin 	 */
7062c3fbf4cSMacpaul Lin 	if (!((mmc->host_caps & MMC_MODE_HS_52MHz) &&
7072c3fbf4cSMacpaul Lin 		(mmc->host_caps & MMC_MODE_HS)))
7082c3fbf4cSMacpaul Lin 		return 0;
7092c3fbf4cSMacpaul Lin 
710f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
711272cc70bSAndy Fleming 
712272cc70bSAndy Fleming 	if (err)
713272cc70bSAndy Fleming 		return err;
714272cc70bSAndy Fleming 
7154e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
716272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
717272cc70bSAndy Fleming 
718272cc70bSAndy Fleming 	return 0;
719272cc70bSAndy Fleming }
720272cc70bSAndy Fleming 
721272cc70bSAndy Fleming /* frequency bases */
722272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
7235f837c2cSMike Frysinger static const int fbase[] = {
724272cc70bSAndy Fleming 	10000,
725272cc70bSAndy Fleming 	100000,
726272cc70bSAndy Fleming 	1000000,
727272cc70bSAndy Fleming 	10000000,
728272cc70bSAndy Fleming };
729272cc70bSAndy Fleming 
730272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
731272cc70bSAndy Fleming  * to platforms without floating point.
732272cc70bSAndy Fleming  */
7335f837c2cSMike Frysinger static const int multipliers[] = {
734272cc70bSAndy Fleming 	0,	/* reserved */
735272cc70bSAndy Fleming 	10,
736272cc70bSAndy Fleming 	12,
737272cc70bSAndy Fleming 	13,
738272cc70bSAndy Fleming 	15,
739272cc70bSAndy Fleming 	20,
740272cc70bSAndy Fleming 	25,
741272cc70bSAndy Fleming 	30,
742272cc70bSAndy Fleming 	35,
743272cc70bSAndy Fleming 	40,
744272cc70bSAndy Fleming 	45,
745272cc70bSAndy Fleming 	50,
746272cc70bSAndy Fleming 	55,
747272cc70bSAndy Fleming 	60,
748272cc70bSAndy Fleming 	70,
749272cc70bSAndy Fleming 	80,
750272cc70bSAndy Fleming };
751272cc70bSAndy Fleming 
752fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
753272cc70bSAndy Fleming {
754272cc70bSAndy Fleming 	mmc->set_ios(mmc);
755272cc70bSAndy Fleming }
756272cc70bSAndy Fleming 
757272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
758272cc70bSAndy Fleming {
759272cc70bSAndy Fleming 	if (clock > mmc->f_max)
760272cc70bSAndy Fleming 		clock = mmc->f_max;
761272cc70bSAndy Fleming 
762272cc70bSAndy Fleming 	if (clock < mmc->f_min)
763272cc70bSAndy Fleming 		clock = mmc->f_min;
764272cc70bSAndy Fleming 
765272cc70bSAndy Fleming 	mmc->clock = clock;
766272cc70bSAndy Fleming 
767272cc70bSAndy Fleming 	mmc_set_ios(mmc);
768272cc70bSAndy Fleming }
769272cc70bSAndy Fleming 
770fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width)
771272cc70bSAndy Fleming {
772272cc70bSAndy Fleming 	mmc->bus_width = width;
773272cc70bSAndy Fleming 
774272cc70bSAndy Fleming 	mmc_set_ios(mmc);
775272cc70bSAndy Fleming }
776272cc70bSAndy Fleming 
777fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
778272cc70bSAndy Fleming {
779f866a46dSStephen Warren 	int err, i;
780272cc70bSAndy Fleming 	uint mult, freq;
781639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
782272cc70bSAndy Fleming 	struct mmc_cmd cmd;
7838bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
7848bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
7855d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
786272cc70bSAndy Fleming 
787d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
788d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
789d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
790d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
791d52ebf10SThomas Chou 		cmd.cmdarg = 1;
792d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
793d52ebf10SThomas Chou 
794d52ebf10SThomas Chou 		if (err)
795d52ebf10SThomas Chou 			return err;
796d52ebf10SThomas Chou 	}
797d52ebf10SThomas Chou #endif
798d52ebf10SThomas Chou 
799272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
800d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
801d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
802272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
803272cc70bSAndy Fleming 	cmd.cmdarg = 0;
804272cc70bSAndy Fleming 
805272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
806272cc70bSAndy Fleming 
807272cc70bSAndy Fleming 	if (err)
808272cc70bSAndy Fleming 		return err;
809272cc70bSAndy Fleming 
810272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
811272cc70bSAndy Fleming 
812272cc70bSAndy Fleming 	/*
813272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
814272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
815272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
816272cc70bSAndy Fleming 	 */
817d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
818272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
819272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
820272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
821272cc70bSAndy Fleming 
822272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
823272cc70bSAndy Fleming 
824272cc70bSAndy Fleming 		if (err)
825272cc70bSAndy Fleming 			return err;
826272cc70bSAndy Fleming 
827272cc70bSAndy Fleming 		if (IS_SD(mmc))
828998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
829d52ebf10SThomas Chou 	}
830272cc70bSAndy Fleming 
831272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
832272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
833272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
834272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
835272cc70bSAndy Fleming 
836272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
837272cc70bSAndy Fleming 
8385d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
8395d4fc8d9SRaffaele Recalcati 	mmc_send_status(mmc, timeout);
8405d4fc8d9SRaffaele Recalcati 
841272cc70bSAndy Fleming 	if (err)
842272cc70bSAndy Fleming 		return err;
843272cc70bSAndy Fleming 
844998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
845998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
846998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
847998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
848272cc70bSAndy Fleming 
849272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
8500b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
851272cc70bSAndy Fleming 
852272cc70bSAndy Fleming 		switch (version) {
853272cc70bSAndy Fleming 			case 0:
854272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
855272cc70bSAndy Fleming 				break;
856272cc70bSAndy Fleming 			case 1:
857272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_4;
858272cc70bSAndy Fleming 				break;
859272cc70bSAndy Fleming 			case 2:
860272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_2_2;
861272cc70bSAndy Fleming 				break;
862272cc70bSAndy Fleming 			case 3:
863272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_3;
864272cc70bSAndy Fleming 				break;
865272cc70bSAndy Fleming 			case 4:
866272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_4;
867272cc70bSAndy Fleming 				break;
868272cc70bSAndy Fleming 			default:
869272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
870272cc70bSAndy Fleming 				break;
871272cc70bSAndy Fleming 		}
872272cc70bSAndy Fleming 	}
873272cc70bSAndy Fleming 
874272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
8750b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
8760b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
877272cc70bSAndy Fleming 
878272cc70bSAndy Fleming 	mmc->tran_speed = freq * mult;
879272cc70bSAndy Fleming 
880ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
881998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
882272cc70bSAndy Fleming 
883272cc70bSAndy Fleming 	if (IS_SD(mmc))
884272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
885272cc70bSAndy Fleming 	else
886998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
887272cc70bSAndy Fleming 
888272cc70bSAndy Fleming 	if (mmc->high_capacity) {
889272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
890272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
891272cc70bSAndy Fleming 		cmult = 8;
892272cc70bSAndy Fleming 	} else {
893272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
894272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
895272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
896272cc70bSAndy Fleming 	}
897272cc70bSAndy Fleming 
898f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
899f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
900f866a46dSStephen Warren 	mmc->capacity_boot = 0;
901f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
902f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
903f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
904272cc70bSAndy Fleming 
9058bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
9068bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
907272cc70bSAndy Fleming 
9088bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
9098bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
910272cc70bSAndy Fleming 
911ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
912ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
913ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
914ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
915ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
916ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
917ab71188cSMarkus Niebel 	}
918ab71188cSMarkus Niebel 
919272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
920d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
921272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
922fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
923272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
924272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
925272cc70bSAndy Fleming 
926272cc70bSAndy Fleming 		if (err)
927272cc70bSAndy Fleming 			return err;
928d52ebf10SThomas Chou 	}
929272cc70bSAndy Fleming 
930e6f99a56SLei Wen 	/*
931e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
932e6f99a56SLei Wen 	 */
933e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
934bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
935d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
936d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
937d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
938fdbb873eSKim Phillips 		if (!err && (ext_csd[EXT_CSD_REV] >= 2)) {
939639b7827SYoshihiro Shimoda 			/*
940639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
941639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
942639b7827SYoshihiro Shimoda 			 * than 2GB
943639b7827SYoshihiro Shimoda 			 */
9440560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
9450560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
9460560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
9470560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
9488bfa195eSSimon Glass 			capacity *= MMC_MAX_BLOCK_LEN;
949b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
950f866a46dSStephen Warren 				mmc->capacity_user = capacity;
951d23e2c09SSukumar Ghorai 		}
952bc897b1dSLei Wen 
95364f4a619SJaehoon Chung 		switch (ext_csd[EXT_CSD_REV]) {
95464f4a619SJaehoon Chung 		case 1:
95564f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_1;
95664f4a619SJaehoon Chung 			break;
95764f4a619SJaehoon Chung 		case 2:
95864f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_2;
95964f4a619SJaehoon Chung 			break;
96064f4a619SJaehoon Chung 		case 3:
96164f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_3;
96264f4a619SJaehoon Chung 			break;
96364f4a619SJaehoon Chung 		case 5:
96464f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_41;
96564f4a619SJaehoon Chung 			break;
96664f4a619SJaehoon Chung 		case 6:
96764f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_5;
96864f4a619SJaehoon Chung 			break;
96964f4a619SJaehoon Chung 		}
97064f4a619SJaehoon Chung 
971e6f99a56SLei Wen 		/*
9721937e5aaSOliver Metz 		 * Host needs to enable ERASE_GRP_DEF bit if device is
9731937e5aaSOliver Metz 		 * partitioned. This bit will be lost every time after a reset
9741937e5aaSOliver Metz 		 * or power off. This will affect erase size.
975e6f99a56SLei Wen 		 */
9761937e5aaSOliver Metz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
9771937e5aaSOliver Metz 		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) {
9781937e5aaSOliver Metz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
9791937e5aaSOliver Metz 				EXT_CSD_ERASE_GROUP_DEF, 1);
9801937e5aaSOliver Metz 
9811937e5aaSOliver Metz 			if (err)
9821937e5aaSOliver Metz 				return err;
9831937e5aaSOliver Metz 
9841937e5aaSOliver Metz 			/* Read out group size from ext_csd */
9850560db18SLei Wen 			mmc->erase_grp_size =
9868bfa195eSSimon Glass 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] *
9878bfa195eSSimon Glass 					MMC_MAX_BLOCK_LEN * 1024;
9888bfa195eSSimon Glass 		} else {
9891937e5aaSOliver Metz 			/* Calculate the group size from the csd value. */
990e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
991e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
992e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
993e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
994e6f99a56SLei Wen 				* (erase_gmul + 1);
995e6f99a56SLei Wen 		}
996e6f99a56SLei Wen 
997bc897b1dSLei Wen 		/* store the partition info of emmc */
9988948ea83SStephen Warren 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
9998948ea83SStephen Warren 		    ext_csd[EXT_CSD_BOOT_MULT])
10000560db18SLei Wen 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
1001f866a46dSStephen Warren 
1002f866a46dSStephen Warren 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
1003f866a46dSStephen Warren 
1004f866a46dSStephen Warren 		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
1005f866a46dSStephen Warren 
1006f866a46dSStephen Warren 		for (i = 0; i < 4; i++) {
1007f866a46dSStephen Warren 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
1008f866a46dSStephen Warren 			mmc->capacity_gp[i] = (ext_csd[idx + 2] << 16) +
1009f866a46dSStephen Warren 				(ext_csd[idx + 1] << 8) + ext_csd[idx];
1010f866a46dSStephen Warren 			mmc->capacity_gp[i] *=
1011f866a46dSStephen Warren 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1012f866a46dSStephen Warren 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1013d23e2c09SSukumar Ghorai 		}
1014f866a46dSStephen Warren 	}
1015f866a46dSStephen Warren 
1016f866a46dSStephen Warren 	err = mmc_set_capacity(mmc, mmc->part_num);
1017f866a46dSStephen Warren 	if (err)
1018f866a46dSStephen Warren 		return err;
1019d23e2c09SSukumar Ghorai 
1020272cc70bSAndy Fleming 	if (IS_SD(mmc))
1021272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1022272cc70bSAndy Fleming 	else
1023272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1024272cc70bSAndy Fleming 
1025272cc70bSAndy Fleming 	if (err)
1026272cc70bSAndy Fleming 		return err;
1027272cc70bSAndy Fleming 
1028272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
1029272cc70bSAndy Fleming 	mmc->card_caps &= mmc->host_caps;
1030272cc70bSAndy Fleming 
1031272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1032272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1033272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1034272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1035272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1036272cc70bSAndy Fleming 
1037272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1038272cc70bSAndy Fleming 			if (err)
1039272cc70bSAndy Fleming 				return err;
1040272cc70bSAndy Fleming 
1041272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1042272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1043272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1044272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1045272cc70bSAndy Fleming 			if (err)
1046272cc70bSAndy Fleming 				return err;
1047272cc70bSAndy Fleming 
1048272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1049272cc70bSAndy Fleming 		}
1050272cc70bSAndy Fleming 
1051272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
1052ad5fd922SJaehoon Chung 			mmc->tran_speed = 50000000;
1053272cc70bSAndy Fleming 		else
1054ad5fd922SJaehoon Chung 			mmc->tran_speed = 25000000;
1055272cc70bSAndy Fleming 	} else {
10567798f6dbSAndy Fleming 		int idx;
10577798f6dbSAndy Fleming 
10587798f6dbSAndy Fleming 		/* An array of possible bus widths in order of preference */
10597798f6dbSAndy Fleming 		static unsigned ext_csd_bits[] = {
10607798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_8,
10617798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_4,
10627798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_1,
10637798f6dbSAndy Fleming 		};
10647798f6dbSAndy Fleming 
10657798f6dbSAndy Fleming 		/* An array to map CSD bus widths to host cap bits */
10667798f6dbSAndy Fleming 		static unsigned ext_to_hostcaps[] = {
10677798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
10687798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
10697798f6dbSAndy Fleming 		};
10707798f6dbSAndy Fleming 
10717798f6dbSAndy Fleming 		/* An array to map chosen bus width to an integer */
10727798f6dbSAndy Fleming 		static unsigned widths[] = {
10737798f6dbSAndy Fleming 			8, 4, 1,
10747798f6dbSAndy Fleming 		};
10757798f6dbSAndy Fleming 
10767798f6dbSAndy Fleming 		for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
10777798f6dbSAndy Fleming 			unsigned int extw = ext_csd_bits[idx];
10787798f6dbSAndy Fleming 
10797798f6dbSAndy Fleming 			/*
10807798f6dbSAndy Fleming 			 * Check to make sure the controller supports
10817798f6dbSAndy Fleming 			 * this bus width, if it's more than 1
10827798f6dbSAndy Fleming 			 */
10837798f6dbSAndy Fleming 			if (extw != EXT_CSD_BUS_WIDTH_1 &&
10847798f6dbSAndy Fleming 					!(mmc->host_caps & ext_to_hostcaps[extw]))
10857798f6dbSAndy Fleming 				continue;
10867798f6dbSAndy Fleming 
1087272cc70bSAndy Fleming 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
10887798f6dbSAndy Fleming 					EXT_CSD_BUS_WIDTH, extw);
1089272cc70bSAndy Fleming 
1090272cc70bSAndy Fleming 			if (err)
10914137894eSLei Wen 				continue;
1092272cc70bSAndy Fleming 
10937798f6dbSAndy Fleming 			mmc_set_bus_width(mmc, widths[idx]);
1094272cc70bSAndy Fleming 
10954137894eSLei Wen 			err = mmc_send_ext_csd(mmc, test_csd);
10964137894eSLei Wen 			if (!err && ext_csd[EXT_CSD_PARTITIONING_SUPPORT] \
10974137894eSLei Wen 				    == test_csd[EXT_CSD_PARTITIONING_SUPPORT]
10984137894eSLei Wen 				 && ext_csd[EXT_CSD_ERASE_GROUP_DEF] \
10994137894eSLei Wen 				    == test_csd[EXT_CSD_ERASE_GROUP_DEF] \
11004137894eSLei Wen 				 && ext_csd[EXT_CSD_REV] \
11014137894eSLei Wen 				    == test_csd[EXT_CSD_REV]
11024137894eSLei Wen 				 && ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] \
11034137894eSLei Wen 				    == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
11044137894eSLei Wen 				 && memcmp(&ext_csd[EXT_CSD_SEC_CNT], \
11054137894eSLei Wen 					&test_csd[EXT_CSD_SEC_CNT], 4) == 0) {
1106272cc70bSAndy Fleming 
11077798f6dbSAndy Fleming 				mmc->card_caps |= ext_to_hostcaps[extw];
11084137894eSLei Wen 				break;
11094137894eSLei Wen 			}
1110272cc70bSAndy Fleming 		}
1111272cc70bSAndy Fleming 
1112272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS) {
1113272cc70bSAndy Fleming 			if (mmc->card_caps & MMC_MODE_HS_52MHz)
1114ad5fd922SJaehoon Chung 				mmc->tran_speed = 52000000;
1115272cc70bSAndy Fleming 			else
1116ad5fd922SJaehoon Chung 				mmc->tran_speed = 26000000;
1117272cc70bSAndy Fleming 		}
1118ad5fd922SJaehoon Chung 	}
1119ad5fd922SJaehoon Chung 
1120ad5fd922SJaehoon Chung 	mmc_set_clock(mmc, mmc->tran_speed);
1121272cc70bSAndy Fleming 
1122272cc70bSAndy Fleming 	/* fill in device description */
1123272cc70bSAndy Fleming 	mmc->block_dev.lun = 0;
1124272cc70bSAndy Fleming 	mmc->block_dev.type = 0;
1125272cc70bSAndy Fleming 	mmc->block_dev.blksz = mmc->read_bl_len;
11260472fbfdSEgbert Eich 	mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz);
11279b1f942cSRabin Vincent 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
112856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1129babce5f6STaylor Hutt 	sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x",
1130babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1131babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1132babce5f6STaylor Hutt 	sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
11330b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1134babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1135babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1136babce5f6STaylor Hutt 	sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1137babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
113856196826SPaul Burton #else
113956196826SPaul Burton 	mmc->block_dev.vendor[0] = 0;
114056196826SPaul Burton 	mmc->block_dev.product[0] = 0;
114156196826SPaul Burton 	mmc->block_dev.revision[0] = 0;
114256196826SPaul Burton #endif
1143122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1144272cc70bSAndy Fleming 	init_part(&mmc->block_dev);
1145122efd43SMikhail Kshevetskiy #endif
1146272cc70bSAndy Fleming 
1147272cc70bSAndy Fleming 	return 0;
1148272cc70bSAndy Fleming }
1149272cc70bSAndy Fleming 
1150fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1151272cc70bSAndy Fleming {
1152272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1153272cc70bSAndy Fleming 	int err;
1154272cc70bSAndy Fleming 
1155272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1156272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
1157272cc70bSAndy Fleming 	cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa;
1158272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1159272cc70bSAndy Fleming 
1160272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1161272cc70bSAndy Fleming 
1162272cc70bSAndy Fleming 	if (err)
1163272cc70bSAndy Fleming 		return err;
1164272cc70bSAndy Fleming 
1165998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1166272cc70bSAndy Fleming 		return UNUSABLE_ERR;
1167272cc70bSAndy Fleming 	else
1168272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1169272cc70bSAndy Fleming 
1170272cc70bSAndy Fleming 	return 0;
1171272cc70bSAndy Fleming }
1172272cc70bSAndy Fleming 
1173272cc70bSAndy Fleming int mmc_register(struct mmc *mmc)
1174272cc70bSAndy Fleming {
1175ab71188cSMarkus Niebel 	/* Setup dsr related values */
1176ab71188cSMarkus Niebel 	mmc->dsr_imp = 0;
1177ab71188cSMarkus Niebel 	mmc->dsr = 0xffffffff;
1178272cc70bSAndy Fleming 	/* Setup the universal parts of the block interface just once */
1179272cc70bSAndy Fleming 	mmc->block_dev.if_type = IF_TYPE_MMC;
1180272cc70bSAndy Fleming 	mmc->block_dev.dev = cur_dev_num++;
1181272cc70bSAndy Fleming 	mmc->block_dev.removable = 1;
1182272cc70bSAndy Fleming 	mmc->block_dev.block_read = mmc_bread;
1183272cc70bSAndy Fleming 	mmc->block_dev.block_write = mmc_bwrite;
1184e6f99a56SLei Wen 	mmc->block_dev.block_erase = mmc_berase;
11858feafcc4SJohn Rigby 	if (!mmc->b_max)
11868feafcc4SJohn Rigby 		mmc->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
1187272cc70bSAndy Fleming 
1188272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc->link);
1189272cc70bSAndy Fleming 
1190272cc70bSAndy Fleming 	list_add_tail (&mmc->link, &mmc_devices);
1191272cc70bSAndy Fleming 
1192272cc70bSAndy Fleming 	return 0;
1193272cc70bSAndy Fleming }
1194272cc70bSAndy Fleming 
1195df3fc526SMatthew McClintock #ifdef CONFIG_PARTITIONS
1196272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev)
1197272cc70bSAndy Fleming {
1198272cc70bSAndy Fleming 	struct mmc *mmc = find_mmc_device(dev);
11996bb4b4bcSBenoît Thébaudeau 	if (!mmc || mmc_init(mmc))
120040242bc3SŁukasz Majewski 		return NULL;
1201272cc70bSAndy Fleming 
120240242bc3SŁukasz Majewski 	return &mmc->block_dev;
1203272cc70bSAndy Fleming }
1204df3fc526SMatthew McClintock #endif
1205272cc70bSAndy Fleming 
1206e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1207272cc70bSAndy Fleming {
1208afd5932bSMacpaul Lin 	int err;
1209272cc70bSAndy Fleming 
121048972d90SThierry Reding 	if (mmc_getcd(mmc) == 0) {
121148972d90SThierry Reding 		mmc->has_init = 0;
121256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
121348972d90SThierry Reding 		printf("MMC: no card present\n");
121456196826SPaul Burton #endif
121548972d90SThierry Reding 		return NO_CARD_ERR;
121648972d90SThierry Reding 	}
121748972d90SThierry Reding 
1218bc897b1dSLei Wen 	if (mmc->has_init)
1219bc897b1dSLei Wen 		return 0;
1220bc897b1dSLei Wen 
1221272cc70bSAndy Fleming 	err = mmc->init(mmc);
1222272cc70bSAndy Fleming 
1223272cc70bSAndy Fleming 	if (err)
1224272cc70bSAndy Fleming 		return err;
1225272cc70bSAndy Fleming 
1226b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1227b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1228b86b85e2SIlya Yanok 
1229272cc70bSAndy Fleming 	/* Reset the Card */
1230272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1231272cc70bSAndy Fleming 
1232272cc70bSAndy Fleming 	if (err)
1233272cc70bSAndy Fleming 		return err;
1234272cc70bSAndy Fleming 
1235bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1236bc897b1dSLei Wen 	mmc->part_num = 0;
1237bc897b1dSLei Wen 
1238272cc70bSAndy Fleming 	/* Test for SD version 2 */
1239272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1240272cc70bSAndy Fleming 
1241272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1242272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1243272cc70bSAndy Fleming 
1244272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1245272cc70bSAndy Fleming 	if (err == TIMEOUT) {
1246272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1247272cc70bSAndy Fleming 
1248e9550449SChe-Liang Chiou 		if (err && err != IN_PROGRESS) {
124956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1250272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
125156196826SPaul Burton #endif
1252272cc70bSAndy Fleming 			return UNUSABLE_ERR;
1253272cc70bSAndy Fleming 		}
1254272cc70bSAndy Fleming 	}
1255272cc70bSAndy Fleming 
1256e9550449SChe-Liang Chiou 	if (err == IN_PROGRESS)
1257e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
1258e9550449SChe-Liang Chiou 
1259e9550449SChe-Liang Chiou 	return err;
1260e9550449SChe-Liang Chiou }
1261e9550449SChe-Liang Chiou 
1262e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
1263e9550449SChe-Liang Chiou {
1264e9550449SChe-Liang Chiou 	int err = 0;
1265e9550449SChe-Liang Chiou 
1266e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
1267e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
1268e9550449SChe-Liang Chiou 
1269e9550449SChe-Liang Chiou 	if (!err)
1270bc897b1dSLei Wen 		err = mmc_startup(mmc);
1271bc897b1dSLei Wen 	if (err)
1272bc897b1dSLei Wen 		mmc->has_init = 0;
1273bc897b1dSLei Wen 	else
1274bc897b1dSLei Wen 		mmc->has_init = 1;
1275e9550449SChe-Liang Chiou 	mmc->init_in_progress = 0;
1276e9550449SChe-Liang Chiou 	return err;
1277e9550449SChe-Liang Chiou }
1278e9550449SChe-Liang Chiou 
1279e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
1280e9550449SChe-Liang Chiou {
1281e9550449SChe-Liang Chiou 	int err = IN_PROGRESS;
1282e9550449SChe-Liang Chiou 	unsigned start = get_timer(0);
1283e9550449SChe-Liang Chiou 
1284e9550449SChe-Liang Chiou 	if (mmc->has_init)
1285e9550449SChe-Liang Chiou 		return 0;
1286e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
1287e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
1288e9550449SChe-Liang Chiou 
1289e9550449SChe-Liang Chiou 	if (!err || err == IN_PROGRESS)
1290e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
1291e9550449SChe-Liang Chiou 	debug("%s: %d, time %lu\n", __func__, err, get_timer(start));
1292bc897b1dSLei Wen 	return err;
1293272cc70bSAndy Fleming }
1294272cc70bSAndy Fleming 
1295ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
1296ab71188cSMarkus Niebel {
1297ab71188cSMarkus Niebel 	mmc->dsr = val;
1298ab71188cSMarkus Niebel 	return 0;
1299ab71188cSMarkus Niebel }
1300ab71188cSMarkus Niebel 
1301272cc70bSAndy Fleming /*
1302272cc70bSAndy Fleming  * CPU and board-specific MMC initializations.  Aliased function
1303272cc70bSAndy Fleming  * signals caller to move on
1304272cc70bSAndy Fleming  */
1305272cc70bSAndy Fleming static int __def_mmc_init(bd_t *bis)
1306272cc70bSAndy Fleming {
1307272cc70bSAndy Fleming 	return -1;
1308272cc70bSAndy Fleming }
1309272cc70bSAndy Fleming 
1310f9a109b3SPeter Tyser int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
1311f9a109b3SPeter Tyser int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
1312272cc70bSAndy Fleming 
131356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
131456196826SPaul Burton 
1315272cc70bSAndy Fleming void print_mmc_devices(char separator)
1316272cc70bSAndy Fleming {
1317272cc70bSAndy Fleming 	struct mmc *m;
1318272cc70bSAndy Fleming 	struct list_head *entry;
1319272cc70bSAndy Fleming 
1320272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
1321272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
1322272cc70bSAndy Fleming 
1323272cc70bSAndy Fleming 		printf("%s: %d", m->name, m->block_dev.dev);
1324272cc70bSAndy Fleming 
1325272cc70bSAndy Fleming 		if (entry->next != &mmc_devices)
1326272cc70bSAndy Fleming 			printf("%c ", separator);
1327272cc70bSAndy Fleming 	}
1328272cc70bSAndy Fleming 
1329272cc70bSAndy Fleming 	printf("\n");
1330272cc70bSAndy Fleming }
1331272cc70bSAndy Fleming 
133256196826SPaul Burton #else
133356196826SPaul Burton void print_mmc_devices(char separator) { }
133456196826SPaul Burton #endif
133556196826SPaul Burton 
1336ea6ebe21SLei Wen int get_mmc_num(void)
1337ea6ebe21SLei Wen {
1338ea6ebe21SLei Wen 	return cur_dev_num;
1339ea6ebe21SLei Wen }
1340ea6ebe21SLei Wen 
1341e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
1342e9550449SChe-Liang Chiou {
1343e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
1344e9550449SChe-Liang Chiou }
1345e9550449SChe-Liang Chiou 
1346e9550449SChe-Liang Chiou static void do_preinit(void)
1347e9550449SChe-Liang Chiou {
1348e9550449SChe-Liang Chiou 	struct mmc *m;
1349e9550449SChe-Liang Chiou 	struct list_head *entry;
1350e9550449SChe-Liang Chiou 
1351e9550449SChe-Liang Chiou 	list_for_each(entry, &mmc_devices) {
1352e9550449SChe-Liang Chiou 		m = list_entry(entry, struct mmc, link);
1353e9550449SChe-Liang Chiou 
1354e9550449SChe-Liang Chiou 		if (m->preinit)
1355e9550449SChe-Liang Chiou 			mmc_start_init(m);
1356e9550449SChe-Liang Chiou 	}
1357e9550449SChe-Liang Chiou }
1358e9550449SChe-Liang Chiou 
1359e9550449SChe-Liang Chiou 
1360272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1361272cc70bSAndy Fleming {
1362272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc_devices);
1363272cc70bSAndy Fleming 	cur_dev_num = 0;
1364272cc70bSAndy Fleming 
1365272cc70bSAndy Fleming 	if (board_mmc_init(bis) < 0)
1366272cc70bSAndy Fleming 		cpu_mmc_init(bis);
1367272cc70bSAndy Fleming 
1368bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
1369272cc70bSAndy Fleming 	print_mmc_devices(',');
1370bb0dc108SYing Zhang #endif
1371272cc70bSAndy Fleming 
1372e9550449SChe-Liang Chiou 	do_preinit();
1373272cc70bSAndy Fleming 	return 0;
1374272cc70bSAndy Fleming }
13753690d6d6SAmar 
13763690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT
13773690d6d6SAmar /*
13783690d6d6SAmar  * This function changes the size of boot partition and the size of rpmb
13793690d6d6SAmar  * partition present on EMMC devices.
13803690d6d6SAmar  *
13813690d6d6SAmar  * Input Parameters:
13823690d6d6SAmar  * struct *mmc: pointer for the mmc device strcuture
13833690d6d6SAmar  * bootsize: size of boot partition
13843690d6d6SAmar  * rpmbsize: size of rpmb partition
13853690d6d6SAmar  *
13863690d6d6SAmar  * Returns 0 on success.
13873690d6d6SAmar  */
13883690d6d6SAmar 
13893690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
13903690d6d6SAmar 				unsigned long rpmbsize)
13913690d6d6SAmar {
13923690d6d6SAmar 	int err;
13933690d6d6SAmar 	struct mmc_cmd cmd;
13943690d6d6SAmar 
13953690d6d6SAmar 	/* Only use this command for raw EMMC moviNAND. Enter backdoor mode */
13963690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
13973690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
13983690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG1;
13993690d6d6SAmar 
14003690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
14013690d6d6SAmar 	if (err) {
14023690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error1 = %d\n", err);
14033690d6d6SAmar 		return err;
14043690d6d6SAmar 	}
14053690d6d6SAmar 
14063690d6d6SAmar 	/* Boot partition changing mode */
14073690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
14083690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
14093690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG2;
14103690d6d6SAmar 
14113690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
14123690d6d6SAmar 	if (err) {
14133690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error2 = %d\n", err);
14143690d6d6SAmar 		return err;
14153690d6d6SAmar 	}
14163690d6d6SAmar 	/* boot partition size is multiple of 128KB */
14173690d6d6SAmar 	bootsize = (bootsize * 1024) / 128;
14183690d6d6SAmar 
14193690d6d6SAmar 	/* Arg: boot partition size */
14203690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
14213690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
14223690d6d6SAmar 	cmd.cmdarg = bootsize;
14233690d6d6SAmar 
14243690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
14253690d6d6SAmar 	if (err) {
14263690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error3 = %d\n", err);
14273690d6d6SAmar 		return err;
14283690d6d6SAmar 	}
14293690d6d6SAmar 	/* RPMB partition size is multiple of 128KB */
14303690d6d6SAmar 	rpmbsize = (rpmbsize * 1024) / 128;
14313690d6d6SAmar 	/* Arg: RPMB partition size */
14323690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
14333690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
14343690d6d6SAmar 	cmd.cmdarg = rpmbsize;
14353690d6d6SAmar 
14363690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
14373690d6d6SAmar 	if (err) {
14383690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error4 = %d\n", err);
14393690d6d6SAmar 		return err;
14403690d6d6SAmar 	}
14413690d6d6SAmar 	return 0;
14423690d6d6SAmar }
14433690d6d6SAmar 
14443690d6d6SAmar /*
14453690d6d6SAmar  * This function shall form and send the commands to open / close the
14463690d6d6SAmar  * boot partition specified by user.
14473690d6d6SAmar  *
14483690d6d6SAmar  * Input Parameters:
14493690d6d6SAmar  * ack: 0x0 - No boot acknowledge sent (default)
14503690d6d6SAmar  *	0x1 - Boot acknowledge sent during boot operation
14513690d6d6SAmar  * part_num: User selects boot data that will be sent to master
14523690d6d6SAmar  *	0x0 - Device not boot enabled (default)
14533690d6d6SAmar  *	0x1 - Boot partition 1 enabled for boot
14543690d6d6SAmar  *	0x2 - Boot partition 2 enabled for boot
14553690d6d6SAmar  * access: User selects partitions to access
14563690d6d6SAmar  *	0x0 : No access to boot partition (default)
14573690d6d6SAmar  *	0x1 : R/W boot partition 1
14583690d6d6SAmar  *	0x2 : R/W boot partition 2
14593690d6d6SAmar  *	0x3 : R/W Replay Protected Memory Block (RPMB)
14603690d6d6SAmar  *
14613690d6d6SAmar  * Returns 0 on success.
14623690d6d6SAmar  */
14633690d6d6SAmar int mmc_boot_part_access(struct mmc *mmc, u8 ack, u8 part_num, u8 access)
14643690d6d6SAmar {
14653690d6d6SAmar 	int err;
14663690d6d6SAmar 	struct mmc_cmd cmd;
14673690d6d6SAmar 
14683690d6d6SAmar 	/* Boot ack enable, boot partition enable , boot partition access */
14693690d6d6SAmar 	cmd.cmdidx = MMC_CMD_SWITCH;
14703690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
14713690d6d6SAmar 
14723690d6d6SAmar 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
14733690d6d6SAmar 			(EXT_CSD_PART_CONF << 16) |
14743690d6d6SAmar 			((EXT_CSD_BOOT_ACK(ack) |
14753690d6d6SAmar 			EXT_CSD_BOOT_PART_NUM(part_num) |
14763690d6d6SAmar 			EXT_CSD_PARTITION_ACCESS(access)) << 8);
14773690d6d6SAmar 
14783690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
14793690d6d6SAmar 	if (err) {
14803690d6d6SAmar 		if (access) {
14813690d6d6SAmar 			debug("mmc boot partition#%d open fail:Error1 = %d\n",
14823690d6d6SAmar 			      part_num, err);
14833690d6d6SAmar 		} else {
14843690d6d6SAmar 			debug("mmc boot partition#%d close fail:Error = %d\n",
14853690d6d6SAmar 			      part_num, err);
14863690d6d6SAmar 		}
14873690d6d6SAmar 		return err;
14883690d6d6SAmar 	}
14893690d6d6SAmar 
14903690d6d6SAmar 	if (access) {
14913690d6d6SAmar 		/* 4bit transfer mode at booting time. */
14923690d6d6SAmar 		cmd.cmdidx = MMC_CMD_SWITCH;
14933690d6d6SAmar 		cmd.resp_type = MMC_RSP_R1b;
14943690d6d6SAmar 
14953690d6d6SAmar 		cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
14963690d6d6SAmar 				(EXT_CSD_BOOT_BUS_WIDTH << 16) |
14973690d6d6SAmar 				((1 << 0) << 8);
14983690d6d6SAmar 
14993690d6d6SAmar 		err = mmc_send_cmd(mmc, &cmd, NULL);
15003690d6d6SAmar 		if (err) {
15013690d6d6SAmar 			debug("mmc boot partition#%d open fail:Error2 = %d\n",
15023690d6d6SAmar 			      part_num, err);
15033690d6d6SAmar 			return err;
15043690d6d6SAmar 		}
15053690d6d6SAmar 	}
15063690d6d6SAmar 	return 0;
15073690d6d6SAmar }
1508792970b0STom Rini 
1509792970b0STom Rini /*
1510*5a99b9deSTom Rini  * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH
1511*5a99b9deSTom Rini  * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH
1512*5a99b9deSTom Rini  * and BOOT_MODE.
1513*5a99b9deSTom Rini  *
1514*5a99b9deSTom Rini  * Returns 0 on success.
1515*5a99b9deSTom Rini  */
1516*5a99b9deSTom Rini int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode)
1517*5a99b9deSTom Rini {
1518*5a99b9deSTom Rini 	int err;
1519*5a99b9deSTom Rini 
1520*5a99b9deSTom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH,
1521*5a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) |
1522*5a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) |
1523*5a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width));
1524*5a99b9deSTom Rini 
1525*5a99b9deSTom Rini 	if (err)
1526*5a99b9deSTom Rini 		return err;
1527*5a99b9deSTom Rini 	return 0;
1528*5a99b9deSTom Rini }
1529*5a99b9deSTom Rini 
1530*5a99b9deSTom Rini /*
1531792970b0STom Rini  * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG)
1532792970b0STom Rini  * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and
1533792970b0STom Rini  * PARTITION_ACCESS.
1534792970b0STom Rini  *
1535792970b0STom Rini  * Returns 0 on success.
1536792970b0STom Rini  */
1537792970b0STom Rini int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access)
1538792970b0STom Rini {
1539792970b0STom Rini 	int err;
1540792970b0STom Rini 
1541792970b0STom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
1542792970b0STom Rini 			 EXT_CSD_BOOT_ACK(ack) |
1543792970b0STom Rini 			 EXT_CSD_BOOT_PART_NUM(part_num) |
1544792970b0STom Rini 			 EXT_CSD_PARTITION_ACCESS(access));
1545792970b0STom Rini 
1546792970b0STom Rini 	if (err)
1547792970b0STom Rini 		return err;
1548792970b0STom Rini 	return 0;
1549792970b0STom Rini }
15503690d6d6SAmar #endif
1551