xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 1a459660)
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  *
7*1a459660SWolfgang 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>
18272cc70bSAndy Fleming 
19ce0fbcd2SMatt Waddel /* Set block count limit because of 16 bit register limit on some hardware*/
20ce0fbcd2SMatt Waddel #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT
21ce0fbcd2SMatt Waddel #define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535
22ce0fbcd2SMatt Waddel #endif
23ce0fbcd2SMatt Waddel 
24272cc70bSAndy Fleming static struct list_head mmc_devices;
25272cc70bSAndy Fleming static int cur_dev_num = -1;
26272cc70bSAndy Fleming 
27d23d8d7eSNikita Kiryanov int __weak board_mmc_getwp(struct mmc *mmc)
28d23d8d7eSNikita Kiryanov {
29d23d8d7eSNikita Kiryanov 	return -1;
30d23d8d7eSNikita Kiryanov }
31d23d8d7eSNikita Kiryanov 
32d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
33d23d8d7eSNikita Kiryanov {
34d23d8d7eSNikita Kiryanov 	int wp;
35d23d8d7eSNikita Kiryanov 
36d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
37d23d8d7eSNikita Kiryanov 
38d4e1da4eSPeter Korsgaard 	if (wp < 0) {
39d4e1da4eSPeter Korsgaard 		if (mmc->getwp)
40d23d8d7eSNikita Kiryanov 			wp = mmc->getwp(mmc);
41d4e1da4eSPeter Korsgaard 		else
42d4e1da4eSPeter Korsgaard 			wp = 0;
43d4e1da4eSPeter Korsgaard 	}
44d23d8d7eSNikita Kiryanov 
45d23d8d7eSNikita Kiryanov 	return wp;
46d23d8d7eSNikita Kiryanov }
47d23d8d7eSNikita Kiryanov 
48314284b1SThierry Reding int __board_mmc_getcd(struct mmc *mmc) {
4911fdade2SStefano Babic 	return -1;
5011fdade2SStefano Babic }
5111fdade2SStefano Babic 
52314284b1SThierry Reding int board_mmc_getcd(struct mmc *mmc)__attribute__((weak,
5311fdade2SStefano Babic 	alias("__board_mmc_getcd")));
5411fdade2SStefano Babic 
55fdbb873eSKim Phillips static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
56fdbb873eSKim Phillips 			struct mmc_data *data)
57272cc70bSAndy Fleming {
588635ff9eSMarek Vasut 	struct mmc_data backup;
595db2fe3aSRaffaele Recalcati 	int ret;
608635ff9eSMarek Vasut 
618635ff9eSMarek Vasut 	memset(&backup, 0, sizeof(backup));
628635ff9eSMarek Vasut 
638635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
645db2fe3aSRaffaele Recalcati 	int i;
655db2fe3aSRaffaele Recalcati 	u8 *ptr;
665db2fe3aSRaffaele Recalcati 
675db2fe3aSRaffaele Recalcati 	printf("CMD_SEND:%d\n", cmd->cmdidx);
685db2fe3aSRaffaele Recalcati 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
695db2fe3aSRaffaele Recalcati 	ret = mmc->send_cmd(mmc, cmd, data);
705db2fe3aSRaffaele Recalcati 	switch (cmd->resp_type) {
715db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
725db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
735db2fe3aSRaffaele Recalcati 			break;
745db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
755db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
765db2fe3aSRaffaele Recalcati 				cmd->response[0]);
775db2fe3aSRaffaele Recalcati 			break;
785db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
795db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
805db2fe3aSRaffaele Recalcati 				cmd->response[0]);
815db2fe3aSRaffaele Recalcati 			break;
825db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
835db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
845db2fe3aSRaffaele Recalcati 				cmd->response[0]);
855db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
865db2fe3aSRaffaele Recalcati 				cmd->response[1]);
875db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
885db2fe3aSRaffaele Recalcati 				cmd->response[2]);
895db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
905db2fe3aSRaffaele Recalcati 				cmd->response[3]);
915db2fe3aSRaffaele Recalcati 			printf("\n");
925db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
935db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
945db2fe3aSRaffaele Recalcati 				int j;
955db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
96146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
975db2fe3aSRaffaele Recalcati 				ptr += 3;
985db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
995db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
1005db2fe3aSRaffaele Recalcati 				printf("\n");
1015db2fe3aSRaffaele Recalcati 			}
1025db2fe3aSRaffaele Recalcati 			break;
1035db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1045db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1055db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1065db2fe3aSRaffaele Recalcati 			break;
1075db2fe3aSRaffaele Recalcati 		default:
1085db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1095db2fe3aSRaffaele Recalcati 			break;
1105db2fe3aSRaffaele Recalcati 	}
1115db2fe3aSRaffaele Recalcati #else
1128635ff9eSMarek Vasut 	ret = mmc->send_cmd(mmc, cmd, data);
1135db2fe3aSRaffaele Recalcati #endif
1148635ff9eSMarek Vasut 	return ret;
115272cc70bSAndy Fleming }
116272cc70bSAndy Fleming 
117fdbb873eSKim Phillips static int mmc_send_status(struct mmc *mmc, int timeout)
1185d4fc8d9SRaffaele Recalcati {
1195d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
120d617c426SJan Kloetzke 	int err, retries = 5;
1215d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
1225d4fc8d9SRaffaele Recalcati 	int status;
1235d4fc8d9SRaffaele Recalcati #endif
1245d4fc8d9SRaffaele Recalcati 
1255d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
1265d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
127aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
128aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
1295d4fc8d9SRaffaele Recalcati 
1305d4fc8d9SRaffaele Recalcati 	do {
1315d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
132d617c426SJan Kloetzke 		if (!err) {
133d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
134d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
135d617c426SJan Kloetzke 			     MMC_STATE_PRG)
1365d4fc8d9SRaffaele Recalcati 				break;
137d617c426SJan Kloetzke 			else if (cmd.response[0] & MMC_STATUS_MASK) {
138d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
139d617c426SJan Kloetzke 					cmd.response[0]);
140d617c426SJan Kloetzke 				return COMM_ERR;
141d617c426SJan Kloetzke 			}
142d617c426SJan Kloetzke 		} else if (--retries < 0)
143d617c426SJan Kloetzke 			return err;
1445d4fc8d9SRaffaele Recalcati 
1455d4fc8d9SRaffaele Recalcati 		udelay(1000);
1465d4fc8d9SRaffaele Recalcati 
1475d4fc8d9SRaffaele Recalcati 	} while (timeout--);
1485d4fc8d9SRaffaele Recalcati 
1495db2fe3aSRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
1505db2fe3aSRaffaele Recalcati 	status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9;
1515db2fe3aSRaffaele Recalcati 	printf("CURR STATE:%d\n", status);
1525db2fe3aSRaffaele Recalcati #endif
1535b0c942fSJongman Heo 	if (timeout <= 0) {
1545d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
1555d4fc8d9SRaffaele Recalcati 		return TIMEOUT;
1565d4fc8d9SRaffaele Recalcati 	}
1575d4fc8d9SRaffaele Recalcati 
1585d4fc8d9SRaffaele Recalcati 	return 0;
1595d4fc8d9SRaffaele Recalcati }
1605d4fc8d9SRaffaele Recalcati 
161fdbb873eSKim Phillips static int mmc_set_blocklen(struct mmc *mmc, int len)
162272cc70bSAndy Fleming {
163272cc70bSAndy Fleming 	struct mmc_cmd cmd;
164272cc70bSAndy Fleming 
165272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
166272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
167272cc70bSAndy Fleming 	cmd.cmdarg = len;
168272cc70bSAndy Fleming 
169272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
170272cc70bSAndy Fleming }
171272cc70bSAndy Fleming 
172272cc70bSAndy Fleming struct mmc *find_mmc_device(int dev_num)
173272cc70bSAndy Fleming {
174272cc70bSAndy Fleming 	struct mmc *m;
175272cc70bSAndy Fleming 	struct list_head *entry;
176272cc70bSAndy Fleming 
177272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
178272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
179272cc70bSAndy Fleming 
180272cc70bSAndy Fleming 		if (m->block_dev.dev == dev_num)
181272cc70bSAndy Fleming 			return m;
182272cc70bSAndy Fleming 	}
183272cc70bSAndy Fleming 
184272cc70bSAndy Fleming 	printf("MMC Device %d not found\n", dev_num);
185272cc70bSAndy Fleming 
186272cc70bSAndy Fleming 	return NULL;
187272cc70bSAndy Fleming }
188272cc70bSAndy Fleming 
189e6f99a56SLei Wen static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt)
190e6f99a56SLei Wen {
191e6f99a56SLei Wen 	struct mmc_cmd cmd;
192e6f99a56SLei Wen 	ulong end;
193e6f99a56SLei Wen 	int err, start_cmd, end_cmd;
194e6f99a56SLei Wen 
195e6f99a56SLei Wen 	if (mmc->high_capacity)
196e6f99a56SLei Wen 		end = start + blkcnt - 1;
197e6f99a56SLei Wen 	else {
198e6f99a56SLei Wen 		end = (start + blkcnt - 1) * mmc->write_bl_len;
199e6f99a56SLei Wen 		start *= mmc->write_bl_len;
200e6f99a56SLei Wen 	}
201e6f99a56SLei Wen 
202e6f99a56SLei Wen 	if (IS_SD(mmc)) {
203e6f99a56SLei Wen 		start_cmd = SD_CMD_ERASE_WR_BLK_START;
204e6f99a56SLei Wen 		end_cmd = SD_CMD_ERASE_WR_BLK_END;
205e6f99a56SLei Wen 	} else {
206e6f99a56SLei Wen 		start_cmd = MMC_CMD_ERASE_GROUP_START;
207e6f99a56SLei Wen 		end_cmd = MMC_CMD_ERASE_GROUP_END;
208e6f99a56SLei Wen 	}
209e6f99a56SLei Wen 
210e6f99a56SLei Wen 	cmd.cmdidx = start_cmd;
211e6f99a56SLei Wen 	cmd.cmdarg = start;
212e6f99a56SLei Wen 	cmd.resp_type = MMC_RSP_R1;
213e6f99a56SLei Wen 
214e6f99a56SLei Wen 	err = mmc_send_cmd(mmc, &cmd, NULL);
215e6f99a56SLei Wen 	if (err)
216e6f99a56SLei Wen 		goto err_out;
217e6f99a56SLei Wen 
218e6f99a56SLei Wen 	cmd.cmdidx = end_cmd;
219e6f99a56SLei Wen 	cmd.cmdarg = end;
220e6f99a56SLei Wen 
221e6f99a56SLei Wen 	err = mmc_send_cmd(mmc, &cmd, NULL);
222e6f99a56SLei Wen 	if (err)
223e6f99a56SLei Wen 		goto err_out;
224e6f99a56SLei Wen 
225e6f99a56SLei Wen 	cmd.cmdidx = MMC_CMD_ERASE;
226e6f99a56SLei Wen 	cmd.cmdarg = SECURE_ERASE;
227e6f99a56SLei Wen 	cmd.resp_type = MMC_RSP_R1b;
228e6f99a56SLei Wen 
229e6f99a56SLei Wen 	err = mmc_send_cmd(mmc, &cmd, NULL);
230e6f99a56SLei Wen 	if (err)
231e6f99a56SLei Wen 		goto err_out;
232e6f99a56SLei Wen 
233e6f99a56SLei Wen 	return 0;
234e6f99a56SLei Wen 
235e6f99a56SLei Wen err_out:
236e6f99a56SLei Wen 	puts("mmc erase failed\n");
237e6f99a56SLei Wen 	return err;
238e6f99a56SLei Wen }
239e6f99a56SLei Wen 
240e6f99a56SLei Wen static unsigned long
241ff8fef56SSascha Silbe mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt)
242e6f99a56SLei Wen {
243e6f99a56SLei Wen 	int err = 0;
244e6f99a56SLei Wen 	struct mmc *mmc = find_mmc_device(dev_num);
245e6f99a56SLei Wen 	lbaint_t blk = 0, blk_r = 0;
246d2d8afaeSJerry Huang 	int timeout = 1000;
247e6f99a56SLei Wen 
248e6f99a56SLei Wen 	if (!mmc)
249e6f99a56SLei Wen 		return -1;
250e6f99a56SLei Wen 
251e6f99a56SLei Wen 	if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size))
252e6f99a56SLei Wen 		printf("\n\nCaution! Your devices Erase group is 0x%x\n"
253ff8fef56SSascha Silbe 		       "The erase range would be change to "
254ff8fef56SSascha Silbe 		       "0x" LBAF "~0x" LBAF "\n\n",
255e6f99a56SLei Wen 		       mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1),
256e6f99a56SLei Wen 		       ((start + blkcnt + mmc->erase_grp_size)
257e6f99a56SLei Wen 		       & ~(mmc->erase_grp_size - 1)) - 1);
258e6f99a56SLei Wen 
259e6f99a56SLei Wen 	while (blk < blkcnt) {
260e6f99a56SLei Wen 		blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
261e6f99a56SLei Wen 			mmc->erase_grp_size : (blkcnt - blk);
262e6f99a56SLei Wen 		err = mmc_erase_t(mmc, start + blk, blk_r);
263e6f99a56SLei Wen 		if (err)
264e6f99a56SLei Wen 			break;
265e6f99a56SLei Wen 
266e6f99a56SLei Wen 		blk += blk_r;
267d2d8afaeSJerry Huang 
268d2d8afaeSJerry Huang 		/* Waiting for the ready status */
269d2d8afaeSJerry Huang 		if (mmc_send_status(mmc, timeout))
270d2d8afaeSJerry Huang 			return 0;
271e6f99a56SLei Wen 	}
272e6f99a56SLei Wen 
273e6f99a56SLei Wen 	return blk;
274e6f99a56SLei Wen }
275e6f99a56SLei Wen 
276272cc70bSAndy Fleming static ulong
277ff8fef56SSascha Silbe mmc_write_blocks(struct mmc *mmc, lbaint_t start, lbaint_t blkcnt, const void*src)
278272cc70bSAndy Fleming {
279272cc70bSAndy Fleming 	struct mmc_cmd cmd;
280272cc70bSAndy Fleming 	struct mmc_data data;
2815d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
282272cc70bSAndy Fleming 
283d2bf29e3SLei Wen 	if ((start + blkcnt) > mmc->block_dev.lba) {
284ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
285d2bf29e3SLei Wen 			start + blkcnt, mmc->block_dev.lba);
286d2bf29e3SLei Wen 		return 0;
287d2bf29e3SLei Wen 	}
288272cc70bSAndy Fleming 
289a586c0aaSRuud Commandeur 	if (blkcnt == 0)
290a586c0aaSRuud Commandeur 		return 0;
291a586c0aaSRuud Commandeur 	else if (blkcnt == 1)
292272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
293a586c0aaSRuud Commandeur 	else
294a586c0aaSRuud Commandeur 		cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
295272cc70bSAndy Fleming 
296272cc70bSAndy Fleming 	if (mmc->high_capacity)
297272cc70bSAndy Fleming 		cmd.cmdarg = start;
298272cc70bSAndy Fleming 	else
299def412b6SSteve Sakoman 		cmd.cmdarg = start * mmc->write_bl_len;
300272cc70bSAndy Fleming 
301272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
302272cc70bSAndy Fleming 
303272cc70bSAndy Fleming 	data.src = src;
304272cc70bSAndy Fleming 	data.blocks = blkcnt;
305def412b6SSteve Sakoman 	data.blocksize = mmc->write_bl_len;
306272cc70bSAndy Fleming 	data.flags = MMC_DATA_WRITE;
307272cc70bSAndy Fleming 
308def412b6SSteve Sakoman 	if (mmc_send_cmd(mmc, &cmd, &data)) {
309def412b6SSteve Sakoman 		printf("mmc write failed\n");
310def412b6SSteve Sakoman 		return 0;
311272cc70bSAndy Fleming 	}
312272cc70bSAndy Fleming 
313d52ebf10SThomas Chou 	/* SPI multiblock writes terminate using a special
314d52ebf10SThomas Chou 	 * token, not a STOP_TRANSMISSION request.
315d52ebf10SThomas Chou 	 */
316d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc) && blkcnt > 1) {
317272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
318272cc70bSAndy Fleming 		cmd.cmdarg = 0;
319272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1b;
320def412b6SSteve Sakoman 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
321def412b6SSteve Sakoman 			printf("mmc fail to send stop cmd\n");
322def412b6SSteve Sakoman 			return 0;
323272cc70bSAndy Fleming 		}
32493ad0d18SJan Kloetzke 	}
3255d4fc8d9SRaffaele Recalcati 
3265d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
32793ad0d18SJan Kloetzke 	if (mmc_send_status(mmc, timeout))
32893ad0d18SJan Kloetzke 		return 0;
3290158126eSLei Wen 
3300158126eSLei Wen 	return blkcnt;
3310158126eSLei Wen }
3320158126eSLei Wen 
3330158126eSLei Wen static ulong
334ff8fef56SSascha Silbe mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void*src)
3350158126eSLei Wen {
3360158126eSLei Wen 	lbaint_t cur, blocks_todo = blkcnt;
3370158126eSLei Wen 
338def412b6SSteve Sakoman 	struct mmc *mmc = find_mmc_device(dev_num);
3390158126eSLei Wen 	if (!mmc)
340def412b6SSteve Sakoman 		return 0;
3410158126eSLei Wen 
342def412b6SSteve Sakoman 	if (mmc_set_blocklen(mmc, mmc->write_bl_len))
343def412b6SSteve Sakoman 		return 0;
3440158126eSLei Wen 
3450158126eSLei Wen 	do {
3468feafcc4SJohn Rigby 		cur = (blocks_todo > mmc->b_max) ?  mmc->b_max : blocks_todo;
3470158126eSLei Wen 		if(mmc_write_blocks(mmc, start, cur, src) != cur)
348def412b6SSteve Sakoman 			return 0;
3490158126eSLei Wen 		blocks_todo -= cur;
3500158126eSLei Wen 		start += cur;
3510158126eSLei Wen 		src += cur * mmc->write_bl_len;
3520158126eSLei Wen 	} while (blocks_todo > 0);
353272cc70bSAndy Fleming 
354272cc70bSAndy Fleming 	return blkcnt;
355272cc70bSAndy Fleming }
356272cc70bSAndy Fleming 
357ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
358fdbb873eSKim Phillips 			   lbaint_t blkcnt)
359272cc70bSAndy Fleming {
360272cc70bSAndy Fleming 	struct mmc_cmd cmd;
361272cc70bSAndy Fleming 	struct mmc_data data;
362272cc70bSAndy Fleming 
3634a1a06bcSAlagu Sankar 	if (blkcnt > 1)
3644a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
3654a1a06bcSAlagu Sankar 	else
366272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
367272cc70bSAndy Fleming 
368272cc70bSAndy Fleming 	if (mmc->high_capacity)
3694a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
370272cc70bSAndy Fleming 	else
3714a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
372272cc70bSAndy Fleming 
373272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
374272cc70bSAndy Fleming 
375272cc70bSAndy Fleming 	data.dest = dst;
3764a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
377272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
378272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
379272cc70bSAndy Fleming 
3804a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
3814a1a06bcSAlagu Sankar 		return 0;
3824a1a06bcSAlagu Sankar 
3834a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
3844a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
3854a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
3864a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
3874a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
3884a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
3894a1a06bcSAlagu Sankar 			return 0;
3904a1a06bcSAlagu Sankar 		}
391272cc70bSAndy Fleming 	}
392272cc70bSAndy Fleming 
3934a1a06bcSAlagu Sankar 	return blkcnt;
394272cc70bSAndy Fleming }
395272cc70bSAndy Fleming 
396ff8fef56SSascha Silbe static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst)
397272cc70bSAndy Fleming {
3984a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
399272cc70bSAndy Fleming 
4004a1a06bcSAlagu Sankar 	if (blkcnt == 0)
4014a1a06bcSAlagu Sankar 		return 0;
4024a1a06bcSAlagu Sankar 
4034a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
404272cc70bSAndy Fleming 	if (!mmc)
405272cc70bSAndy Fleming 		return 0;
406272cc70bSAndy Fleming 
407d2bf29e3SLei Wen 	if ((start + blkcnt) > mmc->block_dev.lba) {
408ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
409d2bf29e3SLei Wen 			start + blkcnt, mmc->block_dev.lba);
410d2bf29e3SLei Wen 		return 0;
411d2bf29e3SLei Wen 	}
412272cc70bSAndy Fleming 
4134a1a06bcSAlagu Sankar 	if (mmc_set_blocklen(mmc, mmc->read_bl_len))
414272cc70bSAndy Fleming 		return 0;
415272cc70bSAndy Fleming 
4164a1a06bcSAlagu Sankar 	do {
4178feafcc4SJohn Rigby 		cur = (blocks_todo > mmc->b_max) ?  mmc->b_max : blocks_todo;
4184a1a06bcSAlagu Sankar 		if(mmc_read_blocks(mmc, dst, start, cur) != cur)
4194a1a06bcSAlagu Sankar 			return 0;
4204a1a06bcSAlagu Sankar 		blocks_todo -= cur;
4214a1a06bcSAlagu Sankar 		start += cur;
4224a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
4234a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
424272cc70bSAndy Fleming 
425272cc70bSAndy Fleming 	return blkcnt;
426272cc70bSAndy Fleming }
427272cc70bSAndy Fleming 
428fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
429272cc70bSAndy Fleming {
430272cc70bSAndy Fleming 	struct mmc_cmd cmd;
431272cc70bSAndy Fleming 	int err;
432272cc70bSAndy Fleming 
433272cc70bSAndy Fleming 	udelay(1000);
434272cc70bSAndy Fleming 
435272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
436272cc70bSAndy Fleming 	cmd.cmdarg = 0;
437272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
438272cc70bSAndy Fleming 
439272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
440272cc70bSAndy Fleming 
441272cc70bSAndy Fleming 	if (err)
442272cc70bSAndy Fleming 		return err;
443272cc70bSAndy Fleming 
444272cc70bSAndy Fleming 	udelay(2000);
445272cc70bSAndy Fleming 
446272cc70bSAndy Fleming 	return 0;
447272cc70bSAndy Fleming }
448272cc70bSAndy Fleming 
449fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
450272cc70bSAndy Fleming {
451272cc70bSAndy Fleming 	int timeout = 1000;
452272cc70bSAndy Fleming 	int err;
453272cc70bSAndy Fleming 	struct mmc_cmd cmd;
454272cc70bSAndy Fleming 
455272cc70bSAndy Fleming 	do {
456272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
457272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
458272cc70bSAndy Fleming 		cmd.cmdarg = 0;
459272cc70bSAndy Fleming 
460272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
461272cc70bSAndy Fleming 
462272cc70bSAndy Fleming 		if (err)
463272cc70bSAndy Fleming 			return err;
464272cc70bSAndy Fleming 
465272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
466272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
467250de12bSStefano Babic 
468250de12bSStefano Babic 		/*
469250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
470250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
471250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
472250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
473250de12bSStefano Babic 		 * specified.
474250de12bSStefano Babic 		 */
475d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
476d52ebf10SThomas Chou 			(mmc->voltages & 0xff8000);
477272cc70bSAndy Fleming 
478272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
479272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
480272cc70bSAndy Fleming 
481272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
482272cc70bSAndy Fleming 
483272cc70bSAndy Fleming 		if (err)
484272cc70bSAndy Fleming 			return err;
485272cc70bSAndy Fleming 
486272cc70bSAndy Fleming 		udelay(1000);
487272cc70bSAndy Fleming 	} while ((!(cmd.response[0] & OCR_BUSY)) && timeout--);
488272cc70bSAndy Fleming 
489272cc70bSAndy Fleming 	if (timeout <= 0)
490272cc70bSAndy Fleming 		return UNUSABLE_ERR;
491272cc70bSAndy Fleming 
492272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
493272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
494272cc70bSAndy Fleming 
495d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
496d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
497d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
498d52ebf10SThomas Chou 		cmd.cmdarg = 0;
499d52ebf10SThomas Chou 
500d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
501d52ebf10SThomas Chou 
502d52ebf10SThomas Chou 		if (err)
503d52ebf10SThomas Chou 			return err;
504d52ebf10SThomas Chou 	}
505d52ebf10SThomas Chou 
506998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
507272cc70bSAndy Fleming 
508272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
509272cc70bSAndy Fleming 	mmc->rca = 0;
510272cc70bSAndy Fleming 
511272cc70bSAndy Fleming 	return 0;
512272cc70bSAndy Fleming }
513272cc70bSAndy Fleming 
514e9550449SChe-Liang Chiou /* We pass in the cmd since otherwise the init seems to fail */
515e9550449SChe-Liang Chiou static int mmc_send_op_cond_iter(struct mmc *mmc, struct mmc_cmd *cmd,
516e9550449SChe-Liang Chiou 		int use_arg)
517272cc70bSAndy Fleming {
518272cc70bSAndy Fleming 	int err;
519272cc70bSAndy Fleming 
520e9550449SChe-Liang Chiou 	cmd->cmdidx = MMC_CMD_SEND_OP_COND;
521e9550449SChe-Liang Chiou 	cmd->resp_type = MMC_RSP_R3;
522e9550449SChe-Liang Chiou 	cmd->cmdarg = 0;
523e9550449SChe-Liang Chiou 	if (use_arg && !mmc_host_is_spi(mmc)) {
524e9550449SChe-Liang Chiou 		cmd->cmdarg =
525e9550449SChe-Liang Chiou 			(mmc->voltages &
526e9550449SChe-Liang Chiou 			(mmc->op_cond_response & OCR_VOLTAGE_MASK)) |
527e9550449SChe-Liang Chiou 			(mmc->op_cond_response & OCR_ACCESS_MODE);
528e9550449SChe-Liang Chiou 
529e9550449SChe-Liang Chiou 		if (mmc->host_caps & MMC_MODE_HC)
530e9550449SChe-Liang Chiou 			cmd->cmdarg |= OCR_HCS;
531e9550449SChe-Liang Chiou 	}
532e9550449SChe-Liang Chiou 	err = mmc_send_cmd(mmc, cmd, NULL);
533e9550449SChe-Liang Chiou 	if (err)
534e9550449SChe-Liang Chiou 		return err;
535e9550449SChe-Liang Chiou 	mmc->op_cond_response = cmd->response[0];
536e9550449SChe-Liang Chiou 	return 0;
537e9550449SChe-Liang Chiou }
538e9550449SChe-Liang Chiou 
539e9550449SChe-Liang Chiou int mmc_send_op_cond(struct mmc *mmc)
540e9550449SChe-Liang Chiou {
541e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
542e9550449SChe-Liang Chiou 	int err, i;
543e9550449SChe-Liang Chiou 
544272cc70bSAndy Fleming 	/* Some cards seem to need this */
545272cc70bSAndy Fleming 	mmc_go_idle(mmc);
546272cc70bSAndy Fleming 
54731cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
548e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 1;
549e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
550e9550449SChe-Liang Chiou 		err = mmc_send_op_cond_iter(mmc, &cmd, i != 0);
55131cacbabSRaffaele Recalcati 		if (err)
55231cacbabSRaffaele Recalcati 			return err;
55331cacbabSRaffaele Recalcati 
554e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
555e9550449SChe-Liang Chiou 		if (mmc->op_cond_response & OCR_BUSY)
556e9550449SChe-Liang Chiou 			return 0;
557e9550449SChe-Liang Chiou 	}
558e9550449SChe-Liang Chiou 	return IN_PROGRESS;
559e9550449SChe-Liang Chiou }
56031cacbabSRaffaele Recalcati 
561e9550449SChe-Liang Chiou int mmc_complete_op_cond(struct mmc *mmc)
562e9550449SChe-Liang Chiou {
563e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
564e9550449SChe-Liang Chiou 	int timeout = 1000;
565e9550449SChe-Liang Chiou 	uint start;
566e9550449SChe-Liang Chiou 	int err;
567e9550449SChe-Liang Chiou 
568e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
569e9550449SChe-Liang Chiou 	start = get_timer(0);
570272cc70bSAndy Fleming 	do {
571e9550449SChe-Liang Chiou 		err = mmc_send_op_cond_iter(mmc, &cmd, 1);
572272cc70bSAndy Fleming 		if (err)
573272cc70bSAndy Fleming 			return err;
574e9550449SChe-Liang Chiou 		if (get_timer(start) > timeout)
575272cc70bSAndy Fleming 			return UNUSABLE_ERR;
576e9550449SChe-Liang Chiou 		udelay(100);
577e9550449SChe-Liang Chiou 	} while (!(mmc->op_cond_response & OCR_BUSY));
578272cc70bSAndy Fleming 
579d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
580d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
581d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
582d52ebf10SThomas Chou 		cmd.cmdarg = 0;
583d52ebf10SThomas Chou 
584d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
585d52ebf10SThomas Chou 
586d52ebf10SThomas Chou 		if (err)
587d52ebf10SThomas Chou 			return err;
588d52ebf10SThomas Chou 	}
589d52ebf10SThomas Chou 
590272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
591998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
592272cc70bSAndy Fleming 
593272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
594272cc70bSAndy Fleming 	mmc->rca = 0;
595272cc70bSAndy Fleming 
596272cc70bSAndy Fleming 	return 0;
597272cc70bSAndy Fleming }
598272cc70bSAndy Fleming 
599272cc70bSAndy Fleming 
600fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
601272cc70bSAndy Fleming {
602272cc70bSAndy Fleming 	struct mmc_cmd cmd;
603272cc70bSAndy Fleming 	struct mmc_data data;
604272cc70bSAndy Fleming 	int err;
605272cc70bSAndy Fleming 
606272cc70bSAndy Fleming 	/* Get the Card Status Register */
607272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
608272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
609272cc70bSAndy Fleming 	cmd.cmdarg = 0;
610272cc70bSAndy Fleming 
611cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
612272cc70bSAndy Fleming 	data.blocks = 1;
6138bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
614272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
615272cc70bSAndy Fleming 
616272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
617272cc70bSAndy Fleming 
618272cc70bSAndy Fleming 	return err;
619272cc70bSAndy Fleming }
620272cc70bSAndy Fleming 
621272cc70bSAndy Fleming 
622fdbb873eSKim Phillips static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
623272cc70bSAndy Fleming {
624272cc70bSAndy Fleming 	struct mmc_cmd cmd;
6255d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
6265d4fc8d9SRaffaele Recalcati 	int ret;
627272cc70bSAndy Fleming 
628272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
629272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
630272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
631272cc70bSAndy Fleming 				 (index << 16) |
632272cc70bSAndy Fleming 				 (value << 8);
633272cc70bSAndy Fleming 
6345d4fc8d9SRaffaele Recalcati 	ret = mmc_send_cmd(mmc, &cmd, NULL);
6355d4fc8d9SRaffaele Recalcati 
6365d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
63793ad0d18SJan Kloetzke 	if (!ret)
63893ad0d18SJan Kloetzke 		ret = mmc_send_status(mmc, timeout);
6395d4fc8d9SRaffaele Recalcati 
6405d4fc8d9SRaffaele Recalcati 	return ret;
6415d4fc8d9SRaffaele Recalcati 
642272cc70bSAndy Fleming }
643272cc70bSAndy Fleming 
644fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
645272cc70bSAndy Fleming {
6468bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
647272cc70bSAndy Fleming 	char cardtype;
648272cc70bSAndy Fleming 	int err;
649272cc70bSAndy Fleming 
650272cc70bSAndy Fleming 	mmc->card_caps = 0;
651272cc70bSAndy Fleming 
652d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
653d52ebf10SThomas Chou 		return 0;
654d52ebf10SThomas Chou 
655272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
656272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
657272cc70bSAndy Fleming 		return 0;
658272cc70bSAndy Fleming 
659272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
660272cc70bSAndy Fleming 
661272cc70bSAndy Fleming 	if (err)
662272cc70bSAndy Fleming 		return err;
663272cc70bSAndy Fleming 
6640560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
665272cc70bSAndy Fleming 
666272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
667272cc70bSAndy Fleming 
668272cc70bSAndy Fleming 	if (err)
669272cc70bSAndy Fleming 		return err;
670272cc70bSAndy Fleming 
671272cc70bSAndy Fleming 	/* Now check to see that it worked */
672272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
673272cc70bSAndy Fleming 
674272cc70bSAndy Fleming 	if (err)
675272cc70bSAndy Fleming 		return err;
676272cc70bSAndy Fleming 
677272cc70bSAndy Fleming 	/* No high-speed support */
6780560db18SLei Wen 	if (!ext_csd[EXT_CSD_HS_TIMING])
679272cc70bSAndy Fleming 		return 0;
680272cc70bSAndy Fleming 
681272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
682272cc70bSAndy Fleming 	if (cardtype & MMC_HS_52MHZ)
683272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
684272cc70bSAndy Fleming 	else
685272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
686272cc70bSAndy Fleming 
687272cc70bSAndy Fleming 	return 0;
688272cc70bSAndy Fleming }
689272cc70bSAndy Fleming 
690f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
691f866a46dSStephen Warren {
692f866a46dSStephen Warren 	switch (part_num) {
693f866a46dSStephen Warren 	case 0:
694f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
695f866a46dSStephen Warren 		break;
696f866a46dSStephen Warren 	case 1:
697f866a46dSStephen Warren 	case 2:
698f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
699f866a46dSStephen Warren 		break;
700f866a46dSStephen Warren 	case 3:
701f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
702f866a46dSStephen Warren 		break;
703f866a46dSStephen Warren 	case 4:
704f866a46dSStephen Warren 	case 5:
705f866a46dSStephen Warren 	case 6:
706f866a46dSStephen Warren 	case 7:
707f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
708f866a46dSStephen Warren 		break;
709f866a46dSStephen Warren 	default:
710f866a46dSStephen Warren 		return -1;
711f866a46dSStephen Warren 	}
712f866a46dSStephen Warren 
713f866a46dSStephen Warren 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
714f866a46dSStephen Warren 
715f866a46dSStephen Warren 	return 0;
716f866a46dSStephen Warren }
717f866a46dSStephen Warren 
718bc897b1dSLei Wen int mmc_switch_part(int dev_num, unsigned int part_num)
719bc897b1dSLei Wen {
720bc897b1dSLei Wen 	struct mmc *mmc = find_mmc_device(dev_num);
721f866a46dSStephen Warren 	int ret;
722bc897b1dSLei Wen 
723bc897b1dSLei Wen 	if (!mmc)
724bc897b1dSLei Wen 		return -1;
725bc897b1dSLei Wen 
726f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
727bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
728bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
729f866a46dSStephen Warren 	if (ret)
730f866a46dSStephen Warren 		return ret;
731f866a46dSStephen Warren 
732f866a46dSStephen Warren 	return mmc_set_capacity(mmc, part_num);
733bc897b1dSLei Wen }
734bc897b1dSLei Wen 
73548972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
73648972d90SThierry Reding {
73748972d90SThierry Reding 	int cd;
73848972d90SThierry Reding 
73948972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
74048972d90SThierry Reding 
741d4e1da4eSPeter Korsgaard 	if (cd < 0) {
742d4e1da4eSPeter Korsgaard 		if (mmc->getcd)
74348972d90SThierry Reding 			cd = mmc->getcd(mmc);
744d4e1da4eSPeter Korsgaard 		else
745d4e1da4eSPeter Korsgaard 			cd = 1;
746d4e1da4eSPeter Korsgaard 	}
74748972d90SThierry Reding 
74848972d90SThierry Reding 	return cd;
74948972d90SThierry Reding }
75048972d90SThierry Reding 
751fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
752272cc70bSAndy Fleming {
753272cc70bSAndy Fleming 	struct mmc_cmd cmd;
754272cc70bSAndy Fleming 	struct mmc_data data;
755272cc70bSAndy Fleming 
756272cc70bSAndy Fleming 	/* Switch the frequency */
757272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
758272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
759272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
760272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
761272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
762272cc70bSAndy Fleming 
763272cc70bSAndy Fleming 	data.dest = (char *)resp;
764272cc70bSAndy Fleming 	data.blocksize = 64;
765272cc70bSAndy Fleming 	data.blocks = 1;
766272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
767272cc70bSAndy Fleming 
768272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
769272cc70bSAndy Fleming }
770272cc70bSAndy Fleming 
771272cc70bSAndy Fleming 
772fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
773272cc70bSAndy Fleming {
774272cc70bSAndy Fleming 	int err;
775272cc70bSAndy Fleming 	struct mmc_cmd cmd;
776f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
777f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
778272cc70bSAndy Fleming 	struct mmc_data data;
779272cc70bSAndy Fleming 	int timeout;
780272cc70bSAndy Fleming 
781272cc70bSAndy Fleming 	mmc->card_caps = 0;
782272cc70bSAndy Fleming 
783d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
784d52ebf10SThomas Chou 		return 0;
785d52ebf10SThomas Chou 
786272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
787272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
788272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
789272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
790272cc70bSAndy Fleming 
791272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
792272cc70bSAndy Fleming 
793272cc70bSAndy Fleming 	if (err)
794272cc70bSAndy Fleming 		return err;
795272cc70bSAndy Fleming 
796272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
797272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
798272cc70bSAndy Fleming 	cmd.cmdarg = 0;
799272cc70bSAndy Fleming 
800272cc70bSAndy Fleming 	timeout = 3;
801272cc70bSAndy Fleming 
802272cc70bSAndy Fleming retry_scr:
803f781dd38SAnton staaf 	data.dest = (char *)scr;
804272cc70bSAndy Fleming 	data.blocksize = 8;
805272cc70bSAndy Fleming 	data.blocks = 1;
806272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
807272cc70bSAndy Fleming 
808272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
809272cc70bSAndy Fleming 
810272cc70bSAndy Fleming 	if (err) {
811272cc70bSAndy Fleming 		if (timeout--)
812272cc70bSAndy Fleming 			goto retry_scr;
813272cc70bSAndy Fleming 
814272cc70bSAndy Fleming 		return err;
815272cc70bSAndy Fleming 	}
816272cc70bSAndy Fleming 
8174e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
8184e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
819272cc70bSAndy Fleming 
820272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
821272cc70bSAndy Fleming 		case 0:
822272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
823272cc70bSAndy Fleming 			break;
824272cc70bSAndy Fleming 		case 1:
825272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_10;
826272cc70bSAndy Fleming 			break;
827272cc70bSAndy Fleming 		case 2:
828272cc70bSAndy Fleming 			mmc->version = SD_VERSION_2;
8291741c64dSJaehoon Chung 			if ((mmc->scr[0] >> 15) & 0x1)
8301741c64dSJaehoon Chung 				mmc->version = SD_VERSION_3;
831272cc70bSAndy Fleming 			break;
832272cc70bSAndy Fleming 		default:
833272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
834272cc70bSAndy Fleming 			break;
835272cc70bSAndy Fleming 	}
836272cc70bSAndy Fleming 
837b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
838b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
839b44c7083SAlagu Sankar 
840272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
841272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
842272cc70bSAndy Fleming 		return 0;
843272cc70bSAndy Fleming 
844272cc70bSAndy Fleming 	timeout = 4;
845272cc70bSAndy Fleming 	while (timeout--) {
846272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
847f781dd38SAnton staaf 				(u8 *)switch_status);
848272cc70bSAndy Fleming 
849272cc70bSAndy Fleming 		if (err)
850272cc70bSAndy Fleming 			return err;
851272cc70bSAndy Fleming 
852272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
8534e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
854272cc70bSAndy Fleming 			break;
855272cc70bSAndy Fleming 	}
856272cc70bSAndy Fleming 
857272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
8584e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
859272cc70bSAndy Fleming 		return 0;
860272cc70bSAndy Fleming 
8612c3fbf4cSMacpaul Lin 	/*
8622c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
8632c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
8642c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
8652c3fbf4cSMacpaul Lin 	 * mode between the host.
8662c3fbf4cSMacpaul Lin 	 */
8672c3fbf4cSMacpaul Lin 	if (!((mmc->host_caps & MMC_MODE_HS_52MHz) &&
8682c3fbf4cSMacpaul Lin 		(mmc->host_caps & MMC_MODE_HS)))
8692c3fbf4cSMacpaul Lin 		return 0;
8702c3fbf4cSMacpaul Lin 
871f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
872272cc70bSAndy Fleming 
873272cc70bSAndy Fleming 	if (err)
874272cc70bSAndy Fleming 		return err;
875272cc70bSAndy Fleming 
8764e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
877272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
878272cc70bSAndy Fleming 
879272cc70bSAndy Fleming 	return 0;
880272cc70bSAndy Fleming }
881272cc70bSAndy Fleming 
882272cc70bSAndy Fleming /* frequency bases */
883272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
8845f837c2cSMike Frysinger static const int fbase[] = {
885272cc70bSAndy Fleming 	10000,
886272cc70bSAndy Fleming 	100000,
887272cc70bSAndy Fleming 	1000000,
888272cc70bSAndy Fleming 	10000000,
889272cc70bSAndy Fleming };
890272cc70bSAndy Fleming 
891272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
892272cc70bSAndy Fleming  * to platforms without floating point.
893272cc70bSAndy Fleming  */
8945f837c2cSMike Frysinger static const int multipliers[] = {
895272cc70bSAndy Fleming 	0,	/* reserved */
896272cc70bSAndy Fleming 	10,
897272cc70bSAndy Fleming 	12,
898272cc70bSAndy Fleming 	13,
899272cc70bSAndy Fleming 	15,
900272cc70bSAndy Fleming 	20,
901272cc70bSAndy Fleming 	25,
902272cc70bSAndy Fleming 	30,
903272cc70bSAndy Fleming 	35,
904272cc70bSAndy Fleming 	40,
905272cc70bSAndy Fleming 	45,
906272cc70bSAndy Fleming 	50,
907272cc70bSAndy Fleming 	55,
908272cc70bSAndy Fleming 	60,
909272cc70bSAndy Fleming 	70,
910272cc70bSAndy Fleming 	80,
911272cc70bSAndy Fleming };
912272cc70bSAndy Fleming 
913fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
914272cc70bSAndy Fleming {
915272cc70bSAndy Fleming 	mmc->set_ios(mmc);
916272cc70bSAndy Fleming }
917272cc70bSAndy Fleming 
918272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
919272cc70bSAndy Fleming {
920272cc70bSAndy Fleming 	if (clock > mmc->f_max)
921272cc70bSAndy Fleming 		clock = mmc->f_max;
922272cc70bSAndy Fleming 
923272cc70bSAndy Fleming 	if (clock < mmc->f_min)
924272cc70bSAndy Fleming 		clock = mmc->f_min;
925272cc70bSAndy Fleming 
926272cc70bSAndy Fleming 	mmc->clock = clock;
927272cc70bSAndy Fleming 
928272cc70bSAndy Fleming 	mmc_set_ios(mmc);
929272cc70bSAndy Fleming }
930272cc70bSAndy Fleming 
931fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width)
932272cc70bSAndy Fleming {
933272cc70bSAndy Fleming 	mmc->bus_width = width;
934272cc70bSAndy Fleming 
935272cc70bSAndy Fleming 	mmc_set_ios(mmc);
936272cc70bSAndy Fleming }
937272cc70bSAndy Fleming 
938fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
939272cc70bSAndy Fleming {
940f866a46dSStephen Warren 	int err, i;
941272cc70bSAndy Fleming 	uint mult, freq;
942639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
943272cc70bSAndy Fleming 	struct mmc_cmd cmd;
9448bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
9458bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
9465d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
947272cc70bSAndy Fleming 
948d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
949d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
950d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
951d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
952d52ebf10SThomas Chou 		cmd.cmdarg = 1;
953d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
954d52ebf10SThomas Chou 
955d52ebf10SThomas Chou 		if (err)
956d52ebf10SThomas Chou 			return err;
957d52ebf10SThomas Chou 	}
958d52ebf10SThomas Chou #endif
959d52ebf10SThomas Chou 
960272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
961d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
962d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
963272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
964272cc70bSAndy Fleming 	cmd.cmdarg = 0;
965272cc70bSAndy Fleming 
966272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
967272cc70bSAndy Fleming 
968272cc70bSAndy Fleming 	if (err)
969272cc70bSAndy Fleming 		return err;
970272cc70bSAndy Fleming 
971272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
972272cc70bSAndy Fleming 
973272cc70bSAndy Fleming 	/*
974272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
975272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
976272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
977272cc70bSAndy Fleming 	 */
978d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
979272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
980272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
981272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
982272cc70bSAndy Fleming 
983272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
984272cc70bSAndy Fleming 
985272cc70bSAndy Fleming 		if (err)
986272cc70bSAndy Fleming 			return err;
987272cc70bSAndy Fleming 
988272cc70bSAndy Fleming 		if (IS_SD(mmc))
989998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
990d52ebf10SThomas Chou 	}
991272cc70bSAndy Fleming 
992272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
993272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
994272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
995272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
996272cc70bSAndy Fleming 
997272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
998272cc70bSAndy Fleming 
9995d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
10005d4fc8d9SRaffaele Recalcati 	mmc_send_status(mmc, timeout);
10015d4fc8d9SRaffaele Recalcati 
1002272cc70bSAndy Fleming 	if (err)
1003272cc70bSAndy Fleming 		return err;
1004272cc70bSAndy Fleming 
1005998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1006998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1007998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1008998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1009272cc70bSAndy Fleming 
1010272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
10110b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1012272cc70bSAndy Fleming 
1013272cc70bSAndy Fleming 		switch (version) {
1014272cc70bSAndy Fleming 			case 0:
1015272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
1016272cc70bSAndy Fleming 				break;
1017272cc70bSAndy Fleming 			case 1:
1018272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_4;
1019272cc70bSAndy Fleming 				break;
1020272cc70bSAndy Fleming 			case 2:
1021272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_2_2;
1022272cc70bSAndy Fleming 				break;
1023272cc70bSAndy Fleming 			case 3:
1024272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_3;
1025272cc70bSAndy Fleming 				break;
1026272cc70bSAndy Fleming 			case 4:
1027272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_4;
1028272cc70bSAndy Fleming 				break;
1029272cc70bSAndy Fleming 			default:
1030272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
1031272cc70bSAndy Fleming 				break;
1032272cc70bSAndy Fleming 		}
1033272cc70bSAndy Fleming 	}
1034272cc70bSAndy Fleming 
1035272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
10360b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
10370b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1038272cc70bSAndy Fleming 
1039272cc70bSAndy Fleming 	mmc->tran_speed = freq * mult;
1040272cc70bSAndy Fleming 
1041998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1042272cc70bSAndy Fleming 
1043272cc70bSAndy Fleming 	if (IS_SD(mmc))
1044272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1045272cc70bSAndy Fleming 	else
1046998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1047272cc70bSAndy Fleming 
1048272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1049272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1050272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1051272cc70bSAndy Fleming 		cmult = 8;
1052272cc70bSAndy Fleming 	} else {
1053272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1054272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1055272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1056272cc70bSAndy Fleming 	}
1057272cc70bSAndy Fleming 
1058f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1059f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1060f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1061f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1062f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1063f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1064272cc70bSAndy Fleming 
10658bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
10668bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1067272cc70bSAndy Fleming 
10688bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
10698bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1070272cc70bSAndy Fleming 
1071272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1072d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1073272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1074fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1075272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1076272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1077272cc70bSAndy Fleming 
1078272cc70bSAndy Fleming 		if (err)
1079272cc70bSAndy Fleming 			return err;
1080d52ebf10SThomas Chou 	}
1081272cc70bSAndy Fleming 
1082e6f99a56SLei Wen 	/*
1083e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1084e6f99a56SLei Wen 	 */
1085e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1086bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1087d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
1088d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
1089d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
1090fdbb873eSKim Phillips 		if (!err && (ext_csd[EXT_CSD_REV] >= 2)) {
1091639b7827SYoshihiro Shimoda 			/*
1092639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
1093639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
1094639b7827SYoshihiro Shimoda 			 * than 2GB
1095639b7827SYoshihiro Shimoda 			 */
10960560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
10970560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
10980560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
10990560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
11008bfa195eSSimon Glass 			capacity *= MMC_MAX_BLOCK_LEN;
1101b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
1102f866a46dSStephen Warren 				mmc->capacity_user = capacity;
1103d23e2c09SSukumar Ghorai 		}
1104bc897b1dSLei Wen 
110564f4a619SJaehoon Chung 		switch (ext_csd[EXT_CSD_REV]) {
110664f4a619SJaehoon Chung 		case 1:
110764f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_1;
110864f4a619SJaehoon Chung 			break;
110964f4a619SJaehoon Chung 		case 2:
111064f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_2;
111164f4a619SJaehoon Chung 			break;
111264f4a619SJaehoon Chung 		case 3:
111364f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_3;
111464f4a619SJaehoon Chung 			break;
111564f4a619SJaehoon Chung 		case 5:
111664f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_41;
111764f4a619SJaehoon Chung 			break;
111864f4a619SJaehoon Chung 		case 6:
111964f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_5;
112064f4a619SJaehoon Chung 			break;
112164f4a619SJaehoon Chung 		}
112264f4a619SJaehoon Chung 
1123e6f99a56SLei Wen 		/*
1124e6f99a56SLei Wen 		 * Check whether GROUP_DEF is set, if yes, read out
1125e6f99a56SLei Wen 		 * group size from ext_csd directly, or calculate
1126e6f99a56SLei Wen 		 * the group size from the csd value.
1127e6f99a56SLei Wen 		 */
11288bfa195eSSimon Glass 		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF]) {
11290560db18SLei Wen 			mmc->erase_grp_size =
11308bfa195eSSimon Glass 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] *
11318bfa195eSSimon Glass 					MMC_MAX_BLOCK_LEN * 1024;
11328bfa195eSSimon Glass 		} else {
1133e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
1134e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1135e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1136e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
1137e6f99a56SLei Wen 				* (erase_gmul + 1);
1138e6f99a56SLei Wen 		}
1139e6f99a56SLei Wen 
1140bc897b1dSLei Wen 		/* store the partition info of emmc */
11418948ea83SStephen Warren 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
11428948ea83SStephen Warren 		    ext_csd[EXT_CSD_BOOT_MULT])
11430560db18SLei Wen 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
1144f866a46dSStephen Warren 
1145f866a46dSStephen Warren 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
1146f866a46dSStephen Warren 
1147f866a46dSStephen Warren 		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
1148f866a46dSStephen Warren 
1149f866a46dSStephen Warren 		for (i = 0; i < 4; i++) {
1150f866a46dSStephen Warren 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
1151f866a46dSStephen Warren 			mmc->capacity_gp[i] = (ext_csd[idx + 2] << 16) +
1152f866a46dSStephen Warren 				(ext_csd[idx + 1] << 8) + ext_csd[idx];
1153f866a46dSStephen Warren 			mmc->capacity_gp[i] *=
1154f866a46dSStephen Warren 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1155f866a46dSStephen Warren 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1156d23e2c09SSukumar Ghorai 		}
1157f866a46dSStephen Warren 	}
1158f866a46dSStephen Warren 
1159f866a46dSStephen Warren 	err = mmc_set_capacity(mmc, mmc->part_num);
1160f866a46dSStephen Warren 	if (err)
1161f866a46dSStephen Warren 		return err;
1162d23e2c09SSukumar Ghorai 
1163272cc70bSAndy Fleming 	if (IS_SD(mmc))
1164272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1165272cc70bSAndy Fleming 	else
1166272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1167272cc70bSAndy Fleming 
1168272cc70bSAndy Fleming 	if (err)
1169272cc70bSAndy Fleming 		return err;
1170272cc70bSAndy Fleming 
1171272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
1172272cc70bSAndy Fleming 	mmc->card_caps &= mmc->host_caps;
1173272cc70bSAndy Fleming 
1174272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1175272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1176272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1177272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1178272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1179272cc70bSAndy Fleming 
1180272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1181272cc70bSAndy Fleming 			if (err)
1182272cc70bSAndy Fleming 				return err;
1183272cc70bSAndy Fleming 
1184272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1185272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1186272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1187272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1188272cc70bSAndy Fleming 			if (err)
1189272cc70bSAndy Fleming 				return err;
1190272cc70bSAndy Fleming 
1191272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1192272cc70bSAndy Fleming 		}
1193272cc70bSAndy Fleming 
1194272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
1195ad5fd922SJaehoon Chung 			mmc->tran_speed = 50000000;
1196272cc70bSAndy Fleming 		else
1197ad5fd922SJaehoon Chung 			mmc->tran_speed = 25000000;
1198272cc70bSAndy Fleming 	} else {
11997798f6dbSAndy Fleming 		int idx;
12007798f6dbSAndy Fleming 
12017798f6dbSAndy Fleming 		/* An array of possible bus widths in order of preference */
12027798f6dbSAndy Fleming 		static unsigned ext_csd_bits[] = {
12037798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_8,
12047798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_4,
12057798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_1,
12067798f6dbSAndy Fleming 		};
12077798f6dbSAndy Fleming 
12087798f6dbSAndy Fleming 		/* An array to map CSD bus widths to host cap bits */
12097798f6dbSAndy Fleming 		static unsigned ext_to_hostcaps[] = {
12107798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
12117798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
12127798f6dbSAndy Fleming 		};
12137798f6dbSAndy Fleming 
12147798f6dbSAndy Fleming 		/* An array to map chosen bus width to an integer */
12157798f6dbSAndy Fleming 		static unsigned widths[] = {
12167798f6dbSAndy Fleming 			8, 4, 1,
12177798f6dbSAndy Fleming 		};
12187798f6dbSAndy Fleming 
12197798f6dbSAndy Fleming 		for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
12207798f6dbSAndy Fleming 			unsigned int extw = ext_csd_bits[idx];
12217798f6dbSAndy Fleming 
12227798f6dbSAndy Fleming 			/*
12237798f6dbSAndy Fleming 			 * Check to make sure the controller supports
12247798f6dbSAndy Fleming 			 * this bus width, if it's more than 1
12257798f6dbSAndy Fleming 			 */
12267798f6dbSAndy Fleming 			if (extw != EXT_CSD_BUS_WIDTH_1 &&
12277798f6dbSAndy Fleming 					!(mmc->host_caps & ext_to_hostcaps[extw]))
12287798f6dbSAndy Fleming 				continue;
12297798f6dbSAndy Fleming 
1230272cc70bSAndy Fleming 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
12317798f6dbSAndy Fleming 					EXT_CSD_BUS_WIDTH, extw);
1232272cc70bSAndy Fleming 
1233272cc70bSAndy Fleming 			if (err)
12344137894eSLei Wen 				continue;
1235272cc70bSAndy Fleming 
12367798f6dbSAndy Fleming 			mmc_set_bus_width(mmc, widths[idx]);
1237272cc70bSAndy Fleming 
12384137894eSLei Wen 			err = mmc_send_ext_csd(mmc, test_csd);
12394137894eSLei Wen 			if (!err && ext_csd[EXT_CSD_PARTITIONING_SUPPORT] \
12404137894eSLei Wen 				    == test_csd[EXT_CSD_PARTITIONING_SUPPORT]
12414137894eSLei Wen 				 && ext_csd[EXT_CSD_ERASE_GROUP_DEF] \
12424137894eSLei Wen 				    == test_csd[EXT_CSD_ERASE_GROUP_DEF] \
12434137894eSLei Wen 				 && ext_csd[EXT_CSD_REV] \
12444137894eSLei Wen 				    == test_csd[EXT_CSD_REV]
12454137894eSLei Wen 				 && ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] \
12464137894eSLei Wen 				    == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
12474137894eSLei Wen 				 && memcmp(&ext_csd[EXT_CSD_SEC_CNT], \
12484137894eSLei Wen 					&test_csd[EXT_CSD_SEC_CNT], 4) == 0) {
1249272cc70bSAndy Fleming 
12507798f6dbSAndy Fleming 				mmc->card_caps |= ext_to_hostcaps[extw];
12514137894eSLei Wen 				break;
12524137894eSLei Wen 			}
1253272cc70bSAndy Fleming 		}
1254272cc70bSAndy Fleming 
1255272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS) {
1256272cc70bSAndy Fleming 			if (mmc->card_caps & MMC_MODE_HS_52MHz)
1257ad5fd922SJaehoon Chung 				mmc->tran_speed = 52000000;
1258272cc70bSAndy Fleming 			else
1259ad5fd922SJaehoon Chung 				mmc->tran_speed = 26000000;
1260272cc70bSAndy Fleming 		}
1261ad5fd922SJaehoon Chung 	}
1262ad5fd922SJaehoon Chung 
1263ad5fd922SJaehoon Chung 	mmc_set_clock(mmc, mmc->tran_speed);
1264272cc70bSAndy Fleming 
1265272cc70bSAndy Fleming 	/* fill in device description */
1266272cc70bSAndy Fleming 	mmc->block_dev.lun = 0;
1267272cc70bSAndy Fleming 	mmc->block_dev.type = 0;
1268272cc70bSAndy Fleming 	mmc->block_dev.blksz = mmc->read_bl_len;
12690472fbfdSEgbert Eich 	mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz);
12709b1f942cSRabin Vincent 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
1271babce5f6STaylor Hutt 	sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x",
1272babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1273babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1274babce5f6STaylor Hutt 	sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
12750b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1276babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1277babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1278babce5f6STaylor Hutt 	sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1279babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
1280122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1281272cc70bSAndy Fleming 	init_part(&mmc->block_dev);
1282122efd43SMikhail Kshevetskiy #endif
1283272cc70bSAndy Fleming 
1284272cc70bSAndy Fleming 	return 0;
1285272cc70bSAndy Fleming }
1286272cc70bSAndy Fleming 
1287fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1288272cc70bSAndy Fleming {
1289272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1290272cc70bSAndy Fleming 	int err;
1291272cc70bSAndy Fleming 
1292272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1293272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
1294272cc70bSAndy Fleming 	cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa;
1295272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1296272cc70bSAndy Fleming 
1297272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1298272cc70bSAndy Fleming 
1299272cc70bSAndy Fleming 	if (err)
1300272cc70bSAndy Fleming 		return err;
1301272cc70bSAndy Fleming 
1302998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1303272cc70bSAndy Fleming 		return UNUSABLE_ERR;
1304272cc70bSAndy Fleming 	else
1305272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1306272cc70bSAndy Fleming 
1307272cc70bSAndy Fleming 	return 0;
1308272cc70bSAndy Fleming }
1309272cc70bSAndy Fleming 
1310272cc70bSAndy Fleming int mmc_register(struct mmc *mmc)
1311272cc70bSAndy Fleming {
1312272cc70bSAndy Fleming 	/* Setup the universal parts of the block interface just once */
1313272cc70bSAndy Fleming 	mmc->block_dev.if_type = IF_TYPE_MMC;
1314272cc70bSAndy Fleming 	mmc->block_dev.dev = cur_dev_num++;
1315272cc70bSAndy Fleming 	mmc->block_dev.removable = 1;
1316272cc70bSAndy Fleming 	mmc->block_dev.block_read = mmc_bread;
1317272cc70bSAndy Fleming 	mmc->block_dev.block_write = mmc_bwrite;
1318e6f99a56SLei Wen 	mmc->block_dev.block_erase = mmc_berase;
13198feafcc4SJohn Rigby 	if (!mmc->b_max)
13208feafcc4SJohn Rigby 		mmc->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
1321272cc70bSAndy Fleming 
1322272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc->link);
1323272cc70bSAndy Fleming 
1324272cc70bSAndy Fleming 	list_add_tail (&mmc->link, &mmc_devices);
1325272cc70bSAndy Fleming 
1326272cc70bSAndy Fleming 	return 0;
1327272cc70bSAndy Fleming }
1328272cc70bSAndy Fleming 
1329df3fc526SMatthew McClintock #ifdef CONFIG_PARTITIONS
1330272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev)
1331272cc70bSAndy Fleming {
1332272cc70bSAndy Fleming 	struct mmc *mmc = find_mmc_device(dev);
13336bb4b4bcSBenoît Thébaudeau 	if (!mmc || mmc_init(mmc))
133440242bc3SŁukasz Majewski 		return NULL;
1335272cc70bSAndy Fleming 
133640242bc3SŁukasz Majewski 	return &mmc->block_dev;
1337272cc70bSAndy Fleming }
1338df3fc526SMatthew McClintock #endif
1339272cc70bSAndy Fleming 
1340e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1341272cc70bSAndy Fleming {
1342afd5932bSMacpaul Lin 	int err;
1343272cc70bSAndy Fleming 
134448972d90SThierry Reding 	if (mmc_getcd(mmc) == 0) {
134548972d90SThierry Reding 		mmc->has_init = 0;
134648972d90SThierry Reding 		printf("MMC: no card present\n");
134748972d90SThierry Reding 		return NO_CARD_ERR;
134848972d90SThierry Reding 	}
134948972d90SThierry Reding 
1350bc897b1dSLei Wen 	if (mmc->has_init)
1351bc897b1dSLei Wen 		return 0;
1352bc897b1dSLei Wen 
1353272cc70bSAndy Fleming 	err = mmc->init(mmc);
1354272cc70bSAndy Fleming 
1355272cc70bSAndy Fleming 	if (err)
1356272cc70bSAndy Fleming 		return err;
1357272cc70bSAndy Fleming 
1358b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1359b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1360b86b85e2SIlya Yanok 
1361272cc70bSAndy Fleming 	/* Reset the Card */
1362272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1363272cc70bSAndy Fleming 
1364272cc70bSAndy Fleming 	if (err)
1365272cc70bSAndy Fleming 		return err;
1366272cc70bSAndy Fleming 
1367bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1368bc897b1dSLei Wen 	mmc->part_num = 0;
1369bc897b1dSLei Wen 
1370272cc70bSAndy Fleming 	/* Test for SD version 2 */
1371272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1372272cc70bSAndy Fleming 
1373272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1374272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1375272cc70bSAndy Fleming 
1376272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1377272cc70bSAndy Fleming 	if (err == TIMEOUT) {
1378272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1379272cc70bSAndy Fleming 
1380e9550449SChe-Liang Chiou 		if (err && err != IN_PROGRESS) {
1381272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
1382272cc70bSAndy Fleming 			return UNUSABLE_ERR;
1383272cc70bSAndy Fleming 		}
1384272cc70bSAndy Fleming 	}
1385272cc70bSAndy Fleming 
1386e9550449SChe-Liang Chiou 	if (err == IN_PROGRESS)
1387e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
1388e9550449SChe-Liang Chiou 
1389e9550449SChe-Liang Chiou 	return err;
1390e9550449SChe-Liang Chiou }
1391e9550449SChe-Liang Chiou 
1392e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
1393e9550449SChe-Liang Chiou {
1394e9550449SChe-Liang Chiou 	int err = 0;
1395e9550449SChe-Liang Chiou 
1396e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
1397e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
1398e9550449SChe-Liang Chiou 
1399e9550449SChe-Liang Chiou 	if (!err)
1400bc897b1dSLei Wen 		err = mmc_startup(mmc);
1401bc897b1dSLei Wen 	if (err)
1402bc897b1dSLei Wen 		mmc->has_init = 0;
1403bc897b1dSLei Wen 	else
1404bc897b1dSLei Wen 		mmc->has_init = 1;
1405e9550449SChe-Liang Chiou 	mmc->init_in_progress = 0;
1406e9550449SChe-Liang Chiou 	return err;
1407e9550449SChe-Liang Chiou }
1408e9550449SChe-Liang Chiou 
1409e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
1410e9550449SChe-Liang Chiou {
1411e9550449SChe-Liang Chiou 	int err = IN_PROGRESS;
1412e9550449SChe-Liang Chiou 	unsigned start = get_timer(0);
1413e9550449SChe-Liang Chiou 
1414e9550449SChe-Liang Chiou 	if (mmc->has_init)
1415e9550449SChe-Liang Chiou 		return 0;
1416e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
1417e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
1418e9550449SChe-Liang Chiou 
1419e9550449SChe-Liang Chiou 	if (!err || err == IN_PROGRESS)
1420e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
1421e9550449SChe-Liang Chiou 	debug("%s: %d, time %lu\n", __func__, err, get_timer(start));
1422bc897b1dSLei Wen 	return err;
1423272cc70bSAndy Fleming }
1424272cc70bSAndy Fleming 
1425272cc70bSAndy Fleming /*
1426272cc70bSAndy Fleming  * CPU and board-specific MMC initializations.  Aliased function
1427272cc70bSAndy Fleming  * signals caller to move on
1428272cc70bSAndy Fleming  */
1429272cc70bSAndy Fleming static int __def_mmc_init(bd_t *bis)
1430272cc70bSAndy Fleming {
1431272cc70bSAndy Fleming 	return -1;
1432272cc70bSAndy Fleming }
1433272cc70bSAndy Fleming 
1434f9a109b3SPeter Tyser int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
1435f9a109b3SPeter Tyser int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
1436272cc70bSAndy Fleming 
1437272cc70bSAndy Fleming void print_mmc_devices(char separator)
1438272cc70bSAndy Fleming {
1439272cc70bSAndy Fleming 	struct mmc *m;
1440272cc70bSAndy Fleming 	struct list_head *entry;
1441272cc70bSAndy Fleming 
1442272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
1443272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
1444272cc70bSAndy Fleming 
1445272cc70bSAndy Fleming 		printf("%s: %d", m->name, m->block_dev.dev);
1446272cc70bSAndy Fleming 
1447272cc70bSAndy Fleming 		if (entry->next != &mmc_devices)
1448272cc70bSAndy Fleming 			printf("%c ", separator);
1449272cc70bSAndy Fleming 	}
1450272cc70bSAndy Fleming 
1451272cc70bSAndy Fleming 	printf("\n");
1452272cc70bSAndy Fleming }
1453272cc70bSAndy Fleming 
1454ea6ebe21SLei Wen int get_mmc_num(void)
1455ea6ebe21SLei Wen {
1456ea6ebe21SLei Wen 	return cur_dev_num;
1457ea6ebe21SLei Wen }
1458ea6ebe21SLei Wen 
1459e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
1460e9550449SChe-Liang Chiou {
1461e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
1462e9550449SChe-Liang Chiou }
1463e9550449SChe-Liang Chiou 
1464e9550449SChe-Liang Chiou static void do_preinit(void)
1465e9550449SChe-Liang Chiou {
1466e9550449SChe-Liang Chiou 	struct mmc *m;
1467e9550449SChe-Liang Chiou 	struct list_head *entry;
1468e9550449SChe-Liang Chiou 
1469e9550449SChe-Liang Chiou 	list_for_each(entry, &mmc_devices) {
1470e9550449SChe-Liang Chiou 		m = list_entry(entry, struct mmc, link);
1471e9550449SChe-Liang Chiou 
1472e9550449SChe-Liang Chiou 		if (m->preinit)
1473e9550449SChe-Liang Chiou 			mmc_start_init(m);
1474e9550449SChe-Liang Chiou 	}
1475e9550449SChe-Liang Chiou }
1476e9550449SChe-Liang Chiou 
1477e9550449SChe-Liang Chiou 
1478272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1479272cc70bSAndy Fleming {
1480272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc_devices);
1481272cc70bSAndy Fleming 	cur_dev_num = 0;
1482272cc70bSAndy Fleming 
1483272cc70bSAndy Fleming 	if (board_mmc_init(bis) < 0)
1484272cc70bSAndy Fleming 		cpu_mmc_init(bis);
1485272cc70bSAndy Fleming 
1486272cc70bSAndy Fleming 	print_mmc_devices(',');
1487272cc70bSAndy Fleming 
1488e9550449SChe-Liang Chiou 	do_preinit();
1489272cc70bSAndy Fleming 	return 0;
1490272cc70bSAndy Fleming }
14913690d6d6SAmar 
14923690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT
14933690d6d6SAmar /*
14943690d6d6SAmar  * This function changes the size of boot partition and the size of rpmb
14953690d6d6SAmar  * partition present on EMMC devices.
14963690d6d6SAmar  *
14973690d6d6SAmar  * Input Parameters:
14983690d6d6SAmar  * struct *mmc: pointer for the mmc device strcuture
14993690d6d6SAmar  * bootsize: size of boot partition
15003690d6d6SAmar  * rpmbsize: size of rpmb partition
15013690d6d6SAmar  *
15023690d6d6SAmar  * Returns 0 on success.
15033690d6d6SAmar  */
15043690d6d6SAmar 
15053690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
15063690d6d6SAmar 				unsigned long rpmbsize)
15073690d6d6SAmar {
15083690d6d6SAmar 	int err;
15093690d6d6SAmar 	struct mmc_cmd cmd;
15103690d6d6SAmar 
15113690d6d6SAmar 	/* Only use this command for raw EMMC moviNAND. Enter backdoor mode */
15123690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
15133690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
15143690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG1;
15153690d6d6SAmar 
15163690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
15173690d6d6SAmar 	if (err) {
15183690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error1 = %d\n", err);
15193690d6d6SAmar 		return err;
15203690d6d6SAmar 	}
15213690d6d6SAmar 
15223690d6d6SAmar 	/* Boot partition changing mode */
15233690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
15243690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
15253690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG2;
15263690d6d6SAmar 
15273690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
15283690d6d6SAmar 	if (err) {
15293690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error2 = %d\n", err);
15303690d6d6SAmar 		return err;
15313690d6d6SAmar 	}
15323690d6d6SAmar 	/* boot partition size is multiple of 128KB */
15333690d6d6SAmar 	bootsize = (bootsize * 1024) / 128;
15343690d6d6SAmar 
15353690d6d6SAmar 	/* Arg: boot partition size */
15363690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
15373690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
15383690d6d6SAmar 	cmd.cmdarg = bootsize;
15393690d6d6SAmar 
15403690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
15413690d6d6SAmar 	if (err) {
15423690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error3 = %d\n", err);
15433690d6d6SAmar 		return err;
15443690d6d6SAmar 	}
15453690d6d6SAmar 	/* RPMB partition size is multiple of 128KB */
15463690d6d6SAmar 	rpmbsize = (rpmbsize * 1024) / 128;
15473690d6d6SAmar 	/* Arg: RPMB partition size */
15483690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
15493690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
15503690d6d6SAmar 	cmd.cmdarg = rpmbsize;
15513690d6d6SAmar 
15523690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
15533690d6d6SAmar 	if (err) {
15543690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error4 = %d\n", err);
15553690d6d6SAmar 		return err;
15563690d6d6SAmar 	}
15573690d6d6SAmar 	return 0;
15583690d6d6SAmar }
15593690d6d6SAmar 
15603690d6d6SAmar /*
15613690d6d6SAmar  * This function shall form and send the commands to open / close the
15623690d6d6SAmar  * boot partition specified by user.
15633690d6d6SAmar  *
15643690d6d6SAmar  * Input Parameters:
15653690d6d6SAmar  * ack: 0x0 - No boot acknowledge sent (default)
15663690d6d6SAmar  *	0x1 - Boot acknowledge sent during boot operation
15673690d6d6SAmar  * part_num: User selects boot data that will be sent to master
15683690d6d6SAmar  *	0x0 - Device not boot enabled (default)
15693690d6d6SAmar  *	0x1 - Boot partition 1 enabled for boot
15703690d6d6SAmar  *	0x2 - Boot partition 2 enabled for boot
15713690d6d6SAmar  * access: User selects partitions to access
15723690d6d6SAmar  *	0x0 : No access to boot partition (default)
15733690d6d6SAmar  *	0x1 : R/W boot partition 1
15743690d6d6SAmar  *	0x2 : R/W boot partition 2
15753690d6d6SAmar  *	0x3 : R/W Replay Protected Memory Block (RPMB)
15763690d6d6SAmar  *
15773690d6d6SAmar  * Returns 0 on success.
15783690d6d6SAmar  */
15793690d6d6SAmar int mmc_boot_part_access(struct mmc *mmc, u8 ack, u8 part_num, u8 access)
15803690d6d6SAmar {
15813690d6d6SAmar 	int err;
15823690d6d6SAmar 	struct mmc_cmd cmd;
15833690d6d6SAmar 
15843690d6d6SAmar 	/* Boot ack enable, boot partition enable , boot partition access */
15853690d6d6SAmar 	cmd.cmdidx = MMC_CMD_SWITCH;
15863690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
15873690d6d6SAmar 
15883690d6d6SAmar 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
15893690d6d6SAmar 			(EXT_CSD_PART_CONF << 16) |
15903690d6d6SAmar 			((EXT_CSD_BOOT_ACK(ack) |
15913690d6d6SAmar 			EXT_CSD_BOOT_PART_NUM(part_num) |
15923690d6d6SAmar 			EXT_CSD_PARTITION_ACCESS(access)) << 8);
15933690d6d6SAmar 
15943690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
15953690d6d6SAmar 	if (err) {
15963690d6d6SAmar 		if (access) {
15973690d6d6SAmar 			debug("mmc boot partition#%d open fail:Error1 = %d\n",
15983690d6d6SAmar 			      part_num, err);
15993690d6d6SAmar 		} else {
16003690d6d6SAmar 			debug("mmc boot partition#%d close fail:Error = %d\n",
16013690d6d6SAmar 			      part_num, err);
16023690d6d6SAmar 		}
16033690d6d6SAmar 		return err;
16043690d6d6SAmar 	}
16053690d6d6SAmar 
16063690d6d6SAmar 	if (access) {
16073690d6d6SAmar 		/* 4bit transfer mode at booting time. */
16083690d6d6SAmar 		cmd.cmdidx = MMC_CMD_SWITCH;
16093690d6d6SAmar 		cmd.resp_type = MMC_RSP_R1b;
16103690d6d6SAmar 
16113690d6d6SAmar 		cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
16123690d6d6SAmar 				(EXT_CSD_BOOT_BUS_WIDTH << 16) |
16133690d6d6SAmar 				((1 << 0) << 8);
16143690d6d6SAmar 
16153690d6d6SAmar 		err = mmc_send_cmd(mmc, &cmd, NULL);
16163690d6d6SAmar 		if (err) {
16173690d6d6SAmar 			debug("mmc boot partition#%d open fail:Error2 = %d\n",
16183690d6d6SAmar 			      part_num, err);
16193690d6d6SAmar 			return err;
16203690d6d6SAmar 		}
16213690d6d6SAmar 	}
16223690d6d6SAmar 	return 0;
16233690d6d6SAmar }
16243690d6d6SAmar #endif
1625