xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision d803fea5)
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 
20272cc70bSAndy Fleming static struct list_head mmc_devices;
21272cc70bSAndy Fleming static int cur_dev_num = -1;
22272cc70bSAndy Fleming 
23d23d8d7eSNikita Kiryanov int __weak board_mmc_getwp(struct mmc *mmc)
24d23d8d7eSNikita Kiryanov {
25d23d8d7eSNikita Kiryanov 	return -1;
26d23d8d7eSNikita Kiryanov }
27d23d8d7eSNikita Kiryanov 
28d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
29d23d8d7eSNikita Kiryanov {
30d23d8d7eSNikita Kiryanov 	int wp;
31d23d8d7eSNikita Kiryanov 
32d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
33d23d8d7eSNikita Kiryanov 
34d4e1da4eSPeter Korsgaard 	if (wp < 0) {
3593bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
3693bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
37d4e1da4eSPeter Korsgaard 		else
38d4e1da4eSPeter Korsgaard 			wp = 0;
39d4e1da4eSPeter Korsgaard 	}
40d23d8d7eSNikita Kiryanov 
41d23d8d7eSNikita Kiryanov 	return wp;
42d23d8d7eSNikita Kiryanov }
43d23d8d7eSNikita Kiryanov 
44314284b1SThierry Reding int __board_mmc_getcd(struct mmc *mmc) {
4511fdade2SStefano Babic 	return -1;
4611fdade2SStefano Babic }
4711fdade2SStefano Babic 
48314284b1SThierry Reding int board_mmc_getcd(struct mmc *mmc)__attribute__((weak,
4911fdade2SStefano Babic 	alias("__board_mmc_getcd")));
5011fdade2SStefano Babic 
51da61fa5fSPaul Burton int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
52272cc70bSAndy Fleming {
535db2fe3aSRaffaele Recalcati 	int ret;
548635ff9eSMarek Vasut 
558635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
565db2fe3aSRaffaele Recalcati 	int i;
575db2fe3aSRaffaele Recalcati 	u8 *ptr;
585db2fe3aSRaffaele Recalcati 
595db2fe3aSRaffaele Recalcati 	printf("CMD_SEND:%d\n", cmd->cmdidx);
605db2fe3aSRaffaele Recalcati 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
6193bfd616SPantelis Antoniou 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
625db2fe3aSRaffaele Recalcati 	switch (cmd->resp_type) {
635db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
645db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
655db2fe3aSRaffaele Recalcati 			break;
665db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
675db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
685db2fe3aSRaffaele Recalcati 				cmd->response[0]);
695db2fe3aSRaffaele Recalcati 			break;
705db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
715db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
725db2fe3aSRaffaele Recalcati 				cmd->response[0]);
735db2fe3aSRaffaele Recalcati 			break;
745db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
755db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
765db2fe3aSRaffaele Recalcati 				cmd->response[0]);
775db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
785db2fe3aSRaffaele Recalcati 				cmd->response[1]);
795db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
805db2fe3aSRaffaele Recalcati 				cmd->response[2]);
815db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
825db2fe3aSRaffaele Recalcati 				cmd->response[3]);
835db2fe3aSRaffaele Recalcati 			printf("\n");
845db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
855db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
865db2fe3aSRaffaele Recalcati 				int j;
875db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
88146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
895db2fe3aSRaffaele Recalcati 				ptr += 3;
905db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
915db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
925db2fe3aSRaffaele Recalcati 				printf("\n");
935db2fe3aSRaffaele Recalcati 			}
945db2fe3aSRaffaele Recalcati 			break;
955db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
965db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
975db2fe3aSRaffaele Recalcati 				cmd->response[0]);
985db2fe3aSRaffaele Recalcati 			break;
995db2fe3aSRaffaele Recalcati 		default:
1005db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1015db2fe3aSRaffaele Recalcati 			break;
1025db2fe3aSRaffaele Recalcati 	}
1035db2fe3aSRaffaele Recalcati #else
10493bfd616SPantelis Antoniou 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
1055db2fe3aSRaffaele Recalcati #endif
1068635ff9eSMarek Vasut 	return ret;
107272cc70bSAndy Fleming }
108272cc70bSAndy Fleming 
109da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
1105d4fc8d9SRaffaele Recalcati {
1115d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
112d617c426SJan Kloetzke 	int err, retries = 5;
1135d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
1145d4fc8d9SRaffaele Recalcati 	int status;
1155d4fc8d9SRaffaele Recalcati #endif
1165d4fc8d9SRaffaele Recalcati 
1175d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
1185d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
119aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
120aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
1215d4fc8d9SRaffaele Recalcati 
1225d4fc8d9SRaffaele Recalcati 	do {
1235d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
124d617c426SJan Kloetzke 		if (!err) {
125d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
126d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
127d617c426SJan Kloetzke 			     MMC_STATE_PRG)
1285d4fc8d9SRaffaele Recalcati 				break;
129d617c426SJan Kloetzke 			else if (cmd.response[0] & MMC_STATUS_MASK) {
13056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
131d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
132d617c426SJan Kloetzke 					cmd.response[0]);
13356196826SPaul Burton #endif
134d617c426SJan Kloetzke 				return COMM_ERR;
135d617c426SJan Kloetzke 			}
136d617c426SJan Kloetzke 		} else if (--retries < 0)
137d617c426SJan Kloetzke 			return err;
1385d4fc8d9SRaffaele Recalcati 
1395d4fc8d9SRaffaele Recalcati 		udelay(1000);
1405d4fc8d9SRaffaele Recalcati 
1415d4fc8d9SRaffaele Recalcati 	} while (timeout--);
1425d4fc8d9SRaffaele Recalcati 
1435db2fe3aSRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
1445db2fe3aSRaffaele Recalcati 	status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9;
1455db2fe3aSRaffaele Recalcati 	printf("CURR STATE:%d\n", status);
1465db2fe3aSRaffaele Recalcati #endif
1475b0c942fSJongman Heo 	if (timeout <= 0) {
14856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1495d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
15056196826SPaul Burton #endif
1515d4fc8d9SRaffaele Recalcati 		return TIMEOUT;
1525d4fc8d9SRaffaele Recalcati 	}
1535d4fc8d9SRaffaele Recalcati 
1545d4fc8d9SRaffaele Recalcati 	return 0;
1555d4fc8d9SRaffaele Recalcati }
1565d4fc8d9SRaffaele Recalcati 
157da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
158272cc70bSAndy Fleming {
159272cc70bSAndy Fleming 	struct mmc_cmd cmd;
160272cc70bSAndy Fleming 
161272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
162272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
163272cc70bSAndy Fleming 	cmd.cmdarg = len;
164272cc70bSAndy Fleming 
165272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
166272cc70bSAndy Fleming }
167272cc70bSAndy Fleming 
168272cc70bSAndy Fleming struct mmc *find_mmc_device(int dev_num)
169272cc70bSAndy Fleming {
170272cc70bSAndy Fleming 	struct mmc *m;
171272cc70bSAndy Fleming 	struct list_head *entry;
172272cc70bSAndy Fleming 
173272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
174272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
175272cc70bSAndy Fleming 
176272cc70bSAndy Fleming 		if (m->block_dev.dev == dev_num)
177272cc70bSAndy Fleming 			return m;
178272cc70bSAndy Fleming 	}
179272cc70bSAndy Fleming 
18056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
181272cc70bSAndy Fleming 	printf("MMC Device %d not found\n", dev_num);
18256196826SPaul Burton #endif
183272cc70bSAndy Fleming 
184272cc70bSAndy Fleming 	return NULL;
185272cc70bSAndy Fleming }
186272cc70bSAndy Fleming 
187ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
188fdbb873eSKim Phillips 			   lbaint_t blkcnt)
189272cc70bSAndy Fleming {
190272cc70bSAndy Fleming 	struct mmc_cmd cmd;
191272cc70bSAndy Fleming 	struct mmc_data data;
192272cc70bSAndy Fleming 
1934a1a06bcSAlagu Sankar 	if (blkcnt > 1)
1944a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
1954a1a06bcSAlagu Sankar 	else
196272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
197272cc70bSAndy Fleming 
198272cc70bSAndy Fleming 	if (mmc->high_capacity)
1994a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
200272cc70bSAndy Fleming 	else
2014a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
202272cc70bSAndy Fleming 
203272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
204272cc70bSAndy Fleming 
205272cc70bSAndy Fleming 	data.dest = dst;
2064a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
207272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
208272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
209272cc70bSAndy Fleming 
2104a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
2114a1a06bcSAlagu Sankar 		return 0;
2124a1a06bcSAlagu Sankar 
2134a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
2144a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
2154a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
2164a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
2174a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
21856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2194a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
22056196826SPaul Burton #endif
2214a1a06bcSAlagu Sankar 			return 0;
2224a1a06bcSAlagu Sankar 		}
223272cc70bSAndy Fleming 	}
224272cc70bSAndy Fleming 
2254a1a06bcSAlagu Sankar 	return blkcnt;
226272cc70bSAndy Fleming }
227272cc70bSAndy Fleming 
228ff8fef56SSascha Silbe static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst)
229272cc70bSAndy Fleming {
2304a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
231272cc70bSAndy Fleming 
2324a1a06bcSAlagu Sankar 	if (blkcnt == 0)
2334a1a06bcSAlagu Sankar 		return 0;
2344a1a06bcSAlagu Sankar 
2354a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
236272cc70bSAndy Fleming 	if (!mmc)
237272cc70bSAndy Fleming 		return 0;
238272cc70bSAndy Fleming 
239d2bf29e3SLei Wen 	if ((start + blkcnt) > mmc->block_dev.lba) {
24056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
241ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
242d2bf29e3SLei Wen 			start + blkcnt, mmc->block_dev.lba);
24356196826SPaul Burton #endif
244d2bf29e3SLei Wen 		return 0;
245d2bf29e3SLei Wen 	}
246272cc70bSAndy Fleming 
2474a1a06bcSAlagu Sankar 	if (mmc_set_blocklen(mmc, mmc->read_bl_len))
248272cc70bSAndy Fleming 		return 0;
249272cc70bSAndy Fleming 
2504a1a06bcSAlagu Sankar 	do {
25193bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
25293bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
2534a1a06bcSAlagu Sankar 		if(mmc_read_blocks(mmc, dst, start, cur) != cur)
2544a1a06bcSAlagu Sankar 			return 0;
2554a1a06bcSAlagu Sankar 		blocks_todo -= cur;
2564a1a06bcSAlagu Sankar 		start += cur;
2574a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
2584a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
259272cc70bSAndy Fleming 
260272cc70bSAndy Fleming 	return blkcnt;
261272cc70bSAndy Fleming }
262272cc70bSAndy Fleming 
263fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
264272cc70bSAndy Fleming {
265272cc70bSAndy Fleming 	struct mmc_cmd cmd;
266272cc70bSAndy Fleming 	int err;
267272cc70bSAndy Fleming 
268272cc70bSAndy Fleming 	udelay(1000);
269272cc70bSAndy Fleming 
270272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
271272cc70bSAndy Fleming 	cmd.cmdarg = 0;
272272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
273272cc70bSAndy Fleming 
274272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
275272cc70bSAndy Fleming 
276272cc70bSAndy Fleming 	if (err)
277272cc70bSAndy Fleming 		return err;
278272cc70bSAndy Fleming 
279272cc70bSAndy Fleming 	udelay(2000);
280272cc70bSAndy Fleming 
281272cc70bSAndy Fleming 	return 0;
282272cc70bSAndy Fleming }
283272cc70bSAndy Fleming 
284fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
285272cc70bSAndy Fleming {
286272cc70bSAndy Fleming 	int timeout = 1000;
287272cc70bSAndy Fleming 	int err;
288272cc70bSAndy Fleming 	struct mmc_cmd cmd;
289272cc70bSAndy Fleming 
290272cc70bSAndy Fleming 	do {
291272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
292272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
293272cc70bSAndy Fleming 		cmd.cmdarg = 0;
294272cc70bSAndy Fleming 
295272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
296272cc70bSAndy Fleming 
297272cc70bSAndy Fleming 		if (err)
298272cc70bSAndy Fleming 			return err;
299272cc70bSAndy Fleming 
300272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
301272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
302250de12bSStefano Babic 
303250de12bSStefano Babic 		/*
304250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
305250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
306250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
307250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
308250de12bSStefano Babic 		 * specified.
309250de12bSStefano Babic 		 */
310d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
31193bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
312272cc70bSAndy Fleming 
313272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
314272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
315272cc70bSAndy Fleming 
316272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
317272cc70bSAndy Fleming 
318272cc70bSAndy Fleming 		if (err)
319272cc70bSAndy Fleming 			return err;
320272cc70bSAndy Fleming 
321272cc70bSAndy Fleming 		udelay(1000);
322272cc70bSAndy Fleming 	} while ((!(cmd.response[0] & OCR_BUSY)) && timeout--);
323272cc70bSAndy Fleming 
324272cc70bSAndy Fleming 	if (timeout <= 0)
325272cc70bSAndy Fleming 		return UNUSABLE_ERR;
326272cc70bSAndy Fleming 
327272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
328272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
329272cc70bSAndy Fleming 
330d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
331d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
332d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
333d52ebf10SThomas Chou 		cmd.cmdarg = 0;
334d52ebf10SThomas Chou 
335d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
336d52ebf10SThomas Chou 
337d52ebf10SThomas Chou 		if (err)
338d52ebf10SThomas Chou 			return err;
339d52ebf10SThomas Chou 	}
340d52ebf10SThomas Chou 
341998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
342272cc70bSAndy Fleming 
343272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
344272cc70bSAndy Fleming 	mmc->rca = 0;
345272cc70bSAndy Fleming 
346272cc70bSAndy Fleming 	return 0;
347272cc70bSAndy Fleming }
348272cc70bSAndy Fleming 
349e9550449SChe-Liang Chiou /* We pass in the cmd since otherwise the init seems to fail */
350e9550449SChe-Liang Chiou static int mmc_send_op_cond_iter(struct mmc *mmc, struct mmc_cmd *cmd,
351e9550449SChe-Liang Chiou 		int use_arg)
352272cc70bSAndy Fleming {
353272cc70bSAndy Fleming 	int err;
354272cc70bSAndy Fleming 
355e9550449SChe-Liang Chiou 	cmd->cmdidx = MMC_CMD_SEND_OP_COND;
356e9550449SChe-Liang Chiou 	cmd->resp_type = MMC_RSP_R3;
357e9550449SChe-Liang Chiou 	cmd->cmdarg = 0;
358e9550449SChe-Liang Chiou 	if (use_arg && !mmc_host_is_spi(mmc)) {
359e9550449SChe-Liang Chiou 		cmd->cmdarg =
36093bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
361e9550449SChe-Liang Chiou 			(mmc->op_cond_response & OCR_VOLTAGE_MASK)) |
362e9550449SChe-Liang Chiou 			(mmc->op_cond_response & OCR_ACCESS_MODE);
363e9550449SChe-Liang Chiou 
36493bfd616SPantelis Antoniou 		if (mmc->cfg->host_caps & MMC_MODE_HC)
365e9550449SChe-Liang Chiou 			cmd->cmdarg |= OCR_HCS;
366e9550449SChe-Liang Chiou 	}
367e9550449SChe-Liang Chiou 	err = mmc_send_cmd(mmc, cmd, NULL);
368e9550449SChe-Liang Chiou 	if (err)
369e9550449SChe-Liang Chiou 		return err;
370e9550449SChe-Liang Chiou 	mmc->op_cond_response = cmd->response[0];
371e9550449SChe-Liang Chiou 	return 0;
372e9550449SChe-Liang Chiou }
373e9550449SChe-Liang Chiou 
374e9550449SChe-Liang Chiou int mmc_send_op_cond(struct mmc *mmc)
375e9550449SChe-Liang Chiou {
376e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
377e9550449SChe-Liang Chiou 	int err, i;
378e9550449SChe-Liang Chiou 
379272cc70bSAndy Fleming 	/* Some cards seem to need this */
380272cc70bSAndy Fleming 	mmc_go_idle(mmc);
381272cc70bSAndy Fleming 
38231cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
383e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 1;
384e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
385e9550449SChe-Liang Chiou 		err = mmc_send_op_cond_iter(mmc, &cmd, i != 0);
38631cacbabSRaffaele Recalcati 		if (err)
38731cacbabSRaffaele Recalcati 			return err;
38831cacbabSRaffaele Recalcati 
389e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
390e9550449SChe-Liang Chiou 		if (mmc->op_cond_response & OCR_BUSY)
391e9550449SChe-Liang Chiou 			return 0;
392e9550449SChe-Liang Chiou 	}
393e9550449SChe-Liang Chiou 	return IN_PROGRESS;
394e9550449SChe-Liang Chiou }
39531cacbabSRaffaele Recalcati 
396e9550449SChe-Liang Chiou int mmc_complete_op_cond(struct mmc *mmc)
397e9550449SChe-Liang Chiou {
398e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
399e9550449SChe-Liang Chiou 	int timeout = 1000;
400e9550449SChe-Liang Chiou 	uint start;
401e9550449SChe-Liang Chiou 	int err;
402e9550449SChe-Liang Chiou 
403e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
404e9550449SChe-Liang Chiou 	start = get_timer(0);
405272cc70bSAndy Fleming 	do {
406e9550449SChe-Liang Chiou 		err = mmc_send_op_cond_iter(mmc, &cmd, 1);
407272cc70bSAndy Fleming 		if (err)
408272cc70bSAndy Fleming 			return err;
409e9550449SChe-Liang Chiou 		if (get_timer(start) > timeout)
410272cc70bSAndy Fleming 			return UNUSABLE_ERR;
411e9550449SChe-Liang Chiou 		udelay(100);
412e9550449SChe-Liang Chiou 	} while (!(mmc->op_cond_response & OCR_BUSY));
413272cc70bSAndy Fleming 
414d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
415d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
416d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
417d52ebf10SThomas Chou 		cmd.cmdarg = 0;
418d52ebf10SThomas Chou 
419d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
420d52ebf10SThomas Chou 
421d52ebf10SThomas Chou 		if (err)
422d52ebf10SThomas Chou 			return err;
423d52ebf10SThomas Chou 	}
424d52ebf10SThomas Chou 
425272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
426998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
427272cc70bSAndy Fleming 
428272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
429def816a2SStephen Warren 	mmc->rca = 1;
430272cc70bSAndy Fleming 
431272cc70bSAndy Fleming 	return 0;
432272cc70bSAndy Fleming }
433272cc70bSAndy Fleming 
434272cc70bSAndy Fleming 
435fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
436272cc70bSAndy Fleming {
437272cc70bSAndy Fleming 	struct mmc_cmd cmd;
438272cc70bSAndy Fleming 	struct mmc_data data;
439272cc70bSAndy Fleming 	int err;
440272cc70bSAndy Fleming 
441272cc70bSAndy Fleming 	/* Get the Card Status Register */
442272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
443272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
444272cc70bSAndy Fleming 	cmd.cmdarg = 0;
445272cc70bSAndy Fleming 
446cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
447272cc70bSAndy Fleming 	data.blocks = 1;
4488bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
449272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
450272cc70bSAndy Fleming 
451272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
452272cc70bSAndy Fleming 
453272cc70bSAndy Fleming 	return err;
454272cc70bSAndy Fleming }
455272cc70bSAndy Fleming 
456272cc70bSAndy Fleming 
457fdbb873eSKim Phillips static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
458272cc70bSAndy Fleming {
459272cc70bSAndy Fleming 	struct mmc_cmd cmd;
4605d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
4615d4fc8d9SRaffaele Recalcati 	int ret;
462272cc70bSAndy Fleming 
463272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
464272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
465272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
466272cc70bSAndy Fleming 				 (index << 16) |
467272cc70bSAndy Fleming 				 (value << 8);
468272cc70bSAndy Fleming 
4695d4fc8d9SRaffaele Recalcati 	ret = mmc_send_cmd(mmc, &cmd, NULL);
4705d4fc8d9SRaffaele Recalcati 
4715d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
47293ad0d18SJan Kloetzke 	if (!ret)
47393ad0d18SJan Kloetzke 		ret = mmc_send_status(mmc, timeout);
4745d4fc8d9SRaffaele Recalcati 
4755d4fc8d9SRaffaele Recalcati 	return ret;
4765d4fc8d9SRaffaele Recalcati 
477272cc70bSAndy Fleming }
478272cc70bSAndy Fleming 
479fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
480272cc70bSAndy Fleming {
4818bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
482272cc70bSAndy Fleming 	char cardtype;
483272cc70bSAndy Fleming 	int err;
484272cc70bSAndy Fleming 
485272cc70bSAndy Fleming 	mmc->card_caps = 0;
486272cc70bSAndy Fleming 
487d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
488d52ebf10SThomas Chou 		return 0;
489d52ebf10SThomas Chou 
490272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
491272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
492272cc70bSAndy Fleming 		return 0;
493272cc70bSAndy Fleming 
494272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
495272cc70bSAndy Fleming 
496272cc70bSAndy Fleming 	if (err)
497272cc70bSAndy Fleming 		return err;
498272cc70bSAndy Fleming 
4990560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
500272cc70bSAndy Fleming 
501272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
502272cc70bSAndy Fleming 
503272cc70bSAndy Fleming 	if (err)
504272cc70bSAndy Fleming 		return err;
505272cc70bSAndy Fleming 
506272cc70bSAndy Fleming 	/* Now check to see that it worked */
507272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
508272cc70bSAndy Fleming 
509272cc70bSAndy Fleming 	if (err)
510272cc70bSAndy Fleming 		return err;
511272cc70bSAndy Fleming 
512272cc70bSAndy Fleming 	/* No high-speed support */
5130560db18SLei Wen 	if (!ext_csd[EXT_CSD_HS_TIMING])
514272cc70bSAndy Fleming 		return 0;
515272cc70bSAndy Fleming 
516272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
517272cc70bSAndy Fleming 	if (cardtype & MMC_HS_52MHZ)
518272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
519272cc70bSAndy Fleming 	else
520272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
521272cc70bSAndy Fleming 
522272cc70bSAndy Fleming 	return 0;
523272cc70bSAndy Fleming }
524272cc70bSAndy Fleming 
525f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
526f866a46dSStephen Warren {
527f866a46dSStephen Warren 	switch (part_num) {
528f866a46dSStephen Warren 	case 0:
529f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
530f866a46dSStephen Warren 		break;
531f866a46dSStephen Warren 	case 1:
532f866a46dSStephen Warren 	case 2:
533f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
534f866a46dSStephen Warren 		break;
535f866a46dSStephen Warren 	case 3:
536f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
537f866a46dSStephen Warren 		break;
538f866a46dSStephen Warren 	case 4:
539f866a46dSStephen Warren 	case 5:
540f866a46dSStephen Warren 	case 6:
541f866a46dSStephen Warren 	case 7:
542f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
543f866a46dSStephen Warren 		break;
544f866a46dSStephen Warren 	default:
545f866a46dSStephen Warren 		return -1;
546f866a46dSStephen Warren 	}
547f866a46dSStephen Warren 
548f866a46dSStephen Warren 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
549f866a46dSStephen Warren 
550f866a46dSStephen Warren 	return 0;
551f866a46dSStephen Warren }
552f866a46dSStephen Warren 
553bc897b1dSLei Wen int mmc_switch_part(int dev_num, unsigned int part_num)
554bc897b1dSLei Wen {
555bc897b1dSLei Wen 	struct mmc *mmc = find_mmc_device(dev_num);
556f866a46dSStephen Warren 	int ret;
557bc897b1dSLei Wen 
558bc897b1dSLei Wen 	if (!mmc)
559bc897b1dSLei Wen 		return -1;
560bc897b1dSLei Wen 
561f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
562bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
563bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
564f866a46dSStephen Warren 	if (ret)
565f866a46dSStephen Warren 		return ret;
566f866a46dSStephen Warren 
567f866a46dSStephen Warren 	return mmc_set_capacity(mmc, part_num);
568bc897b1dSLei Wen }
569bc897b1dSLei Wen 
57048972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
57148972d90SThierry Reding {
57248972d90SThierry Reding 	int cd;
57348972d90SThierry Reding 
57448972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
57548972d90SThierry Reding 
576d4e1da4eSPeter Korsgaard 	if (cd < 0) {
57793bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
57893bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
579d4e1da4eSPeter Korsgaard 		else
580d4e1da4eSPeter Korsgaard 			cd = 1;
581d4e1da4eSPeter Korsgaard 	}
58248972d90SThierry Reding 
58348972d90SThierry Reding 	return cd;
58448972d90SThierry Reding }
58548972d90SThierry Reding 
586fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
587272cc70bSAndy Fleming {
588272cc70bSAndy Fleming 	struct mmc_cmd cmd;
589272cc70bSAndy Fleming 	struct mmc_data data;
590272cc70bSAndy Fleming 
591272cc70bSAndy Fleming 	/* Switch the frequency */
592272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
593272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
594272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
595272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
596272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
597272cc70bSAndy Fleming 
598272cc70bSAndy Fleming 	data.dest = (char *)resp;
599272cc70bSAndy Fleming 	data.blocksize = 64;
600272cc70bSAndy Fleming 	data.blocks = 1;
601272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
602272cc70bSAndy Fleming 
603272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
604272cc70bSAndy Fleming }
605272cc70bSAndy Fleming 
606272cc70bSAndy Fleming 
607fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
608272cc70bSAndy Fleming {
609272cc70bSAndy Fleming 	int err;
610272cc70bSAndy Fleming 	struct mmc_cmd cmd;
611f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
612f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
613272cc70bSAndy Fleming 	struct mmc_data data;
614272cc70bSAndy Fleming 	int timeout;
615272cc70bSAndy Fleming 
616272cc70bSAndy Fleming 	mmc->card_caps = 0;
617272cc70bSAndy Fleming 
618d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
619d52ebf10SThomas Chou 		return 0;
620d52ebf10SThomas Chou 
621272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
622272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
623272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
624272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
625272cc70bSAndy Fleming 
626272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
627272cc70bSAndy Fleming 
628272cc70bSAndy Fleming 	if (err)
629272cc70bSAndy Fleming 		return err;
630272cc70bSAndy Fleming 
631272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
632272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
633272cc70bSAndy Fleming 	cmd.cmdarg = 0;
634272cc70bSAndy Fleming 
635272cc70bSAndy Fleming 	timeout = 3;
636272cc70bSAndy Fleming 
637272cc70bSAndy Fleming retry_scr:
638f781dd38SAnton staaf 	data.dest = (char *)scr;
639272cc70bSAndy Fleming 	data.blocksize = 8;
640272cc70bSAndy Fleming 	data.blocks = 1;
641272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
642272cc70bSAndy Fleming 
643272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
644272cc70bSAndy Fleming 
645272cc70bSAndy Fleming 	if (err) {
646272cc70bSAndy Fleming 		if (timeout--)
647272cc70bSAndy Fleming 			goto retry_scr;
648272cc70bSAndy Fleming 
649272cc70bSAndy Fleming 		return err;
650272cc70bSAndy Fleming 	}
651272cc70bSAndy Fleming 
6524e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
6534e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
654272cc70bSAndy Fleming 
655272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
656272cc70bSAndy Fleming 		case 0:
657272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
658272cc70bSAndy Fleming 			break;
659272cc70bSAndy Fleming 		case 1:
660272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_10;
661272cc70bSAndy Fleming 			break;
662272cc70bSAndy Fleming 		case 2:
663272cc70bSAndy Fleming 			mmc->version = SD_VERSION_2;
6641741c64dSJaehoon Chung 			if ((mmc->scr[0] >> 15) & 0x1)
6651741c64dSJaehoon Chung 				mmc->version = SD_VERSION_3;
666272cc70bSAndy Fleming 			break;
667272cc70bSAndy Fleming 		default:
668272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
669272cc70bSAndy Fleming 			break;
670272cc70bSAndy Fleming 	}
671272cc70bSAndy Fleming 
672b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
673b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
674b44c7083SAlagu Sankar 
675272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
676272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
677272cc70bSAndy Fleming 		return 0;
678272cc70bSAndy Fleming 
679272cc70bSAndy Fleming 	timeout = 4;
680272cc70bSAndy Fleming 	while (timeout--) {
681272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
682f781dd38SAnton staaf 				(u8 *)switch_status);
683272cc70bSAndy Fleming 
684272cc70bSAndy Fleming 		if (err)
685272cc70bSAndy Fleming 			return err;
686272cc70bSAndy Fleming 
687272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
6884e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
689272cc70bSAndy Fleming 			break;
690272cc70bSAndy Fleming 	}
691272cc70bSAndy Fleming 
692272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
6934e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
694272cc70bSAndy Fleming 		return 0;
695272cc70bSAndy Fleming 
6962c3fbf4cSMacpaul Lin 	/*
6972c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
6982c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
6992c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
7002c3fbf4cSMacpaul Lin 	 * mode between the host.
7012c3fbf4cSMacpaul Lin 	 */
70293bfd616SPantelis Antoniou 	if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
70393bfd616SPantelis Antoniou 		(mmc->cfg->host_caps & MMC_MODE_HS)))
7042c3fbf4cSMacpaul Lin 		return 0;
7052c3fbf4cSMacpaul Lin 
706f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
707272cc70bSAndy Fleming 
708272cc70bSAndy Fleming 	if (err)
709272cc70bSAndy Fleming 		return err;
710272cc70bSAndy Fleming 
7114e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
712272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
713272cc70bSAndy Fleming 
714272cc70bSAndy Fleming 	return 0;
715272cc70bSAndy Fleming }
716272cc70bSAndy Fleming 
717272cc70bSAndy Fleming /* frequency bases */
718272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
7195f837c2cSMike Frysinger static const int fbase[] = {
720272cc70bSAndy Fleming 	10000,
721272cc70bSAndy Fleming 	100000,
722272cc70bSAndy Fleming 	1000000,
723272cc70bSAndy Fleming 	10000000,
724272cc70bSAndy Fleming };
725272cc70bSAndy Fleming 
726272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
727272cc70bSAndy Fleming  * to platforms without floating point.
728272cc70bSAndy Fleming  */
7295f837c2cSMike Frysinger static const int multipliers[] = {
730272cc70bSAndy Fleming 	0,	/* reserved */
731272cc70bSAndy Fleming 	10,
732272cc70bSAndy Fleming 	12,
733272cc70bSAndy Fleming 	13,
734272cc70bSAndy Fleming 	15,
735272cc70bSAndy Fleming 	20,
736272cc70bSAndy Fleming 	25,
737272cc70bSAndy Fleming 	30,
738272cc70bSAndy Fleming 	35,
739272cc70bSAndy Fleming 	40,
740272cc70bSAndy Fleming 	45,
741272cc70bSAndy Fleming 	50,
742272cc70bSAndy Fleming 	55,
743272cc70bSAndy Fleming 	60,
744272cc70bSAndy Fleming 	70,
745272cc70bSAndy Fleming 	80,
746272cc70bSAndy Fleming };
747272cc70bSAndy Fleming 
748fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
749272cc70bSAndy Fleming {
75093bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
75193bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
752272cc70bSAndy Fleming }
753272cc70bSAndy Fleming 
754272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
755272cc70bSAndy Fleming {
75693bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
75793bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
758272cc70bSAndy Fleming 
75993bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
76093bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
761272cc70bSAndy Fleming 
762272cc70bSAndy Fleming 	mmc->clock = clock;
763272cc70bSAndy Fleming 
764272cc70bSAndy Fleming 	mmc_set_ios(mmc);
765272cc70bSAndy Fleming }
766272cc70bSAndy Fleming 
767fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width)
768272cc70bSAndy Fleming {
769272cc70bSAndy Fleming 	mmc->bus_width = width;
770272cc70bSAndy Fleming 
771272cc70bSAndy Fleming 	mmc_set_ios(mmc);
772272cc70bSAndy Fleming }
773272cc70bSAndy Fleming 
774fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
775272cc70bSAndy Fleming {
776f866a46dSStephen Warren 	int err, i;
777272cc70bSAndy Fleming 	uint mult, freq;
778639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
779272cc70bSAndy Fleming 	struct mmc_cmd cmd;
7808bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
7818bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
7825d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
783272cc70bSAndy Fleming 
784d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
785d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
786d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
787d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
788d52ebf10SThomas Chou 		cmd.cmdarg = 1;
789d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
790d52ebf10SThomas Chou 
791d52ebf10SThomas Chou 		if (err)
792d52ebf10SThomas Chou 			return err;
793d52ebf10SThomas Chou 	}
794d52ebf10SThomas Chou #endif
795d52ebf10SThomas Chou 
796272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
797d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
798d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
799272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
800272cc70bSAndy Fleming 	cmd.cmdarg = 0;
801272cc70bSAndy Fleming 
802272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
803272cc70bSAndy Fleming 
804272cc70bSAndy Fleming 	if (err)
805272cc70bSAndy Fleming 		return err;
806272cc70bSAndy Fleming 
807272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
808272cc70bSAndy Fleming 
809272cc70bSAndy Fleming 	/*
810272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
811272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
812272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
813272cc70bSAndy Fleming 	 */
814d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
815272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
816272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
817272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
818272cc70bSAndy Fleming 
819272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
820272cc70bSAndy Fleming 
821272cc70bSAndy Fleming 		if (err)
822272cc70bSAndy Fleming 			return err;
823272cc70bSAndy Fleming 
824272cc70bSAndy Fleming 		if (IS_SD(mmc))
825998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
826d52ebf10SThomas Chou 	}
827272cc70bSAndy Fleming 
828272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
829272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
830272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
831272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
832272cc70bSAndy Fleming 
833272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
834272cc70bSAndy Fleming 
8355d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
8365d4fc8d9SRaffaele Recalcati 	mmc_send_status(mmc, timeout);
8375d4fc8d9SRaffaele Recalcati 
838272cc70bSAndy Fleming 	if (err)
839272cc70bSAndy Fleming 		return err;
840272cc70bSAndy Fleming 
841998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
842998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
843998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
844998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
845272cc70bSAndy Fleming 
846272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
8470b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
848272cc70bSAndy Fleming 
849272cc70bSAndy Fleming 		switch (version) {
850272cc70bSAndy Fleming 			case 0:
851272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
852272cc70bSAndy Fleming 				break;
853272cc70bSAndy Fleming 			case 1:
854272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_4;
855272cc70bSAndy Fleming 				break;
856272cc70bSAndy Fleming 			case 2:
857272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_2_2;
858272cc70bSAndy Fleming 				break;
859272cc70bSAndy Fleming 			case 3:
860272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_3;
861272cc70bSAndy Fleming 				break;
862272cc70bSAndy Fleming 			case 4:
863272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_4;
864272cc70bSAndy Fleming 				break;
865272cc70bSAndy Fleming 			default:
866272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
867272cc70bSAndy Fleming 				break;
868272cc70bSAndy Fleming 		}
869272cc70bSAndy Fleming 	}
870272cc70bSAndy Fleming 
871272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
8720b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
8730b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
874272cc70bSAndy Fleming 
875272cc70bSAndy Fleming 	mmc->tran_speed = freq * mult;
876272cc70bSAndy Fleming 
877ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
878998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
879272cc70bSAndy Fleming 
880272cc70bSAndy Fleming 	if (IS_SD(mmc))
881272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
882272cc70bSAndy Fleming 	else
883998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
884272cc70bSAndy Fleming 
885272cc70bSAndy Fleming 	if (mmc->high_capacity) {
886272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
887272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
888272cc70bSAndy Fleming 		cmult = 8;
889272cc70bSAndy Fleming 	} else {
890272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
891272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
892272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
893272cc70bSAndy Fleming 	}
894272cc70bSAndy Fleming 
895f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
896f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
897f866a46dSStephen Warren 	mmc->capacity_boot = 0;
898f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
899f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
900f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
901272cc70bSAndy Fleming 
9028bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
9038bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
904272cc70bSAndy Fleming 
9058bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
9068bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
907272cc70bSAndy Fleming 
908ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
909ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
910ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
911ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
912ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
913ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
914ab71188cSMarkus Niebel 	}
915ab71188cSMarkus Niebel 
916272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
917d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
918272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
919fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
920272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
921272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
922272cc70bSAndy Fleming 
923272cc70bSAndy Fleming 		if (err)
924272cc70bSAndy Fleming 			return err;
925d52ebf10SThomas Chou 	}
926272cc70bSAndy Fleming 
927e6f99a56SLei Wen 	/*
928e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
929e6f99a56SLei Wen 	 */
930e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
931bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
932d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
933d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
934d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
935fdbb873eSKim Phillips 		if (!err && (ext_csd[EXT_CSD_REV] >= 2)) {
936639b7827SYoshihiro Shimoda 			/*
937639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
938639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
939639b7827SYoshihiro Shimoda 			 * than 2GB
940639b7827SYoshihiro Shimoda 			 */
9410560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
9420560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
9430560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
9440560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
9458bfa195eSSimon Glass 			capacity *= MMC_MAX_BLOCK_LEN;
946b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
947f866a46dSStephen Warren 				mmc->capacity_user = capacity;
948d23e2c09SSukumar Ghorai 		}
949bc897b1dSLei Wen 
95064f4a619SJaehoon Chung 		switch (ext_csd[EXT_CSD_REV]) {
95164f4a619SJaehoon Chung 		case 1:
95264f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_1;
95364f4a619SJaehoon Chung 			break;
95464f4a619SJaehoon Chung 		case 2:
95564f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_2;
95664f4a619SJaehoon Chung 			break;
95764f4a619SJaehoon Chung 		case 3:
95864f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_3;
95964f4a619SJaehoon Chung 			break;
96064f4a619SJaehoon Chung 		case 5:
96164f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_41;
96264f4a619SJaehoon Chung 			break;
96364f4a619SJaehoon Chung 		case 6:
96464f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_5;
96564f4a619SJaehoon Chung 			break;
96664f4a619SJaehoon Chung 		}
96764f4a619SJaehoon Chung 
968e6f99a56SLei Wen 		/*
9691937e5aaSOliver Metz 		 * Host needs to enable ERASE_GRP_DEF bit if device is
9701937e5aaSOliver Metz 		 * partitioned. This bit will be lost every time after a reset
9711937e5aaSOliver Metz 		 * or power off. This will affect erase size.
972e6f99a56SLei Wen 		 */
9731937e5aaSOliver Metz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
9741937e5aaSOliver Metz 		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) {
9751937e5aaSOliver Metz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
9761937e5aaSOliver Metz 				EXT_CSD_ERASE_GROUP_DEF, 1);
9771937e5aaSOliver Metz 
9781937e5aaSOliver Metz 			if (err)
9791937e5aaSOliver Metz 				return err;
9801937e5aaSOliver Metz 
9811937e5aaSOliver Metz 			/* Read out group size from ext_csd */
9820560db18SLei Wen 			mmc->erase_grp_size =
9838bfa195eSSimon Glass 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] *
9848bfa195eSSimon Glass 					MMC_MAX_BLOCK_LEN * 1024;
9858bfa195eSSimon Glass 		} else {
9861937e5aaSOliver Metz 			/* Calculate the group size from the csd value. */
987e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
988e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
989e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
990e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
991e6f99a56SLei Wen 				* (erase_gmul + 1);
992e6f99a56SLei Wen 		}
993e6f99a56SLei Wen 
994bc897b1dSLei Wen 		/* store the partition info of emmc */
9958948ea83SStephen Warren 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
9968948ea83SStephen Warren 		    ext_csd[EXT_CSD_BOOT_MULT])
9970560db18SLei Wen 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
998f866a46dSStephen Warren 
999f866a46dSStephen Warren 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
1000f866a46dSStephen Warren 
1001f866a46dSStephen Warren 		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
1002f866a46dSStephen Warren 
1003f866a46dSStephen Warren 		for (i = 0; i < 4; i++) {
1004f866a46dSStephen Warren 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
1005f866a46dSStephen Warren 			mmc->capacity_gp[i] = (ext_csd[idx + 2] << 16) +
1006f866a46dSStephen Warren 				(ext_csd[idx + 1] << 8) + ext_csd[idx];
1007f866a46dSStephen Warren 			mmc->capacity_gp[i] *=
1008f866a46dSStephen Warren 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1009f866a46dSStephen Warren 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1010d23e2c09SSukumar Ghorai 		}
1011f866a46dSStephen Warren 	}
1012f866a46dSStephen Warren 
1013f866a46dSStephen Warren 	err = mmc_set_capacity(mmc, mmc->part_num);
1014f866a46dSStephen Warren 	if (err)
1015f866a46dSStephen Warren 		return err;
1016d23e2c09SSukumar Ghorai 
1017272cc70bSAndy Fleming 	if (IS_SD(mmc))
1018272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1019272cc70bSAndy Fleming 	else
1020272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1021272cc70bSAndy Fleming 
1022272cc70bSAndy Fleming 	if (err)
1023272cc70bSAndy Fleming 		return err;
1024272cc70bSAndy Fleming 
1025272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
102693bfd616SPantelis Antoniou 	mmc->card_caps &= mmc->cfg->host_caps;
1027272cc70bSAndy Fleming 
1028272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1029272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1030272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1031272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1032272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1033272cc70bSAndy Fleming 
1034272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1035272cc70bSAndy Fleming 			if (err)
1036272cc70bSAndy Fleming 				return err;
1037272cc70bSAndy Fleming 
1038272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1039272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1040272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1041272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1042272cc70bSAndy Fleming 			if (err)
1043272cc70bSAndy Fleming 				return err;
1044272cc70bSAndy Fleming 
1045272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1046272cc70bSAndy Fleming 		}
1047272cc70bSAndy Fleming 
1048272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
1049ad5fd922SJaehoon Chung 			mmc->tran_speed = 50000000;
1050272cc70bSAndy Fleming 		else
1051ad5fd922SJaehoon Chung 			mmc->tran_speed = 25000000;
1052272cc70bSAndy Fleming 	} else {
10537798f6dbSAndy Fleming 		int idx;
10547798f6dbSAndy Fleming 
10557798f6dbSAndy Fleming 		/* An array of possible bus widths in order of preference */
10567798f6dbSAndy Fleming 		static unsigned ext_csd_bits[] = {
10577798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_8,
10587798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_4,
10597798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_1,
10607798f6dbSAndy Fleming 		};
10617798f6dbSAndy Fleming 
10627798f6dbSAndy Fleming 		/* An array to map CSD bus widths to host cap bits */
10637798f6dbSAndy Fleming 		static unsigned ext_to_hostcaps[] = {
10647798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
10657798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
10667798f6dbSAndy Fleming 		};
10677798f6dbSAndy Fleming 
10687798f6dbSAndy Fleming 		/* An array to map chosen bus width to an integer */
10697798f6dbSAndy Fleming 		static unsigned widths[] = {
10707798f6dbSAndy Fleming 			8, 4, 1,
10717798f6dbSAndy Fleming 		};
10727798f6dbSAndy Fleming 
10737798f6dbSAndy Fleming 		for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
10747798f6dbSAndy Fleming 			unsigned int extw = ext_csd_bits[idx];
10757798f6dbSAndy Fleming 
10767798f6dbSAndy Fleming 			/*
10777798f6dbSAndy Fleming 			 * Check to make sure the controller supports
10787798f6dbSAndy Fleming 			 * this bus width, if it's more than 1
10797798f6dbSAndy Fleming 			 */
10807798f6dbSAndy Fleming 			if (extw != EXT_CSD_BUS_WIDTH_1 &&
108193bfd616SPantelis Antoniou 					!(mmc->cfg->host_caps & ext_to_hostcaps[extw]))
10827798f6dbSAndy Fleming 				continue;
10837798f6dbSAndy Fleming 
1084272cc70bSAndy Fleming 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
10857798f6dbSAndy Fleming 					EXT_CSD_BUS_WIDTH, extw);
1086272cc70bSAndy Fleming 
1087272cc70bSAndy Fleming 			if (err)
10884137894eSLei Wen 				continue;
1089272cc70bSAndy Fleming 
10907798f6dbSAndy Fleming 			mmc_set_bus_width(mmc, widths[idx]);
1091272cc70bSAndy Fleming 
10924137894eSLei Wen 			err = mmc_send_ext_csd(mmc, test_csd);
10934137894eSLei Wen 			if (!err && ext_csd[EXT_CSD_PARTITIONING_SUPPORT] \
10944137894eSLei Wen 				    == test_csd[EXT_CSD_PARTITIONING_SUPPORT]
10954137894eSLei Wen 				 && ext_csd[EXT_CSD_ERASE_GROUP_DEF] \
10964137894eSLei Wen 				    == test_csd[EXT_CSD_ERASE_GROUP_DEF] \
10974137894eSLei Wen 				 && ext_csd[EXT_CSD_REV] \
10984137894eSLei Wen 				    == test_csd[EXT_CSD_REV]
10994137894eSLei Wen 				 && ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] \
11004137894eSLei Wen 				    == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
11014137894eSLei Wen 				 && memcmp(&ext_csd[EXT_CSD_SEC_CNT], \
11024137894eSLei Wen 					&test_csd[EXT_CSD_SEC_CNT], 4) == 0) {
1103272cc70bSAndy Fleming 
11047798f6dbSAndy Fleming 				mmc->card_caps |= ext_to_hostcaps[extw];
11054137894eSLei Wen 				break;
11064137894eSLei Wen 			}
1107272cc70bSAndy Fleming 		}
1108272cc70bSAndy Fleming 
1109272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS) {
1110272cc70bSAndy Fleming 			if (mmc->card_caps & MMC_MODE_HS_52MHz)
1111ad5fd922SJaehoon Chung 				mmc->tran_speed = 52000000;
1112272cc70bSAndy Fleming 			else
1113ad5fd922SJaehoon Chung 				mmc->tran_speed = 26000000;
1114272cc70bSAndy Fleming 		}
1115ad5fd922SJaehoon Chung 	}
1116ad5fd922SJaehoon Chung 
1117ad5fd922SJaehoon Chung 	mmc_set_clock(mmc, mmc->tran_speed);
1118272cc70bSAndy Fleming 
1119272cc70bSAndy Fleming 	/* fill in device description */
1120272cc70bSAndy Fleming 	mmc->block_dev.lun = 0;
1121272cc70bSAndy Fleming 	mmc->block_dev.type = 0;
1122272cc70bSAndy Fleming 	mmc->block_dev.blksz = mmc->read_bl_len;
11230472fbfdSEgbert Eich 	mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz);
11249b1f942cSRabin Vincent 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
112556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1126babce5f6STaylor Hutt 	sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x",
1127babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1128babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1129babce5f6STaylor Hutt 	sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
11300b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1131babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1132babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1133babce5f6STaylor Hutt 	sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1134babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
113556196826SPaul Burton #else
113656196826SPaul Burton 	mmc->block_dev.vendor[0] = 0;
113756196826SPaul Burton 	mmc->block_dev.product[0] = 0;
113856196826SPaul Burton 	mmc->block_dev.revision[0] = 0;
113956196826SPaul Burton #endif
1140122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1141272cc70bSAndy Fleming 	init_part(&mmc->block_dev);
1142122efd43SMikhail Kshevetskiy #endif
1143272cc70bSAndy Fleming 
1144272cc70bSAndy Fleming 	return 0;
1145272cc70bSAndy Fleming }
1146272cc70bSAndy Fleming 
1147fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1148272cc70bSAndy Fleming {
1149272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1150272cc70bSAndy Fleming 	int err;
1151272cc70bSAndy Fleming 
1152272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1153272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
115493bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1155272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1156272cc70bSAndy Fleming 
1157272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1158272cc70bSAndy Fleming 
1159272cc70bSAndy Fleming 	if (err)
1160272cc70bSAndy Fleming 		return err;
1161272cc70bSAndy Fleming 
1162998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1163272cc70bSAndy Fleming 		return UNUSABLE_ERR;
1164272cc70bSAndy Fleming 	else
1165272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1166272cc70bSAndy Fleming 
1167272cc70bSAndy Fleming 	return 0;
1168272cc70bSAndy Fleming }
1169272cc70bSAndy Fleming 
117093bfd616SPantelis Antoniou /* not used any more */
117193bfd616SPantelis Antoniou int __deprecated mmc_register(struct mmc *mmc)
1172272cc70bSAndy Fleming {
117393bfd616SPantelis Antoniou #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
117493bfd616SPantelis Antoniou 	printf("%s is deprecated! use mmc_create() instead.\n", __func__);
117593bfd616SPantelis Antoniou #endif
117693bfd616SPantelis Antoniou 	return -1;
117793bfd616SPantelis Antoniou }
117893bfd616SPantelis Antoniou 
117993bfd616SPantelis Antoniou struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
118093bfd616SPantelis Antoniou {
118193bfd616SPantelis Antoniou 	struct mmc *mmc;
118293bfd616SPantelis Antoniou 
118393bfd616SPantelis Antoniou 	/* quick validation */
118493bfd616SPantelis Antoniou 	if (cfg == NULL || cfg->ops == NULL || cfg->ops->send_cmd == NULL ||
118593bfd616SPantelis Antoniou 			cfg->f_min == 0 || cfg->f_max == 0 || cfg->b_max == 0)
118693bfd616SPantelis Antoniou 		return NULL;
118793bfd616SPantelis Antoniou 
118893bfd616SPantelis Antoniou 	mmc = calloc(1, sizeof(*mmc));
118993bfd616SPantelis Antoniou 	if (mmc == NULL)
119093bfd616SPantelis Antoniou 		return NULL;
119193bfd616SPantelis Antoniou 
119293bfd616SPantelis Antoniou 	mmc->cfg = cfg;
119393bfd616SPantelis Antoniou 	mmc->priv = priv;
119493bfd616SPantelis Antoniou 
119593bfd616SPantelis Antoniou 	/* the following chunk was mmc_register() */
119693bfd616SPantelis Antoniou 
1197ab71188cSMarkus Niebel 	/* Setup dsr related values */
1198ab71188cSMarkus Niebel 	mmc->dsr_imp = 0;
1199ab71188cSMarkus Niebel 	mmc->dsr = 0xffffffff;
1200272cc70bSAndy Fleming 	/* Setup the universal parts of the block interface just once */
1201272cc70bSAndy Fleming 	mmc->block_dev.if_type = IF_TYPE_MMC;
1202272cc70bSAndy Fleming 	mmc->block_dev.dev = cur_dev_num++;
1203272cc70bSAndy Fleming 	mmc->block_dev.removable = 1;
1204272cc70bSAndy Fleming 	mmc->block_dev.block_read = mmc_bread;
1205272cc70bSAndy Fleming 	mmc->block_dev.block_write = mmc_bwrite;
1206e6f99a56SLei Wen 	mmc->block_dev.block_erase = mmc_berase;
120793bfd616SPantelis Antoniou 
120893bfd616SPantelis Antoniou 	/* setup initial part type */
120993bfd616SPantelis Antoniou 	mmc->block_dev.part_type = mmc->cfg->part_type;
1210272cc70bSAndy Fleming 
1211272cc70bSAndy Fleming 	INIT_LIST_HEAD(&mmc->link);
1212272cc70bSAndy Fleming 
1213272cc70bSAndy Fleming 	list_add_tail(&mmc->link, &mmc_devices);
1214272cc70bSAndy Fleming 
121593bfd616SPantelis Antoniou 	return mmc;
121693bfd616SPantelis Antoniou }
121793bfd616SPantelis Antoniou 
121893bfd616SPantelis Antoniou void mmc_destroy(struct mmc *mmc)
121993bfd616SPantelis Antoniou {
122093bfd616SPantelis Antoniou 	/* only freeing memory for now */
122193bfd616SPantelis Antoniou 	free(mmc);
1222272cc70bSAndy Fleming }
1223272cc70bSAndy Fleming 
1224df3fc526SMatthew McClintock #ifdef CONFIG_PARTITIONS
1225272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev)
1226272cc70bSAndy Fleming {
1227272cc70bSAndy Fleming 	struct mmc *mmc = find_mmc_device(dev);
12286bb4b4bcSBenoît Thébaudeau 	if (!mmc || mmc_init(mmc))
122940242bc3SŁukasz Majewski 		return NULL;
1230272cc70bSAndy Fleming 
123140242bc3SŁukasz Majewski 	return &mmc->block_dev;
1232272cc70bSAndy Fleming }
1233df3fc526SMatthew McClintock #endif
1234272cc70bSAndy Fleming 
1235e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1236272cc70bSAndy Fleming {
1237afd5932bSMacpaul Lin 	int err;
1238272cc70bSAndy Fleming 
1239ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
124093bfd616SPantelis Antoniou 	if (mmc_getcd(mmc) == 0 || mmc->cfg->ops->init == NULL) {
124148972d90SThierry Reding 		mmc->has_init = 0;
124256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
124348972d90SThierry Reding 		printf("MMC: no card present\n");
124456196826SPaul Burton #endif
124548972d90SThierry Reding 		return NO_CARD_ERR;
124648972d90SThierry Reding 	}
124748972d90SThierry Reding 
1248bc897b1dSLei Wen 	if (mmc->has_init)
1249bc897b1dSLei Wen 		return 0;
1250bc897b1dSLei Wen 
1251ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
125293bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
1253272cc70bSAndy Fleming 
1254272cc70bSAndy Fleming 	if (err)
1255272cc70bSAndy Fleming 		return err;
1256272cc70bSAndy Fleming 
1257b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1258b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1259b86b85e2SIlya Yanok 
1260272cc70bSAndy Fleming 	/* Reset the Card */
1261272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1262272cc70bSAndy Fleming 
1263272cc70bSAndy Fleming 	if (err)
1264272cc70bSAndy Fleming 		return err;
1265272cc70bSAndy Fleming 
1266bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1267bc897b1dSLei Wen 	mmc->part_num = 0;
1268bc897b1dSLei Wen 
1269272cc70bSAndy Fleming 	/* Test for SD version 2 */
1270272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1271272cc70bSAndy Fleming 
1272272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1273272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1274272cc70bSAndy Fleming 
1275272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1276272cc70bSAndy Fleming 	if (err == TIMEOUT) {
1277272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1278272cc70bSAndy Fleming 
1279e9550449SChe-Liang Chiou 		if (err && err != IN_PROGRESS) {
128056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1281272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
128256196826SPaul Burton #endif
1283272cc70bSAndy Fleming 			return UNUSABLE_ERR;
1284272cc70bSAndy Fleming 		}
1285272cc70bSAndy Fleming 	}
1286272cc70bSAndy Fleming 
1287e9550449SChe-Liang Chiou 	if (err == IN_PROGRESS)
1288e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
1289e9550449SChe-Liang Chiou 
1290e9550449SChe-Liang Chiou 	return err;
1291e9550449SChe-Liang Chiou }
1292e9550449SChe-Liang Chiou 
1293e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
1294e9550449SChe-Liang Chiou {
1295e9550449SChe-Liang Chiou 	int err = 0;
1296e9550449SChe-Liang Chiou 
1297e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
1298e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
1299e9550449SChe-Liang Chiou 
1300e9550449SChe-Liang Chiou 	if (!err)
1301bc897b1dSLei Wen 		err = mmc_startup(mmc);
1302bc897b1dSLei Wen 	if (err)
1303bc897b1dSLei Wen 		mmc->has_init = 0;
1304bc897b1dSLei Wen 	else
1305bc897b1dSLei Wen 		mmc->has_init = 1;
1306e9550449SChe-Liang Chiou 	mmc->init_in_progress = 0;
1307e9550449SChe-Liang Chiou 	return err;
1308e9550449SChe-Liang Chiou }
1309e9550449SChe-Liang Chiou 
1310e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
1311e9550449SChe-Liang Chiou {
1312e9550449SChe-Liang Chiou 	int err = IN_PROGRESS;
1313*d803fea5SMateusz Zalega 	unsigned start;
1314e9550449SChe-Liang Chiou 
1315e9550449SChe-Liang Chiou 	if (mmc->has_init)
1316e9550449SChe-Liang Chiou 		return 0;
1317*d803fea5SMateusz Zalega 
1318*d803fea5SMateusz Zalega 	start = get_timer(0);
1319*d803fea5SMateusz Zalega 
1320e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
1321e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
1322e9550449SChe-Liang Chiou 
1323e9550449SChe-Liang Chiou 	if (!err || err == IN_PROGRESS)
1324e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
1325e9550449SChe-Liang Chiou 	debug("%s: %d, time %lu\n", __func__, err, get_timer(start));
1326bc897b1dSLei Wen 	return err;
1327272cc70bSAndy Fleming }
1328272cc70bSAndy Fleming 
1329ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
1330ab71188cSMarkus Niebel {
1331ab71188cSMarkus Niebel 	mmc->dsr = val;
1332ab71188cSMarkus Niebel 	return 0;
1333ab71188cSMarkus Niebel }
1334ab71188cSMarkus Niebel 
1335272cc70bSAndy Fleming /*
1336272cc70bSAndy Fleming  * CPU and board-specific MMC initializations.  Aliased function
1337272cc70bSAndy Fleming  * signals caller to move on
1338272cc70bSAndy Fleming  */
1339272cc70bSAndy Fleming static int __def_mmc_init(bd_t *bis)
1340272cc70bSAndy Fleming {
1341272cc70bSAndy Fleming 	return -1;
1342272cc70bSAndy Fleming }
1343272cc70bSAndy Fleming 
1344f9a109b3SPeter Tyser int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
1345f9a109b3SPeter Tyser int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
1346272cc70bSAndy Fleming 
134756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
134856196826SPaul Burton 
1349272cc70bSAndy Fleming void print_mmc_devices(char separator)
1350272cc70bSAndy Fleming {
1351272cc70bSAndy Fleming 	struct mmc *m;
1352272cc70bSAndy Fleming 	struct list_head *entry;
1353272cc70bSAndy Fleming 
1354272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
1355272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
1356272cc70bSAndy Fleming 
135793bfd616SPantelis Antoniou 		printf("%s: %d", m->cfg->name, m->block_dev.dev);
1358272cc70bSAndy Fleming 
1359272cc70bSAndy Fleming 		if (entry->next != &mmc_devices)
1360272cc70bSAndy Fleming 			printf("%c ", separator);
1361272cc70bSAndy Fleming 	}
1362272cc70bSAndy Fleming 
1363272cc70bSAndy Fleming 	printf("\n");
1364272cc70bSAndy Fleming }
1365272cc70bSAndy Fleming 
136656196826SPaul Burton #else
136756196826SPaul Burton void print_mmc_devices(char separator) { }
136856196826SPaul Burton #endif
136956196826SPaul Burton 
1370ea6ebe21SLei Wen int get_mmc_num(void)
1371ea6ebe21SLei Wen {
1372ea6ebe21SLei Wen 	return cur_dev_num;
1373ea6ebe21SLei Wen }
1374ea6ebe21SLei Wen 
1375e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
1376e9550449SChe-Liang Chiou {
1377e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
1378e9550449SChe-Liang Chiou }
1379e9550449SChe-Liang Chiou 
1380e9550449SChe-Liang Chiou static void do_preinit(void)
1381e9550449SChe-Liang Chiou {
1382e9550449SChe-Liang Chiou 	struct mmc *m;
1383e9550449SChe-Liang Chiou 	struct list_head *entry;
1384e9550449SChe-Liang Chiou 
1385e9550449SChe-Liang Chiou 	list_for_each(entry, &mmc_devices) {
1386e9550449SChe-Liang Chiou 		m = list_entry(entry, struct mmc, link);
1387e9550449SChe-Liang Chiou 
1388e9550449SChe-Liang Chiou 		if (m->preinit)
1389e9550449SChe-Liang Chiou 			mmc_start_init(m);
1390e9550449SChe-Liang Chiou 	}
1391e9550449SChe-Liang Chiou }
1392e9550449SChe-Liang Chiou 
1393e9550449SChe-Liang Chiou 
1394272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1395272cc70bSAndy Fleming {
1396272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc_devices);
1397272cc70bSAndy Fleming 	cur_dev_num = 0;
1398272cc70bSAndy Fleming 
1399272cc70bSAndy Fleming 	if (board_mmc_init(bis) < 0)
1400272cc70bSAndy Fleming 		cpu_mmc_init(bis);
1401272cc70bSAndy Fleming 
1402bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
1403272cc70bSAndy Fleming 	print_mmc_devices(',');
1404bb0dc108SYing Zhang #endif
1405272cc70bSAndy Fleming 
1406e9550449SChe-Liang Chiou 	do_preinit();
1407272cc70bSAndy Fleming 	return 0;
1408272cc70bSAndy Fleming }
14093690d6d6SAmar 
14103690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT
14113690d6d6SAmar /*
14123690d6d6SAmar  * This function changes the size of boot partition and the size of rpmb
14133690d6d6SAmar  * partition present on EMMC devices.
14143690d6d6SAmar  *
14153690d6d6SAmar  * Input Parameters:
14163690d6d6SAmar  * struct *mmc: pointer for the mmc device strcuture
14173690d6d6SAmar  * bootsize: size of boot partition
14183690d6d6SAmar  * rpmbsize: size of rpmb partition
14193690d6d6SAmar  *
14203690d6d6SAmar  * Returns 0 on success.
14213690d6d6SAmar  */
14223690d6d6SAmar 
14233690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
14243690d6d6SAmar 				unsigned long rpmbsize)
14253690d6d6SAmar {
14263690d6d6SAmar 	int err;
14273690d6d6SAmar 	struct mmc_cmd cmd;
14283690d6d6SAmar 
14293690d6d6SAmar 	/* Only use this command for raw EMMC moviNAND. Enter backdoor mode */
14303690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
14313690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
14323690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG1;
14333690d6d6SAmar 
14343690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
14353690d6d6SAmar 	if (err) {
14363690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error1 = %d\n", err);
14373690d6d6SAmar 		return err;
14383690d6d6SAmar 	}
14393690d6d6SAmar 
14403690d6d6SAmar 	/* Boot partition changing mode */
14413690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
14423690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
14433690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG2;
14443690d6d6SAmar 
14453690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
14463690d6d6SAmar 	if (err) {
14473690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error2 = %d\n", err);
14483690d6d6SAmar 		return err;
14493690d6d6SAmar 	}
14503690d6d6SAmar 	/* boot partition size is multiple of 128KB */
14513690d6d6SAmar 	bootsize = (bootsize * 1024) / 128;
14523690d6d6SAmar 
14533690d6d6SAmar 	/* Arg: boot partition size */
14543690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
14553690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
14563690d6d6SAmar 	cmd.cmdarg = bootsize;
14573690d6d6SAmar 
14583690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
14593690d6d6SAmar 	if (err) {
14603690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error3 = %d\n", err);
14613690d6d6SAmar 		return err;
14623690d6d6SAmar 	}
14633690d6d6SAmar 	/* RPMB partition size is multiple of 128KB */
14643690d6d6SAmar 	rpmbsize = (rpmbsize * 1024) / 128;
14653690d6d6SAmar 	/* Arg: RPMB partition size */
14663690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
14673690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
14683690d6d6SAmar 	cmd.cmdarg = rpmbsize;
14693690d6d6SAmar 
14703690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
14713690d6d6SAmar 	if (err) {
14723690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error4 = %d\n", err);
14733690d6d6SAmar 		return err;
14743690d6d6SAmar 	}
14753690d6d6SAmar 	return 0;
14763690d6d6SAmar }
14773690d6d6SAmar 
14783690d6d6SAmar /*
14795a99b9deSTom Rini  * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH
14805a99b9deSTom Rini  * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH
14815a99b9deSTom Rini  * and BOOT_MODE.
14825a99b9deSTom Rini  *
14835a99b9deSTom Rini  * Returns 0 on success.
14845a99b9deSTom Rini  */
14855a99b9deSTom Rini int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode)
14865a99b9deSTom Rini {
14875a99b9deSTom Rini 	int err;
14885a99b9deSTom Rini 
14895a99b9deSTom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH,
14905a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) |
14915a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) |
14925a99b9deSTom Rini 			 EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width));
14935a99b9deSTom Rini 
14945a99b9deSTom Rini 	if (err)
14955a99b9deSTom Rini 		return err;
14965a99b9deSTom Rini 	return 0;
14975a99b9deSTom Rini }
14985a99b9deSTom Rini 
14995a99b9deSTom Rini /*
1500792970b0STom Rini  * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG)
1501792970b0STom Rini  * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and
1502792970b0STom Rini  * PARTITION_ACCESS.
1503792970b0STom Rini  *
1504792970b0STom Rini  * Returns 0 on success.
1505792970b0STom Rini  */
1506792970b0STom Rini int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access)
1507792970b0STom Rini {
1508792970b0STom Rini 	int err;
1509792970b0STom Rini 
1510792970b0STom Rini 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
1511792970b0STom Rini 			 EXT_CSD_BOOT_ACK(ack) |
1512792970b0STom Rini 			 EXT_CSD_BOOT_PART_NUM(part_num) |
1513792970b0STom Rini 			 EXT_CSD_PARTITION_ACCESS(access));
1514792970b0STom Rini 
1515792970b0STom Rini 	if (err)
1516792970b0STom Rini 		return err;
1517792970b0STom Rini 	return 0;
1518792970b0STom Rini }
151933ace362STom Rini 
152033ace362STom Rini /*
152133ace362STom Rini  * Modify EXT_CSD[162] which is RST_n_FUNCTION based on the given value
152233ace362STom Rini  * for enable.  Note that this is a write-once field for non-zero values.
152333ace362STom Rini  *
152433ace362STom Rini  * Returns 0 on success.
152533ace362STom Rini  */
152633ace362STom Rini int mmc_set_rst_n_function(struct mmc *mmc, u8 enable)
152733ace362STom Rini {
152833ace362STom Rini 	return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_RST_N_FUNCTION,
152933ace362STom Rini 			  enable);
153033ace362STom Rini }
15313690d6d6SAmar #endif
1532