xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 6bb4b4bc)
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  *
7272cc70bSAndy Fleming  * See file CREDITS for list of people who contributed to this
8272cc70bSAndy Fleming  * project.
9272cc70bSAndy Fleming  *
10272cc70bSAndy Fleming  * This program is free software; you can redistribute it and/or
11272cc70bSAndy Fleming  * modify it under the terms of the GNU General Public License as
12272cc70bSAndy Fleming  * published by the Free Software Foundation; either version 2 of
13272cc70bSAndy Fleming  * the License, or (at your option) any later version.
14272cc70bSAndy Fleming  *
15272cc70bSAndy Fleming  * This program is distributed in the hope that it will be useful,
16272cc70bSAndy Fleming  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17272cc70bSAndy Fleming  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18272cc70bSAndy Fleming  * GNU General Public License for more details.
19272cc70bSAndy Fleming  *
20272cc70bSAndy Fleming  * You should have received a copy of the GNU General Public License
21272cc70bSAndy Fleming  * along with this program; if not, write to the Free Software
22272cc70bSAndy Fleming  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23272cc70bSAndy Fleming  * MA 02111-1307 USA
24272cc70bSAndy Fleming  */
25272cc70bSAndy Fleming 
26272cc70bSAndy Fleming #include <config.h>
27272cc70bSAndy Fleming #include <common.h>
28272cc70bSAndy Fleming #include <command.h>
29272cc70bSAndy Fleming #include <mmc.h>
30272cc70bSAndy Fleming #include <part.h>
31272cc70bSAndy Fleming #include <malloc.h>
32272cc70bSAndy Fleming #include <linux/list.h>
339b1f942cSRabin Vincent #include <div64.h>
34272cc70bSAndy Fleming 
35ce0fbcd2SMatt Waddel /* Set block count limit because of 16 bit register limit on some hardware*/
36ce0fbcd2SMatt Waddel #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT
37ce0fbcd2SMatt Waddel #define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535
38ce0fbcd2SMatt Waddel #endif
39ce0fbcd2SMatt Waddel 
40272cc70bSAndy Fleming static struct list_head mmc_devices;
41272cc70bSAndy Fleming static int cur_dev_num = -1;
42272cc70bSAndy Fleming 
43314284b1SThierry Reding int __board_mmc_getcd(struct mmc *mmc) {
4411fdade2SStefano Babic 	return -1;
4511fdade2SStefano Babic }
4611fdade2SStefano Babic 
47314284b1SThierry Reding int board_mmc_getcd(struct mmc *mmc)__attribute__((weak,
4811fdade2SStefano Babic 	alias("__board_mmc_getcd")));
4911fdade2SStefano Babic 
508635ff9eSMarek Vasut #ifdef CONFIG_MMC_BOUNCE_BUFFER
518635ff9eSMarek Vasut static int mmc_bounce_need_bounce(struct mmc_data *orig)
528635ff9eSMarek Vasut {
538635ff9eSMarek Vasut 	ulong addr, len;
548635ff9eSMarek Vasut 
558635ff9eSMarek Vasut 	if (orig->flags & MMC_DATA_READ)
568635ff9eSMarek Vasut 		addr = (ulong)orig->dest;
578635ff9eSMarek Vasut 	else
588635ff9eSMarek Vasut 		addr = (ulong)orig->src;
598635ff9eSMarek Vasut 
608635ff9eSMarek Vasut 	if (addr % ARCH_DMA_MINALIGN) {
618635ff9eSMarek Vasut 		debug("MMC: Unaligned data destination address %08lx!\n", addr);
628635ff9eSMarek Vasut 		return 1;
638635ff9eSMarek Vasut 	}
648635ff9eSMarek Vasut 
658635ff9eSMarek Vasut 	len = (ulong)(orig->blocksize * orig->blocks);
668635ff9eSMarek Vasut 	if (len % ARCH_DMA_MINALIGN) {
678635ff9eSMarek Vasut 		debug("MMC: Unaligned data destination length %08lx!\n", len);
688635ff9eSMarek Vasut 		return 1;
698635ff9eSMarek Vasut 	}
708635ff9eSMarek Vasut 
718635ff9eSMarek Vasut 	return 0;
728635ff9eSMarek Vasut }
738635ff9eSMarek Vasut 
748635ff9eSMarek Vasut static int mmc_bounce_buffer_start(struct mmc_data *backup,
758635ff9eSMarek Vasut 					struct mmc_data *orig)
768635ff9eSMarek Vasut {
778635ff9eSMarek Vasut 	ulong origlen, len;
788635ff9eSMarek Vasut 	void *buffer;
798635ff9eSMarek Vasut 
808635ff9eSMarek Vasut 	if (!orig)
818635ff9eSMarek Vasut 		return 0;
828635ff9eSMarek Vasut 
838635ff9eSMarek Vasut 	if (!mmc_bounce_need_bounce(orig))
848635ff9eSMarek Vasut 		return 0;
858635ff9eSMarek Vasut 
868635ff9eSMarek Vasut 	memcpy(backup, orig, sizeof(struct mmc_data));
878635ff9eSMarek Vasut 
888635ff9eSMarek Vasut 	origlen = orig->blocksize * orig->blocks;
898635ff9eSMarek Vasut 	len = roundup(origlen, ARCH_DMA_MINALIGN);
908635ff9eSMarek Vasut 	buffer = memalign(ARCH_DMA_MINALIGN, len);
918635ff9eSMarek Vasut 	if (!buffer) {
928635ff9eSMarek Vasut 		puts("MMC: Error allocating MMC bounce buffer!\n");
938635ff9eSMarek Vasut 		return 1;
948635ff9eSMarek Vasut 	}
958635ff9eSMarek Vasut 
968635ff9eSMarek Vasut 	if (orig->flags & MMC_DATA_READ) {
978635ff9eSMarek Vasut 		orig->dest = buffer;
988635ff9eSMarek Vasut 	} else {
998635ff9eSMarek Vasut 		memcpy(buffer, orig->src, origlen);
1008635ff9eSMarek Vasut 		orig->src = buffer;
1018635ff9eSMarek Vasut 	}
1028635ff9eSMarek Vasut 
1038635ff9eSMarek Vasut 	return 0;
1048635ff9eSMarek Vasut }
1058635ff9eSMarek Vasut 
1068635ff9eSMarek Vasut static void mmc_bounce_buffer_stop(struct mmc_data *backup,
1078635ff9eSMarek Vasut 					struct mmc_data *orig)
1088635ff9eSMarek Vasut {
1098635ff9eSMarek Vasut 	ulong len;
1108635ff9eSMarek Vasut 
1118635ff9eSMarek Vasut 	if (!orig)
1128635ff9eSMarek Vasut 		return;
1138635ff9eSMarek Vasut 
1148635ff9eSMarek Vasut 	if (!mmc_bounce_need_bounce(backup))
1158635ff9eSMarek Vasut 		return;
1168635ff9eSMarek Vasut 
1178635ff9eSMarek Vasut 	if (backup->flags & MMC_DATA_READ) {
1188635ff9eSMarek Vasut 		len = backup->blocksize * backup->blocks;
1198635ff9eSMarek Vasut 		memcpy(backup->dest, orig->dest, len);
1208635ff9eSMarek Vasut 		free(orig->dest);
1218635ff9eSMarek Vasut 		orig->dest = backup->dest;
1228635ff9eSMarek Vasut 	} else {
1238635ff9eSMarek Vasut 		free((void *)orig->src);
1248635ff9eSMarek Vasut 		orig->src = backup->src;
1258635ff9eSMarek Vasut 	}
1268635ff9eSMarek Vasut 
1278635ff9eSMarek Vasut 	return;
1288635ff9eSMarek Vasut 
1298635ff9eSMarek Vasut }
1308635ff9eSMarek Vasut #else
1318635ff9eSMarek Vasut static inline int mmc_bounce_buffer_start(struct mmc_data *backup,
132dc3faf09SAnatolij Gustschin 					struct mmc_data *orig) { return 0; }
1338635ff9eSMarek Vasut static inline void mmc_bounce_buffer_stop(struct mmc_data *backup,
1348635ff9eSMarek Vasut 					struct mmc_data *orig) { }
1358635ff9eSMarek Vasut #endif
1368635ff9eSMarek Vasut 
137272cc70bSAndy Fleming int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
138272cc70bSAndy Fleming {
1398635ff9eSMarek Vasut 	struct mmc_data backup;
1405db2fe3aSRaffaele Recalcati 	int ret;
1418635ff9eSMarek Vasut 
1428635ff9eSMarek Vasut 	memset(&backup, 0, sizeof(backup));
1438635ff9eSMarek Vasut 
1448635ff9eSMarek Vasut 	ret = mmc_bounce_buffer_start(&backup, data);
1458635ff9eSMarek Vasut 	if (ret)
1468635ff9eSMarek Vasut 		return ret;
1478635ff9eSMarek Vasut 
1488635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
1495db2fe3aSRaffaele Recalcati 	int i;
1505db2fe3aSRaffaele Recalcati 	u8 *ptr;
1515db2fe3aSRaffaele Recalcati 
1525db2fe3aSRaffaele Recalcati 	printf("CMD_SEND:%d\n", cmd->cmdidx);
1535db2fe3aSRaffaele Recalcati 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
1545db2fe3aSRaffaele Recalcati 	ret = mmc->send_cmd(mmc, cmd, data);
1555db2fe3aSRaffaele Recalcati 	switch (cmd->resp_type) {
1565db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
1575db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
1585db2fe3aSRaffaele Recalcati 			break;
1595db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
1605db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
1615db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1625db2fe3aSRaffaele Recalcati 			break;
1635db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
1645db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
1655db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1665db2fe3aSRaffaele Recalcati 			break;
1675db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
1685db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
1695db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1705db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1715db2fe3aSRaffaele Recalcati 				cmd->response[1]);
1725db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1735db2fe3aSRaffaele Recalcati 				cmd->response[2]);
1745db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1755db2fe3aSRaffaele Recalcati 				cmd->response[3]);
1765db2fe3aSRaffaele Recalcati 			printf("\n");
1775db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
1785db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
1795db2fe3aSRaffaele Recalcati 				int j;
1805db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
181146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
1825db2fe3aSRaffaele Recalcati 				ptr += 3;
1835db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
1845db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
1855db2fe3aSRaffaele Recalcati 				printf("\n");
1865db2fe3aSRaffaele Recalcati 			}
1875db2fe3aSRaffaele Recalcati 			break;
1885db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1895db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1905db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1915db2fe3aSRaffaele Recalcati 			break;
1925db2fe3aSRaffaele Recalcati 		default:
1935db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1945db2fe3aSRaffaele Recalcati 			break;
1955db2fe3aSRaffaele Recalcati 	}
1965db2fe3aSRaffaele Recalcati #else
1978635ff9eSMarek Vasut 	ret = mmc->send_cmd(mmc, cmd, data);
1985db2fe3aSRaffaele Recalcati #endif
1998635ff9eSMarek Vasut 	mmc_bounce_buffer_stop(&backup, data);
2008635ff9eSMarek Vasut 	return ret;
201272cc70bSAndy Fleming }
202272cc70bSAndy Fleming 
2035d4fc8d9SRaffaele Recalcati int mmc_send_status(struct mmc *mmc, int timeout)
2045d4fc8d9SRaffaele Recalcati {
2055d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
206d617c426SJan Kloetzke 	int err, retries = 5;
2075d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
2085d4fc8d9SRaffaele Recalcati 	int status;
2095d4fc8d9SRaffaele Recalcati #endif
2105d4fc8d9SRaffaele Recalcati 
2115d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
2125d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
213aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
214aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
2155d4fc8d9SRaffaele Recalcati 
2165d4fc8d9SRaffaele Recalcati 	do {
2175d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
218d617c426SJan Kloetzke 		if (!err) {
219d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
220d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
221d617c426SJan Kloetzke 			     MMC_STATE_PRG)
2225d4fc8d9SRaffaele Recalcati 				break;
223d617c426SJan Kloetzke 			else if (cmd.response[0] & MMC_STATUS_MASK) {
224d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
225d617c426SJan Kloetzke 					cmd.response[0]);
226d617c426SJan Kloetzke 				return COMM_ERR;
227d617c426SJan Kloetzke 			}
228d617c426SJan Kloetzke 		} else if (--retries < 0)
229d617c426SJan Kloetzke 			return err;
2305d4fc8d9SRaffaele Recalcati 
2315d4fc8d9SRaffaele Recalcati 		udelay(1000);
2325d4fc8d9SRaffaele Recalcati 
2335d4fc8d9SRaffaele Recalcati 	} while (timeout--);
2345d4fc8d9SRaffaele Recalcati 
2355db2fe3aSRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
2365db2fe3aSRaffaele Recalcati 	status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9;
2375db2fe3aSRaffaele Recalcati 	printf("CURR STATE:%d\n", status);
2385db2fe3aSRaffaele Recalcati #endif
2395b0c942fSJongman Heo 	if (timeout <= 0) {
2405d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
2415d4fc8d9SRaffaele Recalcati 		return TIMEOUT;
2425d4fc8d9SRaffaele Recalcati 	}
2435d4fc8d9SRaffaele Recalcati 
2445d4fc8d9SRaffaele Recalcati 	return 0;
2455d4fc8d9SRaffaele Recalcati }
2465d4fc8d9SRaffaele Recalcati 
247272cc70bSAndy Fleming int mmc_set_blocklen(struct mmc *mmc, int len)
248272cc70bSAndy Fleming {
249272cc70bSAndy Fleming 	struct mmc_cmd cmd;
250272cc70bSAndy Fleming 
251272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
252272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
253272cc70bSAndy Fleming 	cmd.cmdarg = len;
254272cc70bSAndy Fleming 
255272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
256272cc70bSAndy Fleming }
257272cc70bSAndy Fleming 
258272cc70bSAndy Fleming struct mmc *find_mmc_device(int dev_num)
259272cc70bSAndy Fleming {
260272cc70bSAndy Fleming 	struct mmc *m;
261272cc70bSAndy Fleming 	struct list_head *entry;
262272cc70bSAndy Fleming 
263272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
264272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
265272cc70bSAndy Fleming 
266272cc70bSAndy Fleming 		if (m->block_dev.dev == dev_num)
267272cc70bSAndy Fleming 			return m;
268272cc70bSAndy Fleming 	}
269272cc70bSAndy Fleming 
270272cc70bSAndy Fleming 	printf("MMC Device %d not found\n", dev_num);
271272cc70bSAndy Fleming 
272272cc70bSAndy Fleming 	return NULL;
273272cc70bSAndy Fleming }
274272cc70bSAndy Fleming 
275e6f99a56SLei Wen static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt)
276e6f99a56SLei Wen {
277e6f99a56SLei Wen 	struct mmc_cmd cmd;
278e6f99a56SLei Wen 	ulong end;
279e6f99a56SLei Wen 	int err, start_cmd, end_cmd;
280e6f99a56SLei Wen 
281e6f99a56SLei Wen 	if (mmc->high_capacity)
282e6f99a56SLei Wen 		end = start + blkcnt - 1;
283e6f99a56SLei Wen 	else {
284e6f99a56SLei Wen 		end = (start + blkcnt - 1) * mmc->write_bl_len;
285e6f99a56SLei Wen 		start *= mmc->write_bl_len;
286e6f99a56SLei Wen 	}
287e6f99a56SLei Wen 
288e6f99a56SLei Wen 	if (IS_SD(mmc)) {
289e6f99a56SLei Wen 		start_cmd = SD_CMD_ERASE_WR_BLK_START;
290e6f99a56SLei Wen 		end_cmd = SD_CMD_ERASE_WR_BLK_END;
291e6f99a56SLei Wen 	} else {
292e6f99a56SLei Wen 		start_cmd = MMC_CMD_ERASE_GROUP_START;
293e6f99a56SLei Wen 		end_cmd = MMC_CMD_ERASE_GROUP_END;
294e6f99a56SLei Wen 	}
295e6f99a56SLei Wen 
296e6f99a56SLei Wen 	cmd.cmdidx = start_cmd;
297e6f99a56SLei Wen 	cmd.cmdarg = start;
298e6f99a56SLei Wen 	cmd.resp_type = MMC_RSP_R1;
299e6f99a56SLei Wen 
300e6f99a56SLei Wen 	err = mmc_send_cmd(mmc, &cmd, NULL);
301e6f99a56SLei Wen 	if (err)
302e6f99a56SLei Wen 		goto err_out;
303e6f99a56SLei Wen 
304e6f99a56SLei Wen 	cmd.cmdidx = end_cmd;
305e6f99a56SLei Wen 	cmd.cmdarg = end;
306e6f99a56SLei Wen 
307e6f99a56SLei Wen 	err = mmc_send_cmd(mmc, &cmd, NULL);
308e6f99a56SLei Wen 	if (err)
309e6f99a56SLei Wen 		goto err_out;
310e6f99a56SLei Wen 
311e6f99a56SLei Wen 	cmd.cmdidx = MMC_CMD_ERASE;
312e6f99a56SLei Wen 	cmd.cmdarg = SECURE_ERASE;
313e6f99a56SLei Wen 	cmd.resp_type = MMC_RSP_R1b;
314e6f99a56SLei Wen 
315e6f99a56SLei Wen 	err = mmc_send_cmd(mmc, &cmd, NULL);
316e6f99a56SLei Wen 	if (err)
317e6f99a56SLei Wen 		goto err_out;
318e6f99a56SLei Wen 
319e6f99a56SLei Wen 	return 0;
320e6f99a56SLei Wen 
321e6f99a56SLei Wen err_out:
322e6f99a56SLei Wen 	puts("mmc erase failed\n");
323e6f99a56SLei Wen 	return err;
324e6f99a56SLei Wen }
325e6f99a56SLei Wen 
326e6f99a56SLei Wen static unsigned long
327e6f99a56SLei Wen mmc_berase(int dev_num, unsigned long start, lbaint_t blkcnt)
328e6f99a56SLei Wen {
329e6f99a56SLei Wen 	int err = 0;
330e6f99a56SLei Wen 	struct mmc *mmc = find_mmc_device(dev_num);
331e6f99a56SLei Wen 	lbaint_t blk = 0, blk_r = 0;
332d2d8afaeSJerry Huang 	int timeout = 1000;
333e6f99a56SLei Wen 
334e6f99a56SLei Wen 	if (!mmc)
335e6f99a56SLei Wen 		return -1;
336e6f99a56SLei Wen 
337e6f99a56SLei Wen 	if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size))
338e6f99a56SLei Wen 		printf("\n\nCaution! Your devices Erase group is 0x%x\n"
339e6f99a56SLei Wen 			"The erase range would be change to 0x%lx~0x%lx\n\n",
340e6f99a56SLei Wen 		       mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1),
341e6f99a56SLei Wen 		       ((start + blkcnt + mmc->erase_grp_size)
342e6f99a56SLei Wen 		       & ~(mmc->erase_grp_size - 1)) - 1);
343e6f99a56SLei Wen 
344e6f99a56SLei Wen 	while (blk < blkcnt) {
345e6f99a56SLei Wen 		blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
346e6f99a56SLei Wen 			mmc->erase_grp_size : (blkcnt - blk);
347e6f99a56SLei Wen 		err = mmc_erase_t(mmc, start + blk, blk_r);
348e6f99a56SLei Wen 		if (err)
349e6f99a56SLei Wen 			break;
350e6f99a56SLei Wen 
351e6f99a56SLei Wen 		blk += blk_r;
352d2d8afaeSJerry Huang 
353d2d8afaeSJerry Huang 		/* Waiting for the ready status */
354d2d8afaeSJerry Huang 		if (mmc_send_status(mmc, timeout))
355d2d8afaeSJerry Huang 			return 0;
356e6f99a56SLei Wen 	}
357e6f99a56SLei Wen 
358e6f99a56SLei Wen 	return blk;
359e6f99a56SLei Wen }
360e6f99a56SLei Wen 
361272cc70bSAndy Fleming static ulong
3620158126eSLei Wen mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)
363272cc70bSAndy Fleming {
364272cc70bSAndy Fleming 	struct mmc_cmd cmd;
365272cc70bSAndy Fleming 	struct mmc_data data;
3665d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
367272cc70bSAndy Fleming 
368d2bf29e3SLei Wen 	if ((start + blkcnt) > mmc->block_dev.lba) {
369def412b6SSteve Sakoman 		printf("MMC: block number 0x%lx exceeds max(0x%lx)\n",
370d2bf29e3SLei Wen 			start + blkcnt, mmc->block_dev.lba);
371d2bf29e3SLei Wen 		return 0;
372d2bf29e3SLei Wen 	}
373272cc70bSAndy Fleming 
374272cc70bSAndy Fleming 	if (blkcnt > 1)
375272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
376272cc70bSAndy Fleming 	else
377272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
378272cc70bSAndy Fleming 
379272cc70bSAndy Fleming 	if (mmc->high_capacity)
380272cc70bSAndy Fleming 		cmd.cmdarg = start;
381272cc70bSAndy Fleming 	else
382def412b6SSteve Sakoman 		cmd.cmdarg = start * mmc->write_bl_len;
383272cc70bSAndy Fleming 
384272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
385272cc70bSAndy Fleming 
386272cc70bSAndy Fleming 	data.src = src;
387272cc70bSAndy Fleming 	data.blocks = blkcnt;
388def412b6SSteve Sakoman 	data.blocksize = mmc->write_bl_len;
389272cc70bSAndy Fleming 	data.flags = MMC_DATA_WRITE;
390272cc70bSAndy Fleming 
391def412b6SSteve Sakoman 	if (mmc_send_cmd(mmc, &cmd, &data)) {
392def412b6SSteve Sakoman 		printf("mmc write failed\n");
393def412b6SSteve Sakoman 		return 0;
394272cc70bSAndy Fleming 	}
395272cc70bSAndy Fleming 
396d52ebf10SThomas Chou 	/* SPI multiblock writes terminate using a special
397d52ebf10SThomas Chou 	 * token, not a STOP_TRANSMISSION request.
398d52ebf10SThomas Chou 	 */
399d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc) && blkcnt > 1) {
400272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
401272cc70bSAndy Fleming 		cmd.cmdarg = 0;
402272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1b;
403def412b6SSteve Sakoman 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
404def412b6SSteve Sakoman 			printf("mmc fail to send stop cmd\n");
405def412b6SSteve Sakoman 			return 0;
406272cc70bSAndy Fleming 		}
40793ad0d18SJan Kloetzke 	}
4085d4fc8d9SRaffaele Recalcati 
4095d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
41093ad0d18SJan Kloetzke 	if (mmc_send_status(mmc, timeout))
41193ad0d18SJan Kloetzke 		return 0;
4120158126eSLei Wen 
4130158126eSLei Wen 	return blkcnt;
4140158126eSLei Wen }
4150158126eSLei Wen 
4160158126eSLei Wen static ulong
4170158126eSLei Wen mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)
4180158126eSLei Wen {
4190158126eSLei Wen 	lbaint_t cur, blocks_todo = blkcnt;
4200158126eSLei Wen 
421def412b6SSteve Sakoman 	struct mmc *mmc = find_mmc_device(dev_num);
4220158126eSLei Wen 	if (!mmc)
423def412b6SSteve Sakoman 		return 0;
4240158126eSLei Wen 
425def412b6SSteve Sakoman 	if (mmc_set_blocklen(mmc, mmc->write_bl_len))
426def412b6SSteve Sakoman 		return 0;
4270158126eSLei Wen 
4280158126eSLei Wen 	do {
4298feafcc4SJohn Rigby 		cur = (blocks_todo > mmc->b_max) ?  mmc->b_max : blocks_todo;
4300158126eSLei Wen 		if(mmc_write_blocks(mmc, start, cur, src) != cur)
431def412b6SSteve Sakoman 			return 0;
4320158126eSLei Wen 		blocks_todo -= cur;
4330158126eSLei Wen 		start += cur;
4340158126eSLei Wen 		src += cur * mmc->write_bl_len;
4350158126eSLei Wen 	} while (blocks_todo > 0);
436272cc70bSAndy Fleming 
437272cc70bSAndy Fleming 	return blkcnt;
438272cc70bSAndy Fleming }
439272cc70bSAndy Fleming 
4404a1a06bcSAlagu Sankar int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt)
441272cc70bSAndy Fleming {
442272cc70bSAndy Fleming 	struct mmc_cmd cmd;
443272cc70bSAndy Fleming 	struct mmc_data data;
444272cc70bSAndy Fleming 
4454a1a06bcSAlagu Sankar 	if (blkcnt > 1)
4464a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
4474a1a06bcSAlagu Sankar 	else
448272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
449272cc70bSAndy Fleming 
450272cc70bSAndy Fleming 	if (mmc->high_capacity)
4514a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
452272cc70bSAndy Fleming 	else
4534a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
454272cc70bSAndy Fleming 
455272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
456272cc70bSAndy Fleming 
457272cc70bSAndy Fleming 	data.dest = dst;
4584a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
459272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
460272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
461272cc70bSAndy Fleming 
4624a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
4634a1a06bcSAlagu Sankar 		return 0;
4644a1a06bcSAlagu Sankar 
4654a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
4664a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
4674a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
4684a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
4694a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
4704a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
4714a1a06bcSAlagu Sankar 			return 0;
4724a1a06bcSAlagu Sankar 		}
473272cc70bSAndy Fleming 	}
474272cc70bSAndy Fleming 
4754a1a06bcSAlagu Sankar 	return blkcnt;
476272cc70bSAndy Fleming }
477272cc70bSAndy Fleming 
478272cc70bSAndy Fleming static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
479272cc70bSAndy Fleming {
4804a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
481272cc70bSAndy Fleming 
4824a1a06bcSAlagu Sankar 	if (blkcnt == 0)
4834a1a06bcSAlagu Sankar 		return 0;
4844a1a06bcSAlagu Sankar 
4854a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
486272cc70bSAndy Fleming 	if (!mmc)
487272cc70bSAndy Fleming 		return 0;
488272cc70bSAndy Fleming 
489d2bf29e3SLei Wen 	if ((start + blkcnt) > mmc->block_dev.lba) {
4904a1a06bcSAlagu Sankar 		printf("MMC: block number 0x%lx exceeds max(0x%lx)\n",
491d2bf29e3SLei Wen 			start + blkcnt, mmc->block_dev.lba);
492d2bf29e3SLei Wen 		return 0;
493d2bf29e3SLei Wen 	}
494272cc70bSAndy Fleming 
4954a1a06bcSAlagu Sankar 	if (mmc_set_blocklen(mmc, mmc->read_bl_len))
496272cc70bSAndy Fleming 		return 0;
497272cc70bSAndy Fleming 
4984a1a06bcSAlagu Sankar 	do {
4998feafcc4SJohn Rigby 		cur = (blocks_todo > mmc->b_max) ?  mmc->b_max : blocks_todo;
5004a1a06bcSAlagu Sankar 		if(mmc_read_blocks(mmc, dst, start, cur) != cur)
5014a1a06bcSAlagu Sankar 			return 0;
5024a1a06bcSAlagu Sankar 		blocks_todo -= cur;
5034a1a06bcSAlagu Sankar 		start += cur;
5044a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
5054a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
506272cc70bSAndy Fleming 
507272cc70bSAndy Fleming 	return blkcnt;
508272cc70bSAndy Fleming }
509272cc70bSAndy Fleming 
510272cc70bSAndy Fleming int mmc_go_idle(struct mmc* mmc)
511272cc70bSAndy Fleming {
512272cc70bSAndy Fleming 	struct mmc_cmd cmd;
513272cc70bSAndy Fleming 	int err;
514272cc70bSAndy Fleming 
515272cc70bSAndy Fleming 	udelay(1000);
516272cc70bSAndy Fleming 
517272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
518272cc70bSAndy Fleming 	cmd.cmdarg = 0;
519272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
520272cc70bSAndy Fleming 
521272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
522272cc70bSAndy Fleming 
523272cc70bSAndy Fleming 	if (err)
524272cc70bSAndy Fleming 		return err;
525272cc70bSAndy Fleming 
526272cc70bSAndy Fleming 	udelay(2000);
527272cc70bSAndy Fleming 
528272cc70bSAndy Fleming 	return 0;
529272cc70bSAndy Fleming }
530272cc70bSAndy Fleming 
531272cc70bSAndy Fleming int
532272cc70bSAndy Fleming sd_send_op_cond(struct mmc *mmc)
533272cc70bSAndy Fleming {
534272cc70bSAndy Fleming 	int timeout = 1000;
535272cc70bSAndy Fleming 	int err;
536272cc70bSAndy Fleming 	struct mmc_cmd cmd;
537272cc70bSAndy Fleming 
538272cc70bSAndy Fleming 	do {
539272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
540272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
541272cc70bSAndy Fleming 		cmd.cmdarg = 0;
542272cc70bSAndy Fleming 
543272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
544272cc70bSAndy Fleming 
545272cc70bSAndy Fleming 		if (err)
546272cc70bSAndy Fleming 			return err;
547272cc70bSAndy Fleming 
548272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
549272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
550250de12bSStefano Babic 
551250de12bSStefano Babic 		/*
552250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
553250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
554250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
555250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
556250de12bSStefano Babic 		 * specified.
557250de12bSStefano Babic 		 */
558d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
559d52ebf10SThomas Chou 			(mmc->voltages & 0xff8000);
560272cc70bSAndy Fleming 
561272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
562272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
563272cc70bSAndy Fleming 
564272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
565272cc70bSAndy Fleming 
566272cc70bSAndy Fleming 		if (err)
567272cc70bSAndy Fleming 			return err;
568272cc70bSAndy Fleming 
569272cc70bSAndy Fleming 		udelay(1000);
570272cc70bSAndy Fleming 	} while ((!(cmd.response[0] & OCR_BUSY)) && timeout--);
571272cc70bSAndy Fleming 
572272cc70bSAndy Fleming 	if (timeout <= 0)
573272cc70bSAndy Fleming 		return UNUSABLE_ERR;
574272cc70bSAndy Fleming 
575272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
576272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
577272cc70bSAndy Fleming 
578d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
579d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
580d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
581d52ebf10SThomas Chou 		cmd.cmdarg = 0;
582d52ebf10SThomas Chou 
583d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
584d52ebf10SThomas Chou 
585d52ebf10SThomas Chou 		if (err)
586d52ebf10SThomas Chou 			return err;
587d52ebf10SThomas Chou 	}
588d52ebf10SThomas Chou 
589998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
590272cc70bSAndy Fleming 
591272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
592272cc70bSAndy Fleming 	mmc->rca = 0;
593272cc70bSAndy Fleming 
594272cc70bSAndy Fleming 	return 0;
595272cc70bSAndy Fleming }
596272cc70bSAndy Fleming 
597272cc70bSAndy Fleming int mmc_send_op_cond(struct mmc *mmc)
598272cc70bSAndy Fleming {
59931cacbabSRaffaele Recalcati 	int timeout = 10000;
600272cc70bSAndy Fleming 	struct mmc_cmd cmd;
601272cc70bSAndy Fleming 	int err;
602272cc70bSAndy Fleming 
603272cc70bSAndy Fleming 	/* Some cards seem to need this */
604272cc70bSAndy Fleming 	mmc_go_idle(mmc);
605272cc70bSAndy Fleming 
60631cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
60731cacbabSRaffaele Recalcati  	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
60831cacbabSRaffaele Recalcati  	cmd.resp_type = MMC_RSP_R3;
60931cacbabSRaffaele Recalcati  	cmd.cmdarg = 0;
61031cacbabSRaffaele Recalcati 
61131cacbabSRaffaele Recalcati  	err = mmc_send_cmd(mmc, &cmd, NULL);
61231cacbabSRaffaele Recalcati 
61331cacbabSRaffaele Recalcati  	if (err)
61431cacbabSRaffaele Recalcati  		return err;
61531cacbabSRaffaele Recalcati 
61631cacbabSRaffaele Recalcati  	udelay(1000);
61731cacbabSRaffaele Recalcati 
618272cc70bSAndy Fleming 	do {
619272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SEND_OP_COND;
620272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
62131cacbabSRaffaele Recalcati 		cmd.cmdarg = (mmc_host_is_spi(mmc) ? 0 :
62231cacbabSRaffaele Recalcati 				(mmc->voltages &
62331cacbabSRaffaele Recalcati 				(cmd.response[0] & OCR_VOLTAGE_MASK)) |
62431cacbabSRaffaele Recalcati 				(cmd.response[0] & OCR_ACCESS_MODE));
625b1f1e821SŁukasz Majewski 
626b1f1e821SŁukasz Majewski 		if (mmc->host_caps & MMC_MODE_HC)
627b1f1e821SŁukasz Majewski 			cmd.cmdarg |= OCR_HCS;
628b1f1e821SŁukasz Majewski 
629272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
630272cc70bSAndy Fleming 
631272cc70bSAndy Fleming 		if (err)
632272cc70bSAndy Fleming 			return err;
633272cc70bSAndy Fleming 
634272cc70bSAndy Fleming 		udelay(1000);
635272cc70bSAndy Fleming 	} while (!(cmd.response[0] & OCR_BUSY) && timeout--);
636272cc70bSAndy Fleming 
637272cc70bSAndy Fleming 	if (timeout <= 0)
638272cc70bSAndy Fleming 		return UNUSABLE_ERR;
639272cc70bSAndy Fleming 
640d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
641d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
642d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
643d52ebf10SThomas Chou 		cmd.cmdarg = 0;
644d52ebf10SThomas Chou 
645d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
646d52ebf10SThomas Chou 
647d52ebf10SThomas Chou 		if (err)
648d52ebf10SThomas Chou 			return err;
649d52ebf10SThomas Chou 	}
650d52ebf10SThomas Chou 
651272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
652998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
653272cc70bSAndy Fleming 
654272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
655272cc70bSAndy Fleming 	mmc->rca = 0;
656272cc70bSAndy Fleming 
657272cc70bSAndy Fleming 	return 0;
658272cc70bSAndy Fleming }
659272cc70bSAndy Fleming 
660272cc70bSAndy Fleming 
661cdfd1ac6SYoshihiro Shimoda int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
662272cc70bSAndy Fleming {
663272cc70bSAndy Fleming 	struct mmc_cmd cmd;
664272cc70bSAndy Fleming 	struct mmc_data data;
665272cc70bSAndy Fleming 	int err;
666272cc70bSAndy Fleming 
667272cc70bSAndy Fleming 	/* Get the Card Status Register */
668272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
669272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
670272cc70bSAndy Fleming 	cmd.cmdarg = 0;
671272cc70bSAndy Fleming 
672cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
673272cc70bSAndy Fleming 	data.blocks = 1;
674272cc70bSAndy Fleming 	data.blocksize = 512;
675272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
676272cc70bSAndy Fleming 
677272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
678272cc70bSAndy Fleming 
679272cc70bSAndy Fleming 	return err;
680272cc70bSAndy Fleming }
681272cc70bSAndy Fleming 
682272cc70bSAndy Fleming 
683272cc70bSAndy Fleming int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
684272cc70bSAndy Fleming {
685272cc70bSAndy Fleming 	struct mmc_cmd cmd;
6865d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
6875d4fc8d9SRaffaele Recalcati 	int ret;
688272cc70bSAndy Fleming 
689272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
690272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
691272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
692272cc70bSAndy Fleming 				 (index << 16) |
693272cc70bSAndy Fleming 				 (value << 8);
694272cc70bSAndy Fleming 
6955d4fc8d9SRaffaele Recalcati 	ret = mmc_send_cmd(mmc, &cmd, NULL);
6965d4fc8d9SRaffaele Recalcati 
6975d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
69893ad0d18SJan Kloetzke 	if (!ret)
69993ad0d18SJan Kloetzke 		ret = mmc_send_status(mmc, timeout);
7005d4fc8d9SRaffaele Recalcati 
7015d4fc8d9SRaffaele Recalcati 	return ret;
7025d4fc8d9SRaffaele Recalcati 
703272cc70bSAndy Fleming }
704272cc70bSAndy Fleming 
705272cc70bSAndy Fleming int mmc_change_freq(struct mmc *mmc)
706272cc70bSAndy Fleming {
707cdfd1ac6SYoshihiro Shimoda 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, 512);
708272cc70bSAndy Fleming 	char cardtype;
709272cc70bSAndy Fleming 	int err;
710272cc70bSAndy Fleming 
711272cc70bSAndy Fleming 	mmc->card_caps = 0;
712272cc70bSAndy Fleming 
713d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
714d52ebf10SThomas Chou 		return 0;
715d52ebf10SThomas Chou 
716272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
717272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
718272cc70bSAndy Fleming 		return 0;
719272cc70bSAndy Fleming 
720272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
721272cc70bSAndy Fleming 
722272cc70bSAndy Fleming 	if (err)
723272cc70bSAndy Fleming 		return err;
724272cc70bSAndy Fleming 
7250560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
726272cc70bSAndy Fleming 
727272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
728272cc70bSAndy Fleming 
729272cc70bSAndy Fleming 	if (err)
730272cc70bSAndy Fleming 		return err;
731272cc70bSAndy Fleming 
732272cc70bSAndy Fleming 	/* Now check to see that it worked */
733272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
734272cc70bSAndy Fleming 
735272cc70bSAndy Fleming 	if (err)
736272cc70bSAndy Fleming 		return err;
737272cc70bSAndy Fleming 
738272cc70bSAndy Fleming 	/* No high-speed support */
7390560db18SLei Wen 	if (!ext_csd[EXT_CSD_HS_TIMING])
740272cc70bSAndy Fleming 		return 0;
741272cc70bSAndy Fleming 
742272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
743272cc70bSAndy Fleming 	if (cardtype & MMC_HS_52MHZ)
744272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
745272cc70bSAndy Fleming 	else
746272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
747272cc70bSAndy Fleming 
748272cc70bSAndy Fleming 	return 0;
749272cc70bSAndy Fleming }
750272cc70bSAndy Fleming 
751bc897b1dSLei Wen int mmc_switch_part(int dev_num, unsigned int part_num)
752bc897b1dSLei Wen {
753bc897b1dSLei Wen 	struct mmc *mmc = find_mmc_device(dev_num);
754bc897b1dSLei Wen 
755bc897b1dSLei Wen 	if (!mmc)
756bc897b1dSLei Wen 		return -1;
757bc897b1dSLei Wen 
758bc897b1dSLei Wen 	return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
759bc897b1dSLei Wen 			  (mmc->part_config & ~PART_ACCESS_MASK)
760bc897b1dSLei Wen 			  | (part_num & PART_ACCESS_MASK));
761bc897b1dSLei Wen }
762bc897b1dSLei Wen 
76348972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
76448972d90SThierry Reding {
76548972d90SThierry Reding 	int cd;
76648972d90SThierry Reding 
76748972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
76848972d90SThierry Reding 
76948972d90SThierry Reding 	if ((cd < 0) && mmc->getcd)
77048972d90SThierry Reding 		cd = mmc->getcd(mmc);
77148972d90SThierry Reding 
77248972d90SThierry Reding 	return cd;
77348972d90SThierry Reding }
77448972d90SThierry Reding 
775272cc70bSAndy Fleming int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
776272cc70bSAndy Fleming {
777272cc70bSAndy Fleming 	struct mmc_cmd cmd;
778272cc70bSAndy Fleming 	struct mmc_data data;
779272cc70bSAndy Fleming 
780272cc70bSAndy Fleming 	/* Switch the frequency */
781272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
782272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
783272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
784272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
785272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
786272cc70bSAndy Fleming 
787272cc70bSAndy Fleming 	data.dest = (char *)resp;
788272cc70bSAndy Fleming 	data.blocksize = 64;
789272cc70bSAndy Fleming 	data.blocks = 1;
790272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
791272cc70bSAndy Fleming 
792272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
793272cc70bSAndy Fleming }
794272cc70bSAndy Fleming 
795272cc70bSAndy Fleming 
796272cc70bSAndy Fleming int sd_change_freq(struct mmc *mmc)
797272cc70bSAndy Fleming {
798272cc70bSAndy Fleming 	int err;
799272cc70bSAndy Fleming 	struct mmc_cmd cmd;
800f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
801f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
802272cc70bSAndy Fleming 	struct mmc_data data;
803272cc70bSAndy Fleming 	int timeout;
804272cc70bSAndy Fleming 
805272cc70bSAndy Fleming 	mmc->card_caps = 0;
806272cc70bSAndy Fleming 
807d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
808d52ebf10SThomas Chou 		return 0;
809d52ebf10SThomas Chou 
810272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
811272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
812272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
813272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
814272cc70bSAndy Fleming 
815272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
816272cc70bSAndy Fleming 
817272cc70bSAndy Fleming 	if (err)
818272cc70bSAndy Fleming 		return err;
819272cc70bSAndy Fleming 
820272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
821272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
822272cc70bSAndy Fleming 	cmd.cmdarg = 0;
823272cc70bSAndy Fleming 
824272cc70bSAndy Fleming 	timeout = 3;
825272cc70bSAndy Fleming 
826272cc70bSAndy Fleming retry_scr:
827f781dd38SAnton staaf 	data.dest = (char *)scr;
828272cc70bSAndy Fleming 	data.blocksize = 8;
829272cc70bSAndy Fleming 	data.blocks = 1;
830272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
831272cc70bSAndy Fleming 
832272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
833272cc70bSAndy Fleming 
834272cc70bSAndy Fleming 	if (err) {
835272cc70bSAndy Fleming 		if (timeout--)
836272cc70bSAndy Fleming 			goto retry_scr;
837272cc70bSAndy Fleming 
838272cc70bSAndy Fleming 		return err;
839272cc70bSAndy Fleming 	}
840272cc70bSAndy Fleming 
8414e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
8424e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
843272cc70bSAndy Fleming 
844272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
845272cc70bSAndy Fleming 		case 0:
846272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
847272cc70bSAndy Fleming 			break;
848272cc70bSAndy Fleming 		case 1:
849272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_10;
850272cc70bSAndy Fleming 			break;
851272cc70bSAndy Fleming 		case 2:
852272cc70bSAndy Fleming 			mmc->version = SD_VERSION_2;
853272cc70bSAndy Fleming 			break;
854272cc70bSAndy Fleming 		default:
855272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
856272cc70bSAndy Fleming 			break;
857272cc70bSAndy Fleming 	}
858272cc70bSAndy Fleming 
859b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
860b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
861b44c7083SAlagu Sankar 
862272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
863272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
864272cc70bSAndy Fleming 		return 0;
865272cc70bSAndy Fleming 
866272cc70bSAndy Fleming 	timeout = 4;
867272cc70bSAndy Fleming 	while (timeout--) {
868272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
869f781dd38SAnton staaf 				(u8 *)switch_status);
870272cc70bSAndy Fleming 
871272cc70bSAndy Fleming 		if (err)
872272cc70bSAndy Fleming 			return err;
873272cc70bSAndy Fleming 
874272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
8754e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
876272cc70bSAndy Fleming 			break;
877272cc70bSAndy Fleming 	}
878272cc70bSAndy Fleming 
879272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
8804e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
881272cc70bSAndy Fleming 		return 0;
882272cc70bSAndy Fleming 
8832c3fbf4cSMacpaul Lin 	/*
8842c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
8852c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
8862c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
8872c3fbf4cSMacpaul Lin 	 * mode between the host.
8882c3fbf4cSMacpaul Lin 	 */
8892c3fbf4cSMacpaul Lin 	if (!((mmc->host_caps & MMC_MODE_HS_52MHz) &&
8902c3fbf4cSMacpaul Lin 		(mmc->host_caps & MMC_MODE_HS)))
8912c3fbf4cSMacpaul Lin 		return 0;
8922c3fbf4cSMacpaul Lin 
893f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
894272cc70bSAndy Fleming 
895272cc70bSAndy Fleming 	if (err)
896272cc70bSAndy Fleming 		return err;
897272cc70bSAndy Fleming 
8984e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
899272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
900272cc70bSAndy Fleming 
901272cc70bSAndy Fleming 	return 0;
902272cc70bSAndy Fleming }
903272cc70bSAndy Fleming 
904272cc70bSAndy Fleming /* frequency bases */
905272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
9065f837c2cSMike Frysinger static const int fbase[] = {
907272cc70bSAndy Fleming 	10000,
908272cc70bSAndy Fleming 	100000,
909272cc70bSAndy Fleming 	1000000,
910272cc70bSAndy Fleming 	10000000,
911272cc70bSAndy Fleming };
912272cc70bSAndy Fleming 
913272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
914272cc70bSAndy Fleming  * to platforms without floating point.
915272cc70bSAndy Fleming  */
9165f837c2cSMike Frysinger static const int multipliers[] = {
917272cc70bSAndy Fleming 	0,	/* reserved */
918272cc70bSAndy Fleming 	10,
919272cc70bSAndy Fleming 	12,
920272cc70bSAndy Fleming 	13,
921272cc70bSAndy Fleming 	15,
922272cc70bSAndy Fleming 	20,
923272cc70bSAndy Fleming 	25,
924272cc70bSAndy Fleming 	30,
925272cc70bSAndy Fleming 	35,
926272cc70bSAndy Fleming 	40,
927272cc70bSAndy Fleming 	45,
928272cc70bSAndy Fleming 	50,
929272cc70bSAndy Fleming 	55,
930272cc70bSAndy Fleming 	60,
931272cc70bSAndy Fleming 	70,
932272cc70bSAndy Fleming 	80,
933272cc70bSAndy Fleming };
934272cc70bSAndy Fleming 
935272cc70bSAndy Fleming void mmc_set_ios(struct mmc *mmc)
936272cc70bSAndy Fleming {
937272cc70bSAndy Fleming 	mmc->set_ios(mmc);
938272cc70bSAndy Fleming }
939272cc70bSAndy Fleming 
940272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
941272cc70bSAndy Fleming {
942272cc70bSAndy Fleming 	if (clock > mmc->f_max)
943272cc70bSAndy Fleming 		clock = mmc->f_max;
944272cc70bSAndy Fleming 
945272cc70bSAndy Fleming 	if (clock < mmc->f_min)
946272cc70bSAndy Fleming 		clock = mmc->f_min;
947272cc70bSAndy Fleming 
948272cc70bSAndy Fleming 	mmc->clock = clock;
949272cc70bSAndy Fleming 
950272cc70bSAndy Fleming 	mmc_set_ios(mmc);
951272cc70bSAndy Fleming }
952272cc70bSAndy Fleming 
953272cc70bSAndy Fleming void mmc_set_bus_width(struct mmc *mmc, uint width)
954272cc70bSAndy Fleming {
955272cc70bSAndy Fleming 	mmc->bus_width = width;
956272cc70bSAndy Fleming 
957272cc70bSAndy Fleming 	mmc_set_ios(mmc);
958272cc70bSAndy Fleming }
959272cc70bSAndy Fleming 
960272cc70bSAndy Fleming int mmc_startup(struct mmc *mmc)
961272cc70bSAndy Fleming {
9624137894eSLei Wen 	int err, width;
963272cc70bSAndy Fleming 	uint mult, freq;
964639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
965272cc70bSAndy Fleming 	struct mmc_cmd cmd;
966cdfd1ac6SYoshihiro Shimoda 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, 512);
967cdfd1ac6SYoshihiro Shimoda 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, 512);
9685d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
969272cc70bSAndy Fleming 
970d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
971d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
972d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
973d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
974d52ebf10SThomas Chou 		cmd.cmdarg = 1;
975d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
976d52ebf10SThomas Chou 
977d52ebf10SThomas Chou 		if (err)
978d52ebf10SThomas Chou 			return err;
979d52ebf10SThomas Chou 	}
980d52ebf10SThomas Chou #endif
981d52ebf10SThomas Chou 
982272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
983d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
984d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
985272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
986272cc70bSAndy Fleming 	cmd.cmdarg = 0;
987272cc70bSAndy Fleming 
988272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
989272cc70bSAndy Fleming 
990272cc70bSAndy Fleming 	if (err)
991272cc70bSAndy Fleming 		return err;
992272cc70bSAndy Fleming 
993272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
994272cc70bSAndy Fleming 
995272cc70bSAndy Fleming 	/*
996272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
997272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
998272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
999272cc70bSAndy Fleming 	 */
1000d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1001272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1002272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1003272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1004272cc70bSAndy Fleming 
1005272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1006272cc70bSAndy Fleming 
1007272cc70bSAndy Fleming 		if (err)
1008272cc70bSAndy Fleming 			return err;
1009272cc70bSAndy Fleming 
1010272cc70bSAndy Fleming 		if (IS_SD(mmc))
1011998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1012d52ebf10SThomas Chou 	}
1013272cc70bSAndy Fleming 
1014272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1015272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1016272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1017272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1018272cc70bSAndy Fleming 
1019272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1020272cc70bSAndy Fleming 
10215d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
10225d4fc8d9SRaffaele Recalcati 	mmc_send_status(mmc, timeout);
10235d4fc8d9SRaffaele Recalcati 
1024272cc70bSAndy Fleming 	if (err)
1025272cc70bSAndy Fleming 		return err;
1026272cc70bSAndy Fleming 
1027998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1028998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1029998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1030998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1031272cc70bSAndy Fleming 
1032272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
10330b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1034272cc70bSAndy Fleming 
1035272cc70bSAndy Fleming 		switch (version) {
1036272cc70bSAndy Fleming 			case 0:
1037272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
1038272cc70bSAndy Fleming 				break;
1039272cc70bSAndy Fleming 			case 1:
1040272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_4;
1041272cc70bSAndy Fleming 				break;
1042272cc70bSAndy Fleming 			case 2:
1043272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_2_2;
1044272cc70bSAndy Fleming 				break;
1045272cc70bSAndy Fleming 			case 3:
1046272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_3;
1047272cc70bSAndy Fleming 				break;
1048272cc70bSAndy Fleming 			case 4:
1049272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_4;
1050272cc70bSAndy Fleming 				break;
1051272cc70bSAndy Fleming 			default:
1052272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
1053272cc70bSAndy Fleming 				break;
1054272cc70bSAndy Fleming 		}
1055272cc70bSAndy Fleming 	}
1056272cc70bSAndy Fleming 
1057272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
10580b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
10590b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1060272cc70bSAndy Fleming 
1061272cc70bSAndy Fleming 	mmc->tran_speed = freq * mult;
1062272cc70bSAndy Fleming 
1063998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1064272cc70bSAndy Fleming 
1065272cc70bSAndy Fleming 	if (IS_SD(mmc))
1066272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1067272cc70bSAndy Fleming 	else
1068998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1069272cc70bSAndy Fleming 
1070272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1071272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1072272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1073272cc70bSAndy Fleming 		cmult = 8;
1074272cc70bSAndy Fleming 	} else {
1075272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1076272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1077272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1078272cc70bSAndy Fleming 	}
1079272cc70bSAndy Fleming 
1080272cc70bSAndy Fleming 	mmc->capacity = (csize + 1) << (cmult + 2);
1081272cc70bSAndy Fleming 	mmc->capacity *= mmc->read_bl_len;
1082272cc70bSAndy Fleming 
1083272cc70bSAndy Fleming 	if (mmc->read_bl_len > 512)
1084272cc70bSAndy Fleming 		mmc->read_bl_len = 512;
1085272cc70bSAndy Fleming 
1086272cc70bSAndy Fleming 	if (mmc->write_bl_len > 512)
1087272cc70bSAndy Fleming 		mmc->write_bl_len = 512;
1088272cc70bSAndy Fleming 
1089272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1090d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1091272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1092fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1093272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1094272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1095272cc70bSAndy Fleming 
1096272cc70bSAndy Fleming 		if (err)
1097272cc70bSAndy Fleming 			return err;
1098d52ebf10SThomas Chou 	}
1099272cc70bSAndy Fleming 
1100e6f99a56SLei Wen 	/*
1101e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1102e6f99a56SLei Wen 	 */
1103e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1104bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1105d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
1106d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
1107d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
11080560db18SLei Wen 		if (!err & (ext_csd[EXT_CSD_REV] >= 2)) {
1109639b7827SYoshihiro Shimoda 			/*
1110639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
1111639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
1112639b7827SYoshihiro Shimoda 			 * than 2GB
1113639b7827SYoshihiro Shimoda 			 */
11140560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
11150560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
11160560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
11170560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1118639b7827SYoshihiro Shimoda 			capacity *= 512;
1119b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
1120639b7827SYoshihiro Shimoda 				mmc->capacity = capacity;
1121d23e2c09SSukumar Ghorai 		}
1122bc897b1dSLei Wen 
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 		 */
11280560db18SLei Wen 		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF])
11290560db18SLei Wen 			mmc->erase_grp_size =
11300560db18SLei Wen 			      ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 512 * 1024;
1131e6f99a56SLei Wen 		else {
1132e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
1133e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1134e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1135e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
1136e6f99a56SLei Wen 				* (erase_gmul + 1);
1137e6f99a56SLei Wen 		}
1138e6f99a56SLei Wen 
1139bc897b1dSLei Wen 		/* store the partition info of emmc */
11408948ea83SStephen Warren 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
11418948ea83SStephen Warren 		    ext_csd[EXT_CSD_BOOT_MULT])
11420560db18SLei Wen 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
1143d23e2c09SSukumar Ghorai 	}
1144d23e2c09SSukumar Ghorai 
1145272cc70bSAndy Fleming 	if (IS_SD(mmc))
1146272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1147272cc70bSAndy Fleming 	else
1148272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1149272cc70bSAndy Fleming 
1150272cc70bSAndy Fleming 	if (err)
1151272cc70bSAndy Fleming 		return err;
1152272cc70bSAndy Fleming 
1153272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
1154272cc70bSAndy Fleming 	mmc->card_caps &= mmc->host_caps;
1155272cc70bSAndy Fleming 
1156272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1157272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1158272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1159272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1160272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1161272cc70bSAndy Fleming 
1162272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1163272cc70bSAndy Fleming 			if (err)
1164272cc70bSAndy Fleming 				return err;
1165272cc70bSAndy Fleming 
1166272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1167272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1168272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1169272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1170272cc70bSAndy Fleming 			if (err)
1171272cc70bSAndy Fleming 				return err;
1172272cc70bSAndy Fleming 
1173272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1174272cc70bSAndy Fleming 		}
1175272cc70bSAndy Fleming 
1176272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
1177ad5fd922SJaehoon Chung 			mmc->tran_speed = 50000000;
1178272cc70bSAndy Fleming 		else
1179ad5fd922SJaehoon Chung 			mmc->tran_speed = 25000000;
1180272cc70bSAndy Fleming 	} else {
118162722036SŁukasz Majewski 		width = ((mmc->host_caps & MMC_MODE_MASK_WIDTH_BITS) >>
118262722036SŁukasz Majewski 			 MMC_MODE_WIDTH_BITS_SHIFT);
118362722036SŁukasz Majewski 		for (; width >= 0; width--) {
1184272cc70bSAndy Fleming 			/* Set the card to use 4 bit*/
1185272cc70bSAndy Fleming 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
11864137894eSLei Wen 					EXT_CSD_BUS_WIDTH, width);
1187272cc70bSAndy Fleming 
1188272cc70bSAndy Fleming 			if (err)
11894137894eSLei Wen 				continue;
1190272cc70bSAndy Fleming 
11914137894eSLei Wen 			if (!width) {
11924137894eSLei Wen 				mmc_set_bus_width(mmc, 1);
11934137894eSLei Wen 				break;
11944137894eSLei Wen 			} else
11954137894eSLei Wen 				mmc_set_bus_width(mmc, 4 * width);
1196272cc70bSAndy Fleming 
11974137894eSLei Wen 			err = mmc_send_ext_csd(mmc, test_csd);
11984137894eSLei Wen 			if (!err && ext_csd[EXT_CSD_PARTITIONING_SUPPORT] \
11994137894eSLei Wen 				    == test_csd[EXT_CSD_PARTITIONING_SUPPORT]
12004137894eSLei Wen 				 && ext_csd[EXT_CSD_ERASE_GROUP_DEF] \
12014137894eSLei Wen 				    == test_csd[EXT_CSD_ERASE_GROUP_DEF] \
12024137894eSLei Wen 				 && ext_csd[EXT_CSD_REV] \
12034137894eSLei Wen 				    == test_csd[EXT_CSD_REV]
12044137894eSLei Wen 				 && ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] \
12054137894eSLei Wen 				    == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
12064137894eSLei Wen 				 && memcmp(&ext_csd[EXT_CSD_SEC_CNT], \
12074137894eSLei Wen 					&test_csd[EXT_CSD_SEC_CNT], 4) == 0) {
1208272cc70bSAndy Fleming 
12094137894eSLei Wen 				mmc->card_caps |= width;
12104137894eSLei Wen 				break;
12114137894eSLei Wen 			}
1212272cc70bSAndy Fleming 		}
1213272cc70bSAndy Fleming 
1214272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS) {
1215272cc70bSAndy Fleming 			if (mmc->card_caps & MMC_MODE_HS_52MHz)
1216ad5fd922SJaehoon Chung 				mmc->tran_speed = 52000000;
1217272cc70bSAndy Fleming 			else
1218ad5fd922SJaehoon Chung 				mmc->tran_speed = 26000000;
1219272cc70bSAndy Fleming 		}
1220ad5fd922SJaehoon Chung 	}
1221ad5fd922SJaehoon Chung 
1222ad5fd922SJaehoon Chung 	mmc_set_clock(mmc, mmc->tran_speed);
1223272cc70bSAndy Fleming 
1224272cc70bSAndy Fleming 	/* fill in device description */
1225272cc70bSAndy Fleming 	mmc->block_dev.lun = 0;
1226272cc70bSAndy Fleming 	mmc->block_dev.type = 0;
1227272cc70bSAndy Fleming 	mmc->block_dev.blksz = mmc->read_bl_len;
12289b1f942cSRabin Vincent 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
12290b453ffeSRabin Vincent 	sprintf(mmc->block_dev.vendor, "Man %06x Snr %08x", mmc->cid[0] >> 8,
12300b453ffeSRabin Vincent 			(mmc->cid[2] << 8) | (mmc->cid[3] >> 24));
12310b453ffeSRabin Vincent 	sprintf(mmc->block_dev.product, "%c%c%c%c%c", mmc->cid[0] & 0xff,
12320b453ffeSRabin Vincent 			(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
12330b453ffeSRabin Vincent 			(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff);
12340b453ffeSRabin Vincent 	sprintf(mmc->block_dev.revision, "%d.%d", mmc->cid[2] >> 28,
12350b453ffeSRabin Vincent 			(mmc->cid[2] >> 24) & 0xf);
1236122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1237272cc70bSAndy Fleming 	init_part(&mmc->block_dev);
1238122efd43SMikhail Kshevetskiy #endif
1239272cc70bSAndy Fleming 
1240272cc70bSAndy Fleming 	return 0;
1241272cc70bSAndy Fleming }
1242272cc70bSAndy Fleming 
1243272cc70bSAndy Fleming int mmc_send_if_cond(struct mmc *mmc)
1244272cc70bSAndy Fleming {
1245272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1246272cc70bSAndy Fleming 	int err;
1247272cc70bSAndy Fleming 
1248272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1249272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
1250272cc70bSAndy Fleming 	cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa;
1251272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1252272cc70bSAndy Fleming 
1253272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1254272cc70bSAndy Fleming 
1255272cc70bSAndy Fleming 	if (err)
1256272cc70bSAndy Fleming 		return err;
1257272cc70bSAndy Fleming 
1258998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1259272cc70bSAndy Fleming 		return UNUSABLE_ERR;
1260272cc70bSAndy Fleming 	else
1261272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1262272cc70bSAndy Fleming 
1263272cc70bSAndy Fleming 	return 0;
1264272cc70bSAndy Fleming }
1265272cc70bSAndy Fleming 
1266272cc70bSAndy Fleming int mmc_register(struct mmc *mmc)
1267272cc70bSAndy Fleming {
1268272cc70bSAndy Fleming 	/* Setup the universal parts of the block interface just once */
1269272cc70bSAndy Fleming 	mmc->block_dev.if_type = IF_TYPE_MMC;
1270272cc70bSAndy Fleming 	mmc->block_dev.dev = cur_dev_num++;
1271272cc70bSAndy Fleming 	mmc->block_dev.removable = 1;
1272272cc70bSAndy Fleming 	mmc->block_dev.block_read = mmc_bread;
1273272cc70bSAndy Fleming 	mmc->block_dev.block_write = mmc_bwrite;
1274e6f99a56SLei Wen 	mmc->block_dev.block_erase = mmc_berase;
12758feafcc4SJohn Rigby 	if (!mmc->b_max)
12768feafcc4SJohn Rigby 		mmc->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
1277272cc70bSAndy Fleming 
1278272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc->link);
1279272cc70bSAndy Fleming 
1280272cc70bSAndy Fleming 	list_add_tail (&mmc->link, &mmc_devices);
1281272cc70bSAndy Fleming 
1282272cc70bSAndy Fleming 	return 0;
1283272cc70bSAndy Fleming }
1284272cc70bSAndy Fleming 
1285df3fc526SMatthew McClintock #ifdef CONFIG_PARTITIONS
1286272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev)
1287272cc70bSAndy Fleming {
1288272cc70bSAndy Fleming 	struct mmc *mmc = find_mmc_device(dev);
1289*6bb4b4bcSBenoît Thébaudeau 	if (!mmc || mmc_init(mmc))
129040242bc3SŁukasz Majewski 		return NULL;
1291272cc70bSAndy Fleming 
129240242bc3SŁukasz Majewski 	return &mmc->block_dev;
1293272cc70bSAndy Fleming }
1294df3fc526SMatthew McClintock #endif
1295272cc70bSAndy Fleming 
1296272cc70bSAndy Fleming int mmc_init(struct mmc *mmc)
1297272cc70bSAndy Fleming {
1298afd5932bSMacpaul Lin 	int err;
1299272cc70bSAndy Fleming 
130048972d90SThierry Reding 	if (mmc_getcd(mmc) == 0) {
130148972d90SThierry Reding 		mmc->has_init = 0;
130248972d90SThierry Reding 		printf("MMC: no card present\n");
130348972d90SThierry Reding 		return NO_CARD_ERR;
130448972d90SThierry Reding 	}
130548972d90SThierry Reding 
1306bc897b1dSLei Wen 	if (mmc->has_init)
1307bc897b1dSLei Wen 		return 0;
1308bc897b1dSLei Wen 
1309272cc70bSAndy Fleming 	err = mmc->init(mmc);
1310272cc70bSAndy Fleming 
1311272cc70bSAndy Fleming 	if (err)
1312272cc70bSAndy Fleming 		return err;
1313272cc70bSAndy Fleming 
1314b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1315b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1316b86b85e2SIlya Yanok 
1317272cc70bSAndy Fleming 	/* Reset the Card */
1318272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1319272cc70bSAndy Fleming 
1320272cc70bSAndy Fleming 	if (err)
1321272cc70bSAndy Fleming 		return err;
1322272cc70bSAndy Fleming 
1323bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1324bc897b1dSLei Wen 	mmc->part_num = 0;
1325bc897b1dSLei Wen 
1326272cc70bSAndy Fleming 	/* Test for SD version 2 */
1327272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1328272cc70bSAndy Fleming 
1329272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1330272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1331272cc70bSAndy Fleming 
1332272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1333272cc70bSAndy Fleming 	if (err == TIMEOUT) {
1334272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1335272cc70bSAndy Fleming 
1336272cc70bSAndy Fleming 		if (err) {
1337272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
1338272cc70bSAndy Fleming 			return UNUSABLE_ERR;
1339272cc70bSAndy Fleming 		}
1340272cc70bSAndy Fleming 	}
1341272cc70bSAndy Fleming 
1342bc897b1dSLei Wen 	err = mmc_startup(mmc);
1343bc897b1dSLei Wen 	if (err)
1344bc897b1dSLei Wen 		mmc->has_init = 0;
1345bc897b1dSLei Wen 	else
1346bc897b1dSLei Wen 		mmc->has_init = 1;
1347bc897b1dSLei Wen 	return err;
1348272cc70bSAndy Fleming }
1349272cc70bSAndy Fleming 
1350272cc70bSAndy Fleming /*
1351272cc70bSAndy Fleming  * CPU and board-specific MMC initializations.  Aliased function
1352272cc70bSAndy Fleming  * signals caller to move on
1353272cc70bSAndy Fleming  */
1354272cc70bSAndy Fleming static int __def_mmc_init(bd_t *bis)
1355272cc70bSAndy Fleming {
1356272cc70bSAndy Fleming 	return -1;
1357272cc70bSAndy Fleming }
1358272cc70bSAndy Fleming 
1359f9a109b3SPeter Tyser int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
1360f9a109b3SPeter Tyser int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
1361272cc70bSAndy Fleming 
1362272cc70bSAndy Fleming void print_mmc_devices(char separator)
1363272cc70bSAndy Fleming {
1364272cc70bSAndy Fleming 	struct mmc *m;
1365272cc70bSAndy Fleming 	struct list_head *entry;
1366272cc70bSAndy Fleming 
1367272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
1368272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
1369272cc70bSAndy Fleming 
1370272cc70bSAndy Fleming 		printf("%s: %d", m->name, m->block_dev.dev);
1371272cc70bSAndy Fleming 
1372272cc70bSAndy Fleming 		if (entry->next != &mmc_devices)
1373272cc70bSAndy Fleming 			printf("%c ", separator);
1374272cc70bSAndy Fleming 	}
1375272cc70bSAndy Fleming 
1376272cc70bSAndy Fleming 	printf("\n");
1377272cc70bSAndy Fleming }
1378272cc70bSAndy Fleming 
1379ea6ebe21SLei Wen int get_mmc_num(void)
1380ea6ebe21SLei Wen {
1381ea6ebe21SLei Wen 	return cur_dev_num;
1382ea6ebe21SLei Wen }
1383ea6ebe21SLei Wen 
1384272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1385272cc70bSAndy Fleming {
1386272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc_devices);
1387272cc70bSAndy Fleming 	cur_dev_num = 0;
1388272cc70bSAndy Fleming 
1389272cc70bSAndy Fleming 	if (board_mmc_init(bis) < 0)
1390272cc70bSAndy Fleming 		cpu_mmc_init(bis);
1391272cc70bSAndy Fleming 
1392272cc70bSAndy Fleming 	print_mmc_devices(',');
1393272cc70bSAndy Fleming 
1394272cc70bSAndy Fleming 	return 0;
1395272cc70bSAndy Fleming }
1396