xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision ad5fd922)
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 	printf("\t\tFLAG\t\t\t %d\n", cmd->flags);
1555db2fe3aSRaffaele Recalcati 	ret = mmc->send_cmd(mmc, cmd, data);
1565db2fe3aSRaffaele Recalcati 	switch (cmd->resp_type) {
1575db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
1585db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
1595db2fe3aSRaffaele Recalcati 			break;
1605db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
1615db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
1625db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1635db2fe3aSRaffaele Recalcati 			break;
1645db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
1655db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
1665db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1675db2fe3aSRaffaele Recalcati 			break;
1685db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
1695db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
1705db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1715db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1725db2fe3aSRaffaele Recalcati 				cmd->response[1]);
1735db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1745db2fe3aSRaffaele Recalcati 				cmd->response[2]);
1755db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1765db2fe3aSRaffaele Recalcati 				cmd->response[3]);
1775db2fe3aSRaffaele Recalcati 			printf("\n");
1785db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
1795db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
1805db2fe3aSRaffaele Recalcati 				int j;
1815db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
182146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
1835db2fe3aSRaffaele Recalcati 				ptr += 3;
1845db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
1855db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
1865db2fe3aSRaffaele Recalcati 				printf("\n");
1875db2fe3aSRaffaele Recalcati 			}
1885db2fe3aSRaffaele Recalcati 			break;
1895db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1905db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1915db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1925db2fe3aSRaffaele Recalcati 			break;
1935db2fe3aSRaffaele Recalcati 		default:
1945db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1955db2fe3aSRaffaele Recalcati 			break;
1965db2fe3aSRaffaele Recalcati 	}
1975db2fe3aSRaffaele Recalcati #else
1988635ff9eSMarek Vasut 	ret = mmc->send_cmd(mmc, cmd, data);
1995db2fe3aSRaffaele Recalcati #endif
2008635ff9eSMarek Vasut 	mmc_bounce_buffer_stop(&backup, data);
2018635ff9eSMarek Vasut 	return ret;
202272cc70bSAndy Fleming }
203272cc70bSAndy Fleming 
2045d4fc8d9SRaffaele Recalcati int mmc_send_status(struct mmc *mmc, int timeout)
2055d4fc8d9SRaffaele Recalcati {
2065d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
207d617c426SJan Kloetzke 	int err, retries = 5;
2085d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
2095d4fc8d9SRaffaele Recalcati 	int status;
2105d4fc8d9SRaffaele Recalcati #endif
2115d4fc8d9SRaffaele Recalcati 
2125d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
2135d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
214aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
215aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
2165d4fc8d9SRaffaele Recalcati 	cmd.flags = 0;
2175d4fc8d9SRaffaele Recalcati 
2185d4fc8d9SRaffaele Recalcati 	do {
2195d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
220d617c426SJan Kloetzke 		if (!err) {
221d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
222d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
223d617c426SJan Kloetzke 			     MMC_STATE_PRG)
2245d4fc8d9SRaffaele Recalcati 				break;
225d617c426SJan Kloetzke 			else if (cmd.response[0] & MMC_STATUS_MASK) {
226d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
227d617c426SJan Kloetzke 					cmd.response[0]);
228d617c426SJan Kloetzke 				return COMM_ERR;
229d617c426SJan Kloetzke 			}
230d617c426SJan Kloetzke 		} else if (--retries < 0)
231d617c426SJan Kloetzke 			return err;
2325d4fc8d9SRaffaele Recalcati 
2335d4fc8d9SRaffaele Recalcati 		udelay(1000);
2345d4fc8d9SRaffaele Recalcati 
2355d4fc8d9SRaffaele Recalcati 	} while (timeout--);
2365d4fc8d9SRaffaele Recalcati 
2375db2fe3aSRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
2385db2fe3aSRaffaele Recalcati 	status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9;
2395db2fe3aSRaffaele Recalcati 	printf("CURR STATE:%d\n", status);
2405db2fe3aSRaffaele Recalcati #endif
2415d4fc8d9SRaffaele Recalcati 	if (!timeout) {
2425d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
2435d4fc8d9SRaffaele Recalcati 		return TIMEOUT;
2445d4fc8d9SRaffaele Recalcati 	}
2455d4fc8d9SRaffaele Recalcati 
2465d4fc8d9SRaffaele Recalcati 	return 0;
2475d4fc8d9SRaffaele Recalcati }
2485d4fc8d9SRaffaele Recalcati 
249272cc70bSAndy Fleming int mmc_set_blocklen(struct mmc *mmc, int len)
250272cc70bSAndy Fleming {
251272cc70bSAndy Fleming 	struct mmc_cmd cmd;
252272cc70bSAndy Fleming 
253272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
254272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
255272cc70bSAndy Fleming 	cmd.cmdarg = len;
256272cc70bSAndy Fleming 	cmd.flags = 0;
257272cc70bSAndy Fleming 
258272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
259272cc70bSAndy Fleming }
260272cc70bSAndy Fleming 
261272cc70bSAndy Fleming struct mmc *find_mmc_device(int dev_num)
262272cc70bSAndy Fleming {
263272cc70bSAndy Fleming 	struct mmc *m;
264272cc70bSAndy Fleming 	struct list_head *entry;
265272cc70bSAndy Fleming 
266272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
267272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
268272cc70bSAndy Fleming 
269272cc70bSAndy Fleming 		if (m->block_dev.dev == dev_num)
270272cc70bSAndy Fleming 			return m;
271272cc70bSAndy Fleming 	}
272272cc70bSAndy Fleming 
273272cc70bSAndy Fleming 	printf("MMC Device %d not found\n", dev_num);
274272cc70bSAndy Fleming 
275272cc70bSAndy Fleming 	return NULL;
276272cc70bSAndy Fleming }
277272cc70bSAndy Fleming 
278e6f99a56SLei Wen static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt)
279e6f99a56SLei Wen {
280e6f99a56SLei Wen 	struct mmc_cmd cmd;
281e6f99a56SLei Wen 	ulong end;
282e6f99a56SLei Wen 	int err, start_cmd, end_cmd;
283e6f99a56SLei Wen 
284e6f99a56SLei Wen 	if (mmc->high_capacity)
285e6f99a56SLei Wen 		end = start + blkcnt - 1;
286e6f99a56SLei Wen 	else {
287e6f99a56SLei Wen 		end = (start + blkcnt - 1) * mmc->write_bl_len;
288e6f99a56SLei Wen 		start *= mmc->write_bl_len;
289e6f99a56SLei Wen 	}
290e6f99a56SLei Wen 
291e6f99a56SLei Wen 	if (IS_SD(mmc)) {
292e6f99a56SLei Wen 		start_cmd = SD_CMD_ERASE_WR_BLK_START;
293e6f99a56SLei Wen 		end_cmd = SD_CMD_ERASE_WR_BLK_END;
294e6f99a56SLei Wen 	} else {
295e6f99a56SLei Wen 		start_cmd = MMC_CMD_ERASE_GROUP_START;
296e6f99a56SLei Wen 		end_cmd = MMC_CMD_ERASE_GROUP_END;
297e6f99a56SLei Wen 	}
298e6f99a56SLei Wen 
299e6f99a56SLei Wen 	cmd.cmdidx = start_cmd;
300e6f99a56SLei Wen 	cmd.cmdarg = start;
301e6f99a56SLei Wen 	cmd.resp_type = MMC_RSP_R1;
302e6f99a56SLei Wen 	cmd.flags = 0;
303e6f99a56SLei Wen 
304e6f99a56SLei Wen 	err = mmc_send_cmd(mmc, &cmd, NULL);
305e6f99a56SLei Wen 	if (err)
306e6f99a56SLei Wen 		goto err_out;
307e6f99a56SLei Wen 
308e6f99a56SLei Wen 	cmd.cmdidx = end_cmd;
309e6f99a56SLei Wen 	cmd.cmdarg = end;
310e6f99a56SLei Wen 
311e6f99a56SLei Wen 	err = mmc_send_cmd(mmc, &cmd, NULL);
312e6f99a56SLei Wen 	if (err)
313e6f99a56SLei Wen 		goto err_out;
314e6f99a56SLei Wen 
315e6f99a56SLei Wen 	cmd.cmdidx = MMC_CMD_ERASE;
316e6f99a56SLei Wen 	cmd.cmdarg = SECURE_ERASE;
317e6f99a56SLei Wen 	cmd.resp_type = MMC_RSP_R1b;
318e6f99a56SLei Wen 
319e6f99a56SLei Wen 	err = mmc_send_cmd(mmc, &cmd, NULL);
320e6f99a56SLei Wen 	if (err)
321e6f99a56SLei Wen 		goto err_out;
322e6f99a56SLei Wen 
323e6f99a56SLei Wen 	return 0;
324e6f99a56SLei Wen 
325e6f99a56SLei Wen err_out:
326e6f99a56SLei Wen 	puts("mmc erase failed\n");
327e6f99a56SLei Wen 	return err;
328e6f99a56SLei Wen }
329e6f99a56SLei Wen 
330e6f99a56SLei Wen static unsigned long
331e6f99a56SLei Wen mmc_berase(int dev_num, unsigned long start, lbaint_t blkcnt)
332e6f99a56SLei Wen {
333e6f99a56SLei Wen 	int err = 0;
334e6f99a56SLei Wen 	struct mmc *mmc = find_mmc_device(dev_num);
335e6f99a56SLei Wen 	lbaint_t blk = 0, blk_r = 0;
336e6f99a56SLei Wen 
337e6f99a56SLei Wen 	if (!mmc)
338e6f99a56SLei Wen 		return -1;
339e6f99a56SLei Wen 
340e6f99a56SLei Wen 	if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size))
341e6f99a56SLei Wen 		printf("\n\nCaution! Your devices Erase group is 0x%x\n"
342e6f99a56SLei Wen 			"The erase range would be change to 0x%lx~0x%lx\n\n",
343e6f99a56SLei Wen 		       mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1),
344e6f99a56SLei Wen 		       ((start + blkcnt + mmc->erase_grp_size)
345e6f99a56SLei Wen 		       & ~(mmc->erase_grp_size - 1)) - 1);
346e6f99a56SLei Wen 
347e6f99a56SLei Wen 	while (blk < blkcnt) {
348e6f99a56SLei Wen 		blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
349e6f99a56SLei Wen 			mmc->erase_grp_size : (blkcnt - blk);
350e6f99a56SLei Wen 		err = mmc_erase_t(mmc, start + blk, blk_r);
351e6f99a56SLei Wen 		if (err)
352e6f99a56SLei Wen 			break;
353e6f99a56SLei Wen 
354e6f99a56SLei Wen 		blk += blk_r;
355e6f99a56SLei Wen 	}
356e6f99a56SLei Wen 
357e6f99a56SLei Wen 	return blk;
358e6f99a56SLei Wen }
359e6f99a56SLei Wen 
360272cc70bSAndy Fleming static ulong
3610158126eSLei Wen mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)
362272cc70bSAndy Fleming {
363272cc70bSAndy Fleming 	struct mmc_cmd cmd;
364272cc70bSAndy Fleming 	struct mmc_data data;
3655d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
366272cc70bSAndy Fleming 
367d2bf29e3SLei Wen 	if ((start + blkcnt) > mmc->block_dev.lba) {
368def412b6SSteve Sakoman 		printf("MMC: block number 0x%lx exceeds max(0x%lx)\n",
369d2bf29e3SLei Wen 			start + blkcnt, mmc->block_dev.lba);
370d2bf29e3SLei Wen 		return 0;
371d2bf29e3SLei Wen 	}
372272cc70bSAndy Fleming 
373272cc70bSAndy Fleming 	if (blkcnt > 1)
374272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
375272cc70bSAndy Fleming 	else
376272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
377272cc70bSAndy Fleming 
378272cc70bSAndy Fleming 	if (mmc->high_capacity)
379272cc70bSAndy Fleming 		cmd.cmdarg = start;
380272cc70bSAndy Fleming 	else
381def412b6SSteve Sakoman 		cmd.cmdarg = start * mmc->write_bl_len;
382272cc70bSAndy Fleming 
383272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
384272cc70bSAndy Fleming 	cmd.flags = 0;
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;
403272cc70bSAndy Fleming 		cmd.flags = 0;
404def412b6SSteve Sakoman 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
405def412b6SSteve Sakoman 			printf("mmc fail to send stop cmd\n");
406def412b6SSteve Sakoman 			return 0;
407272cc70bSAndy Fleming 		}
40893ad0d18SJan Kloetzke 	}
4095d4fc8d9SRaffaele Recalcati 
4105d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
41193ad0d18SJan Kloetzke 	if (mmc_send_status(mmc, timeout))
41293ad0d18SJan Kloetzke 		return 0;
4130158126eSLei Wen 
4140158126eSLei Wen 	return blkcnt;
4150158126eSLei Wen }
4160158126eSLei Wen 
4170158126eSLei Wen static ulong
4180158126eSLei Wen mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)
4190158126eSLei Wen {
4200158126eSLei Wen 	lbaint_t cur, blocks_todo = blkcnt;
4210158126eSLei Wen 
422def412b6SSteve Sakoman 	struct mmc *mmc = find_mmc_device(dev_num);
4230158126eSLei Wen 	if (!mmc)
424def412b6SSteve Sakoman 		return 0;
4250158126eSLei Wen 
426def412b6SSteve Sakoman 	if (mmc_set_blocklen(mmc, mmc->write_bl_len))
427def412b6SSteve Sakoman 		return 0;
4280158126eSLei Wen 
4290158126eSLei Wen 	do {
4308feafcc4SJohn Rigby 		cur = (blocks_todo > mmc->b_max) ?  mmc->b_max : blocks_todo;
4310158126eSLei Wen 		if(mmc_write_blocks(mmc, start, cur, src) != cur)
432def412b6SSteve Sakoman 			return 0;
4330158126eSLei Wen 		blocks_todo -= cur;
4340158126eSLei Wen 		start += cur;
4350158126eSLei Wen 		src += cur * mmc->write_bl_len;
4360158126eSLei Wen 	} while (blocks_todo > 0);
437272cc70bSAndy Fleming 
438272cc70bSAndy Fleming 	return blkcnt;
439272cc70bSAndy Fleming }
440272cc70bSAndy Fleming 
4414a1a06bcSAlagu Sankar int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt)
442272cc70bSAndy Fleming {
443272cc70bSAndy Fleming 	struct mmc_cmd cmd;
444272cc70bSAndy Fleming 	struct mmc_data data;
445272cc70bSAndy Fleming 
4464a1a06bcSAlagu Sankar 	if (blkcnt > 1)
4474a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
4484a1a06bcSAlagu Sankar 	else
449272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
450272cc70bSAndy Fleming 
451272cc70bSAndy Fleming 	if (mmc->high_capacity)
4524a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
453272cc70bSAndy Fleming 	else
4544a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
455272cc70bSAndy Fleming 
456272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
457272cc70bSAndy Fleming 	cmd.flags = 0;
458272cc70bSAndy Fleming 
459272cc70bSAndy Fleming 	data.dest = dst;
4604a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
461272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
462272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
463272cc70bSAndy Fleming 
4644a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
4654a1a06bcSAlagu Sankar 		return 0;
4664a1a06bcSAlagu Sankar 
4674a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
4684a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
4694a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
4704a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
4714a1a06bcSAlagu Sankar 		cmd.flags = 0;
4724a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
4734a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
4744a1a06bcSAlagu Sankar 			return 0;
4754a1a06bcSAlagu Sankar 		}
476272cc70bSAndy Fleming 	}
477272cc70bSAndy Fleming 
4784a1a06bcSAlagu Sankar 	return blkcnt;
479272cc70bSAndy Fleming }
480272cc70bSAndy Fleming 
481272cc70bSAndy Fleming static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
482272cc70bSAndy Fleming {
4834a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
484272cc70bSAndy Fleming 
4854a1a06bcSAlagu Sankar 	if (blkcnt == 0)
4864a1a06bcSAlagu Sankar 		return 0;
4874a1a06bcSAlagu Sankar 
4884a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
489272cc70bSAndy Fleming 	if (!mmc)
490272cc70bSAndy Fleming 		return 0;
491272cc70bSAndy Fleming 
492d2bf29e3SLei Wen 	if ((start + blkcnt) > mmc->block_dev.lba) {
4934a1a06bcSAlagu Sankar 		printf("MMC: block number 0x%lx exceeds max(0x%lx)\n",
494d2bf29e3SLei Wen 			start + blkcnt, mmc->block_dev.lba);
495d2bf29e3SLei Wen 		return 0;
496d2bf29e3SLei Wen 	}
497272cc70bSAndy Fleming 
4984a1a06bcSAlagu Sankar 	if (mmc_set_blocklen(mmc, mmc->read_bl_len))
499272cc70bSAndy Fleming 		return 0;
500272cc70bSAndy Fleming 
5014a1a06bcSAlagu Sankar 	do {
5028feafcc4SJohn Rigby 		cur = (blocks_todo > mmc->b_max) ?  mmc->b_max : blocks_todo;
5034a1a06bcSAlagu Sankar 		if(mmc_read_blocks(mmc, dst, start, cur) != cur)
5044a1a06bcSAlagu Sankar 			return 0;
5054a1a06bcSAlagu Sankar 		blocks_todo -= cur;
5064a1a06bcSAlagu Sankar 		start += cur;
5074a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
5084a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
509272cc70bSAndy Fleming 
510272cc70bSAndy Fleming 	return blkcnt;
511272cc70bSAndy Fleming }
512272cc70bSAndy Fleming 
513272cc70bSAndy Fleming int mmc_go_idle(struct mmc* mmc)
514272cc70bSAndy Fleming {
515272cc70bSAndy Fleming 	struct mmc_cmd cmd;
516272cc70bSAndy Fleming 	int err;
517272cc70bSAndy Fleming 
518272cc70bSAndy Fleming 	udelay(1000);
519272cc70bSAndy Fleming 
520272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
521272cc70bSAndy Fleming 	cmd.cmdarg = 0;
522272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
523272cc70bSAndy Fleming 	cmd.flags = 0;
524272cc70bSAndy Fleming 
525272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
526272cc70bSAndy Fleming 
527272cc70bSAndy Fleming 	if (err)
528272cc70bSAndy Fleming 		return err;
529272cc70bSAndy Fleming 
530272cc70bSAndy Fleming 	udelay(2000);
531272cc70bSAndy Fleming 
532272cc70bSAndy Fleming 	return 0;
533272cc70bSAndy Fleming }
534272cc70bSAndy Fleming 
535272cc70bSAndy Fleming int
536272cc70bSAndy Fleming sd_send_op_cond(struct mmc *mmc)
537272cc70bSAndy Fleming {
538272cc70bSAndy Fleming 	int timeout = 1000;
539272cc70bSAndy Fleming 	int err;
540272cc70bSAndy Fleming 	struct mmc_cmd cmd;
541272cc70bSAndy Fleming 
542272cc70bSAndy Fleming 	do {
543272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
544272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
545272cc70bSAndy Fleming 		cmd.cmdarg = 0;
546272cc70bSAndy Fleming 		cmd.flags = 0;
547272cc70bSAndy Fleming 
548272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
549272cc70bSAndy Fleming 
550272cc70bSAndy Fleming 		if (err)
551272cc70bSAndy Fleming 			return err;
552272cc70bSAndy Fleming 
553272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
554272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
555250de12bSStefano Babic 
556250de12bSStefano Babic 		/*
557250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
558250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
559250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
560250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
561250de12bSStefano Babic 		 * specified.
562250de12bSStefano Babic 		 */
563d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
564d52ebf10SThomas Chou 			(mmc->voltages & 0xff8000);
565272cc70bSAndy Fleming 
566272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
567272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
568272cc70bSAndy Fleming 
569272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
570272cc70bSAndy Fleming 
571272cc70bSAndy Fleming 		if (err)
572272cc70bSAndy Fleming 			return err;
573272cc70bSAndy Fleming 
574272cc70bSAndy Fleming 		udelay(1000);
575272cc70bSAndy Fleming 	} while ((!(cmd.response[0] & OCR_BUSY)) && timeout--);
576272cc70bSAndy Fleming 
577272cc70bSAndy Fleming 	if (timeout <= 0)
578272cc70bSAndy Fleming 		return UNUSABLE_ERR;
579272cc70bSAndy Fleming 
580272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
581272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
582272cc70bSAndy Fleming 
583d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
584d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
585d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
586d52ebf10SThomas Chou 		cmd.cmdarg = 0;
587d52ebf10SThomas Chou 		cmd.flags = 0;
588d52ebf10SThomas Chou 
589d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
590d52ebf10SThomas Chou 
591d52ebf10SThomas Chou 		if (err)
592d52ebf10SThomas Chou 			return err;
593d52ebf10SThomas Chou 	}
594d52ebf10SThomas Chou 
595998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
596272cc70bSAndy Fleming 
597272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
598272cc70bSAndy Fleming 	mmc->rca = 0;
599272cc70bSAndy Fleming 
600272cc70bSAndy Fleming 	return 0;
601272cc70bSAndy Fleming }
602272cc70bSAndy Fleming 
603272cc70bSAndy Fleming int mmc_send_op_cond(struct mmc *mmc)
604272cc70bSAndy Fleming {
60531cacbabSRaffaele Recalcati 	int timeout = 10000;
606272cc70bSAndy Fleming 	struct mmc_cmd cmd;
607272cc70bSAndy Fleming 	int err;
608272cc70bSAndy Fleming 
609272cc70bSAndy Fleming 	/* Some cards seem to need this */
610272cc70bSAndy Fleming 	mmc_go_idle(mmc);
611272cc70bSAndy Fleming 
61231cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
61331cacbabSRaffaele Recalcati  	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
61431cacbabSRaffaele Recalcati  	cmd.resp_type = MMC_RSP_R3;
61531cacbabSRaffaele Recalcati  	cmd.cmdarg = 0;
61631cacbabSRaffaele Recalcati  	cmd.flags = 0;
61731cacbabSRaffaele Recalcati 
61831cacbabSRaffaele Recalcati  	err = mmc_send_cmd(mmc, &cmd, NULL);
61931cacbabSRaffaele Recalcati 
62031cacbabSRaffaele Recalcati  	if (err)
62131cacbabSRaffaele Recalcati  		return err;
62231cacbabSRaffaele Recalcati 
62331cacbabSRaffaele Recalcati  	udelay(1000);
62431cacbabSRaffaele Recalcati 
625272cc70bSAndy Fleming 	do {
626272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SEND_OP_COND;
627272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
62831cacbabSRaffaele Recalcati 		cmd.cmdarg = (mmc_host_is_spi(mmc) ? 0 :
62931cacbabSRaffaele Recalcati 				(mmc->voltages &
63031cacbabSRaffaele Recalcati 				(cmd.response[0] & OCR_VOLTAGE_MASK)) |
63131cacbabSRaffaele Recalcati 				(cmd.response[0] & OCR_ACCESS_MODE));
632b1f1e821SŁukasz Majewski 
633b1f1e821SŁukasz Majewski 		if (mmc->host_caps & MMC_MODE_HC)
634b1f1e821SŁukasz Majewski 			cmd.cmdarg |= OCR_HCS;
635b1f1e821SŁukasz Majewski 
636272cc70bSAndy Fleming 		cmd.flags = 0;
637272cc70bSAndy Fleming 
638272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
639272cc70bSAndy Fleming 
640272cc70bSAndy Fleming 		if (err)
641272cc70bSAndy Fleming 			return err;
642272cc70bSAndy Fleming 
643272cc70bSAndy Fleming 		udelay(1000);
644272cc70bSAndy Fleming 	} while (!(cmd.response[0] & OCR_BUSY) && timeout--);
645272cc70bSAndy Fleming 
646272cc70bSAndy Fleming 	if (timeout <= 0)
647272cc70bSAndy Fleming 		return UNUSABLE_ERR;
648272cc70bSAndy Fleming 
649d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
650d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
651d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
652d52ebf10SThomas Chou 		cmd.cmdarg = 0;
653d52ebf10SThomas Chou 		cmd.flags = 0;
654d52ebf10SThomas Chou 
655d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
656d52ebf10SThomas Chou 
657d52ebf10SThomas Chou 		if (err)
658d52ebf10SThomas Chou 			return err;
659d52ebf10SThomas Chou 	}
660d52ebf10SThomas Chou 
661272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
662998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
663272cc70bSAndy Fleming 
664272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
665272cc70bSAndy Fleming 	mmc->rca = 0;
666272cc70bSAndy Fleming 
667272cc70bSAndy Fleming 	return 0;
668272cc70bSAndy Fleming }
669272cc70bSAndy Fleming 
670272cc70bSAndy Fleming 
671272cc70bSAndy Fleming int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd)
672272cc70bSAndy Fleming {
673272cc70bSAndy Fleming 	struct mmc_cmd cmd;
674272cc70bSAndy Fleming 	struct mmc_data data;
675272cc70bSAndy Fleming 	int err;
676272cc70bSAndy Fleming 
677272cc70bSAndy Fleming 	/* Get the Card Status Register */
678272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
679272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
680272cc70bSAndy Fleming 	cmd.cmdarg = 0;
681272cc70bSAndy Fleming 	cmd.flags = 0;
682272cc70bSAndy Fleming 
683272cc70bSAndy Fleming 	data.dest = ext_csd;
684272cc70bSAndy Fleming 	data.blocks = 1;
685272cc70bSAndy Fleming 	data.blocksize = 512;
686272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
687272cc70bSAndy Fleming 
688272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
689272cc70bSAndy Fleming 
690272cc70bSAndy Fleming 	return err;
691272cc70bSAndy Fleming }
692272cc70bSAndy Fleming 
693272cc70bSAndy Fleming 
694272cc70bSAndy Fleming int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
695272cc70bSAndy Fleming {
696272cc70bSAndy Fleming 	struct mmc_cmd cmd;
6975d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
6985d4fc8d9SRaffaele Recalcati 	int ret;
699272cc70bSAndy Fleming 
700272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
701272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
702272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
703272cc70bSAndy Fleming 				 (index << 16) |
704272cc70bSAndy Fleming 				 (value << 8);
705272cc70bSAndy Fleming 	cmd.flags = 0;
706272cc70bSAndy Fleming 
7075d4fc8d9SRaffaele Recalcati 	ret = mmc_send_cmd(mmc, &cmd, NULL);
7085d4fc8d9SRaffaele Recalcati 
7095d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
71093ad0d18SJan Kloetzke 	if (!ret)
71193ad0d18SJan Kloetzke 		ret = mmc_send_status(mmc, timeout);
7125d4fc8d9SRaffaele Recalcati 
7135d4fc8d9SRaffaele Recalcati 	return ret;
7145d4fc8d9SRaffaele Recalcati 
715272cc70bSAndy Fleming }
716272cc70bSAndy Fleming 
717272cc70bSAndy Fleming int mmc_change_freq(struct mmc *mmc)
718272cc70bSAndy Fleming {
719a1969923SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(char, ext_csd, 512);
720272cc70bSAndy Fleming 	char cardtype;
721272cc70bSAndy Fleming 	int err;
722272cc70bSAndy Fleming 
723272cc70bSAndy Fleming 	mmc->card_caps = 0;
724272cc70bSAndy Fleming 
725d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
726d52ebf10SThomas Chou 		return 0;
727d52ebf10SThomas Chou 
728272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
729272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
730272cc70bSAndy Fleming 		return 0;
731272cc70bSAndy Fleming 
732272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
733272cc70bSAndy Fleming 
734272cc70bSAndy Fleming 	if (err)
735272cc70bSAndy Fleming 		return err;
736272cc70bSAndy Fleming 
7370560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
738272cc70bSAndy Fleming 
739272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
740272cc70bSAndy Fleming 
741272cc70bSAndy Fleming 	if (err)
742272cc70bSAndy Fleming 		return err;
743272cc70bSAndy Fleming 
744272cc70bSAndy Fleming 	/* Now check to see that it worked */
745272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
746272cc70bSAndy Fleming 
747272cc70bSAndy Fleming 	if (err)
748272cc70bSAndy Fleming 		return err;
749272cc70bSAndy Fleming 
750272cc70bSAndy Fleming 	/* No high-speed support */
7510560db18SLei Wen 	if (!ext_csd[EXT_CSD_HS_TIMING])
752272cc70bSAndy Fleming 		return 0;
753272cc70bSAndy Fleming 
754272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
755272cc70bSAndy Fleming 	if (cardtype & MMC_HS_52MHZ)
756272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
757272cc70bSAndy Fleming 	else
758272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
759272cc70bSAndy Fleming 
760272cc70bSAndy Fleming 	return 0;
761272cc70bSAndy Fleming }
762272cc70bSAndy Fleming 
763bc897b1dSLei Wen int mmc_switch_part(int dev_num, unsigned int part_num)
764bc897b1dSLei Wen {
765bc897b1dSLei Wen 	struct mmc *mmc = find_mmc_device(dev_num);
766bc897b1dSLei Wen 
767bc897b1dSLei Wen 	if (!mmc)
768bc897b1dSLei Wen 		return -1;
769bc897b1dSLei Wen 
770bc897b1dSLei Wen 	return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
771bc897b1dSLei Wen 			  (mmc->part_config & ~PART_ACCESS_MASK)
772bc897b1dSLei Wen 			  | (part_num & PART_ACCESS_MASK));
773bc897b1dSLei Wen }
774bc897b1dSLei Wen 
77548972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
77648972d90SThierry Reding {
77748972d90SThierry Reding 	int cd;
77848972d90SThierry Reding 
77948972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
78048972d90SThierry Reding 
78148972d90SThierry Reding 	if ((cd < 0) && mmc->getcd)
78248972d90SThierry Reding 		cd = mmc->getcd(mmc);
78348972d90SThierry Reding 
78448972d90SThierry Reding 	return cd;
78548972d90SThierry Reding }
78648972d90SThierry Reding 
787272cc70bSAndy Fleming int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
788272cc70bSAndy Fleming {
789272cc70bSAndy Fleming 	struct mmc_cmd cmd;
790272cc70bSAndy Fleming 	struct mmc_data data;
791272cc70bSAndy Fleming 
792272cc70bSAndy Fleming 	/* Switch the frequency */
793272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
794272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
795272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
796272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
797272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
798272cc70bSAndy Fleming 	cmd.flags = 0;
799272cc70bSAndy Fleming 
800272cc70bSAndy Fleming 	data.dest = (char *)resp;
801272cc70bSAndy Fleming 	data.blocksize = 64;
802272cc70bSAndy Fleming 	data.blocks = 1;
803272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
804272cc70bSAndy Fleming 
805272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
806272cc70bSAndy Fleming }
807272cc70bSAndy Fleming 
808272cc70bSAndy Fleming 
809272cc70bSAndy Fleming int sd_change_freq(struct mmc *mmc)
810272cc70bSAndy Fleming {
811272cc70bSAndy Fleming 	int err;
812272cc70bSAndy Fleming 	struct mmc_cmd cmd;
813f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
814f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
815272cc70bSAndy Fleming 	struct mmc_data data;
816272cc70bSAndy Fleming 	int timeout;
817272cc70bSAndy Fleming 
818272cc70bSAndy Fleming 	mmc->card_caps = 0;
819272cc70bSAndy Fleming 
820d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
821d52ebf10SThomas Chou 		return 0;
822d52ebf10SThomas Chou 
823272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
824272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
825272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
826272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
827272cc70bSAndy Fleming 	cmd.flags = 0;
828272cc70bSAndy Fleming 
829272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
830272cc70bSAndy Fleming 
831272cc70bSAndy Fleming 	if (err)
832272cc70bSAndy Fleming 		return err;
833272cc70bSAndy Fleming 
834272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
835272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
836272cc70bSAndy Fleming 	cmd.cmdarg = 0;
837272cc70bSAndy Fleming 	cmd.flags = 0;
838272cc70bSAndy Fleming 
839272cc70bSAndy Fleming 	timeout = 3;
840272cc70bSAndy Fleming 
841272cc70bSAndy Fleming retry_scr:
842f781dd38SAnton staaf 	data.dest = (char *)scr;
843272cc70bSAndy Fleming 	data.blocksize = 8;
844272cc70bSAndy Fleming 	data.blocks = 1;
845272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
846272cc70bSAndy Fleming 
847272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
848272cc70bSAndy Fleming 
849272cc70bSAndy Fleming 	if (err) {
850272cc70bSAndy Fleming 		if (timeout--)
851272cc70bSAndy Fleming 			goto retry_scr;
852272cc70bSAndy Fleming 
853272cc70bSAndy Fleming 		return err;
854272cc70bSAndy Fleming 	}
855272cc70bSAndy Fleming 
8564e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
8574e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
858272cc70bSAndy Fleming 
859272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
860272cc70bSAndy Fleming 		case 0:
861272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
862272cc70bSAndy Fleming 			break;
863272cc70bSAndy Fleming 		case 1:
864272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_10;
865272cc70bSAndy Fleming 			break;
866272cc70bSAndy Fleming 		case 2:
867272cc70bSAndy Fleming 			mmc->version = SD_VERSION_2;
868272cc70bSAndy Fleming 			break;
869272cc70bSAndy Fleming 		default:
870272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
871272cc70bSAndy Fleming 			break;
872272cc70bSAndy Fleming 	}
873272cc70bSAndy Fleming 
874b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
875b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
876b44c7083SAlagu Sankar 
877272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
878272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
879272cc70bSAndy Fleming 		return 0;
880272cc70bSAndy Fleming 
881272cc70bSAndy Fleming 	timeout = 4;
882272cc70bSAndy Fleming 	while (timeout--) {
883272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
884f781dd38SAnton staaf 				(u8 *)switch_status);
885272cc70bSAndy Fleming 
886272cc70bSAndy Fleming 		if (err)
887272cc70bSAndy Fleming 			return err;
888272cc70bSAndy Fleming 
889272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
8904e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
891272cc70bSAndy Fleming 			break;
892272cc70bSAndy Fleming 	}
893272cc70bSAndy Fleming 
894272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
8954e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
896272cc70bSAndy Fleming 		return 0;
897272cc70bSAndy Fleming 
8982c3fbf4cSMacpaul Lin 	/*
8992c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
9002c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
9012c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
9022c3fbf4cSMacpaul Lin 	 * mode between the host.
9032c3fbf4cSMacpaul Lin 	 */
9042c3fbf4cSMacpaul Lin 	if (!((mmc->host_caps & MMC_MODE_HS_52MHz) &&
9052c3fbf4cSMacpaul Lin 		(mmc->host_caps & MMC_MODE_HS)))
9062c3fbf4cSMacpaul Lin 		return 0;
9072c3fbf4cSMacpaul Lin 
908f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
909272cc70bSAndy Fleming 
910272cc70bSAndy Fleming 	if (err)
911272cc70bSAndy Fleming 		return err;
912272cc70bSAndy Fleming 
9134e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
914272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
915272cc70bSAndy Fleming 
916272cc70bSAndy Fleming 	return 0;
917272cc70bSAndy Fleming }
918272cc70bSAndy Fleming 
919272cc70bSAndy Fleming /* frequency bases */
920272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
9215f837c2cSMike Frysinger static const int fbase[] = {
922272cc70bSAndy Fleming 	10000,
923272cc70bSAndy Fleming 	100000,
924272cc70bSAndy Fleming 	1000000,
925272cc70bSAndy Fleming 	10000000,
926272cc70bSAndy Fleming };
927272cc70bSAndy Fleming 
928272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
929272cc70bSAndy Fleming  * to platforms without floating point.
930272cc70bSAndy Fleming  */
9315f837c2cSMike Frysinger static const int multipliers[] = {
932272cc70bSAndy Fleming 	0,	/* reserved */
933272cc70bSAndy Fleming 	10,
934272cc70bSAndy Fleming 	12,
935272cc70bSAndy Fleming 	13,
936272cc70bSAndy Fleming 	15,
937272cc70bSAndy Fleming 	20,
938272cc70bSAndy Fleming 	25,
939272cc70bSAndy Fleming 	30,
940272cc70bSAndy Fleming 	35,
941272cc70bSAndy Fleming 	40,
942272cc70bSAndy Fleming 	45,
943272cc70bSAndy Fleming 	50,
944272cc70bSAndy Fleming 	55,
945272cc70bSAndy Fleming 	60,
946272cc70bSAndy Fleming 	70,
947272cc70bSAndy Fleming 	80,
948272cc70bSAndy Fleming };
949272cc70bSAndy Fleming 
950272cc70bSAndy Fleming void mmc_set_ios(struct mmc *mmc)
951272cc70bSAndy Fleming {
952272cc70bSAndy Fleming 	mmc->set_ios(mmc);
953272cc70bSAndy Fleming }
954272cc70bSAndy Fleming 
955272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
956272cc70bSAndy Fleming {
957272cc70bSAndy Fleming 	if (clock > mmc->f_max)
958272cc70bSAndy Fleming 		clock = mmc->f_max;
959272cc70bSAndy Fleming 
960272cc70bSAndy Fleming 	if (clock < mmc->f_min)
961272cc70bSAndy Fleming 		clock = mmc->f_min;
962272cc70bSAndy Fleming 
963272cc70bSAndy Fleming 	mmc->clock = clock;
964272cc70bSAndy Fleming 
965272cc70bSAndy Fleming 	mmc_set_ios(mmc);
966272cc70bSAndy Fleming }
967272cc70bSAndy Fleming 
968272cc70bSAndy Fleming void mmc_set_bus_width(struct mmc *mmc, uint width)
969272cc70bSAndy Fleming {
970272cc70bSAndy Fleming 	mmc->bus_width = width;
971272cc70bSAndy Fleming 
972272cc70bSAndy Fleming 	mmc_set_ios(mmc);
973272cc70bSAndy Fleming }
974272cc70bSAndy Fleming 
975272cc70bSAndy Fleming int mmc_startup(struct mmc *mmc)
976272cc70bSAndy Fleming {
9774137894eSLei Wen 	int err, width;
978272cc70bSAndy Fleming 	uint mult, freq;
979639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
980272cc70bSAndy Fleming 	struct mmc_cmd cmd;
981a1969923SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(char, ext_csd, 512);
9824137894eSLei Wen 	ALLOC_CACHE_ALIGN_BUFFER(char, test_csd, 512);
9835d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
984272cc70bSAndy Fleming 
985d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
986d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
987d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
988d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
989d52ebf10SThomas Chou 		cmd.cmdarg = 1;
990d52ebf10SThomas Chou 		cmd.flags = 0;
991d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
992d52ebf10SThomas Chou 
993d52ebf10SThomas Chou 		if (err)
994d52ebf10SThomas Chou 			return err;
995d52ebf10SThomas Chou 	}
996d52ebf10SThomas Chou #endif
997d52ebf10SThomas Chou 
998272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
999d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1000d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1001272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1002272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1003272cc70bSAndy Fleming 	cmd.flags = 0;
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 	memcpy(mmc->cid, cmd.response, 16);
1011272cc70bSAndy Fleming 
1012272cc70bSAndy Fleming 	/*
1013272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1014272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1015272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1016272cc70bSAndy Fleming 	 */
1017d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1018272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1019272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1020272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1021272cc70bSAndy Fleming 		cmd.flags = 0;
1022272cc70bSAndy Fleming 
1023272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1024272cc70bSAndy Fleming 
1025272cc70bSAndy Fleming 		if (err)
1026272cc70bSAndy Fleming 			return err;
1027272cc70bSAndy Fleming 
1028272cc70bSAndy Fleming 		if (IS_SD(mmc))
1029998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1030d52ebf10SThomas Chou 	}
1031272cc70bSAndy Fleming 
1032272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1033272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1034272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1035272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1036272cc70bSAndy Fleming 	cmd.flags = 0;
1037272cc70bSAndy Fleming 
1038272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1039272cc70bSAndy Fleming 
10405d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
10415d4fc8d9SRaffaele Recalcati 	mmc_send_status(mmc, timeout);
10425d4fc8d9SRaffaele Recalcati 
1043272cc70bSAndy Fleming 	if (err)
1044272cc70bSAndy Fleming 		return err;
1045272cc70bSAndy Fleming 
1046998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1047998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1048998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1049998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1050272cc70bSAndy Fleming 
1051272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
10520b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1053272cc70bSAndy Fleming 
1054272cc70bSAndy Fleming 		switch (version) {
1055272cc70bSAndy Fleming 			case 0:
1056272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
1057272cc70bSAndy Fleming 				break;
1058272cc70bSAndy Fleming 			case 1:
1059272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_4;
1060272cc70bSAndy Fleming 				break;
1061272cc70bSAndy Fleming 			case 2:
1062272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_2_2;
1063272cc70bSAndy Fleming 				break;
1064272cc70bSAndy Fleming 			case 3:
1065272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_3;
1066272cc70bSAndy Fleming 				break;
1067272cc70bSAndy Fleming 			case 4:
1068272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_4;
1069272cc70bSAndy Fleming 				break;
1070272cc70bSAndy Fleming 			default:
1071272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
1072272cc70bSAndy Fleming 				break;
1073272cc70bSAndy Fleming 		}
1074272cc70bSAndy Fleming 	}
1075272cc70bSAndy Fleming 
1076272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
10770b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
10780b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1079272cc70bSAndy Fleming 
1080272cc70bSAndy Fleming 	mmc->tran_speed = freq * mult;
1081272cc70bSAndy Fleming 
1082998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1083272cc70bSAndy Fleming 
1084272cc70bSAndy Fleming 	if (IS_SD(mmc))
1085272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1086272cc70bSAndy Fleming 	else
1087998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1088272cc70bSAndy Fleming 
1089272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1090272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1091272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1092272cc70bSAndy Fleming 		cmult = 8;
1093272cc70bSAndy Fleming 	} else {
1094272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1095272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1096272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1097272cc70bSAndy Fleming 	}
1098272cc70bSAndy Fleming 
1099272cc70bSAndy Fleming 	mmc->capacity = (csize + 1) << (cmult + 2);
1100272cc70bSAndy Fleming 	mmc->capacity *= mmc->read_bl_len;
1101272cc70bSAndy Fleming 
1102272cc70bSAndy Fleming 	if (mmc->read_bl_len > 512)
1103272cc70bSAndy Fleming 		mmc->read_bl_len = 512;
1104272cc70bSAndy Fleming 
1105272cc70bSAndy Fleming 	if (mmc->write_bl_len > 512)
1106272cc70bSAndy Fleming 		mmc->write_bl_len = 512;
1107272cc70bSAndy Fleming 
1108272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1109d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1110272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1111fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1112272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1113272cc70bSAndy Fleming 		cmd.flags = 0;
1114272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1115272cc70bSAndy Fleming 
1116272cc70bSAndy Fleming 		if (err)
1117272cc70bSAndy Fleming 			return err;
1118d52ebf10SThomas Chou 	}
1119272cc70bSAndy Fleming 
1120e6f99a56SLei Wen 	/*
1121e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1122e6f99a56SLei Wen 	 */
1123e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1124bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1125d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
1126d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
1127d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
11280560db18SLei Wen 		if (!err & (ext_csd[EXT_CSD_REV] >= 2)) {
1129639b7827SYoshihiro Shimoda 			/*
1130639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
1131639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
1132639b7827SYoshihiro Shimoda 			 * than 2GB
1133639b7827SYoshihiro Shimoda 			 */
11340560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
11350560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
11360560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
11370560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1138639b7827SYoshihiro Shimoda 			capacity *= 512;
1139b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
1140639b7827SYoshihiro Shimoda 				mmc->capacity = capacity;
1141d23e2c09SSukumar Ghorai 		}
1142bc897b1dSLei Wen 
1143e6f99a56SLei Wen 		/*
1144e6f99a56SLei Wen 		 * Check whether GROUP_DEF is set, if yes, read out
1145e6f99a56SLei Wen 		 * group size from ext_csd directly, or calculate
1146e6f99a56SLei Wen 		 * the group size from the csd value.
1147e6f99a56SLei Wen 		 */
11480560db18SLei Wen 		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF])
11490560db18SLei Wen 			mmc->erase_grp_size =
11500560db18SLei Wen 			      ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 512 * 1024;
1151e6f99a56SLei Wen 		else {
1152e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
1153e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1154e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1155e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
1156e6f99a56SLei Wen 				* (erase_gmul + 1);
1157e6f99a56SLei Wen 		}
1158e6f99a56SLei Wen 
1159bc897b1dSLei Wen 		/* store the partition info of emmc */
11600560db18SLei Wen 		if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT)
11610560db18SLei Wen 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
1162d23e2c09SSukumar Ghorai 	}
1163d23e2c09SSukumar Ghorai 
1164272cc70bSAndy Fleming 	if (IS_SD(mmc))
1165272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1166272cc70bSAndy Fleming 	else
1167272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1168272cc70bSAndy Fleming 
1169272cc70bSAndy Fleming 	if (err)
1170272cc70bSAndy Fleming 		return err;
1171272cc70bSAndy Fleming 
1172272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
1173272cc70bSAndy Fleming 	mmc->card_caps &= mmc->host_caps;
1174272cc70bSAndy Fleming 
1175272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1176272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1177272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1178272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1179272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1180272cc70bSAndy Fleming 			cmd.flags = 0;
1181272cc70bSAndy Fleming 
1182272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1183272cc70bSAndy Fleming 			if (err)
1184272cc70bSAndy Fleming 				return err;
1185272cc70bSAndy Fleming 
1186272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1187272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1188272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1189272cc70bSAndy Fleming 			cmd.flags = 0;
1190272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1191272cc70bSAndy Fleming 			if (err)
1192272cc70bSAndy Fleming 				return err;
1193272cc70bSAndy Fleming 
1194272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1195272cc70bSAndy Fleming 		}
1196272cc70bSAndy Fleming 
1197272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
1198*ad5fd922SJaehoon Chung 			mmc->tran_speed = 50000000;
1199272cc70bSAndy Fleming 		else
1200*ad5fd922SJaehoon Chung 			mmc->tran_speed = 25000000;
1201272cc70bSAndy Fleming 	} else {
120262722036SŁukasz Majewski 		width = ((mmc->host_caps & MMC_MODE_MASK_WIDTH_BITS) >>
120362722036SŁukasz Majewski 			 MMC_MODE_WIDTH_BITS_SHIFT);
120462722036SŁukasz Majewski 		for (; width >= 0; width--) {
1205272cc70bSAndy Fleming 			/* Set the card to use 4 bit*/
1206272cc70bSAndy Fleming 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
12074137894eSLei Wen 					EXT_CSD_BUS_WIDTH, width);
1208272cc70bSAndy Fleming 
1209272cc70bSAndy Fleming 			if (err)
12104137894eSLei Wen 				continue;
1211272cc70bSAndy Fleming 
12124137894eSLei Wen 			if (!width) {
12134137894eSLei Wen 				mmc_set_bus_width(mmc, 1);
12144137894eSLei Wen 				break;
12154137894eSLei Wen 			} else
12164137894eSLei Wen 				mmc_set_bus_width(mmc, 4 * width);
1217272cc70bSAndy Fleming 
12184137894eSLei Wen 			err = mmc_send_ext_csd(mmc, test_csd);
12194137894eSLei Wen 			if (!err && ext_csd[EXT_CSD_PARTITIONING_SUPPORT] \
12204137894eSLei Wen 				    == test_csd[EXT_CSD_PARTITIONING_SUPPORT]
12214137894eSLei Wen 				 && ext_csd[EXT_CSD_ERASE_GROUP_DEF] \
12224137894eSLei Wen 				    == test_csd[EXT_CSD_ERASE_GROUP_DEF] \
12234137894eSLei Wen 				 && ext_csd[EXT_CSD_REV] \
12244137894eSLei Wen 				    == test_csd[EXT_CSD_REV]
12254137894eSLei Wen 				 && ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] \
12264137894eSLei Wen 				    == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
12274137894eSLei Wen 				 && memcmp(&ext_csd[EXT_CSD_SEC_CNT], \
12284137894eSLei Wen 					&test_csd[EXT_CSD_SEC_CNT], 4) == 0) {
1229272cc70bSAndy Fleming 
12304137894eSLei Wen 				mmc->card_caps |= width;
12314137894eSLei Wen 				break;
12324137894eSLei Wen 			}
1233272cc70bSAndy Fleming 		}
1234272cc70bSAndy Fleming 
1235272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS) {
1236272cc70bSAndy Fleming 			if (mmc->card_caps & MMC_MODE_HS_52MHz)
1237*ad5fd922SJaehoon Chung 				mmc->tran_speed = 52000000;
1238272cc70bSAndy Fleming 			else
1239*ad5fd922SJaehoon Chung 				mmc->tran_speed = 26000000;
1240272cc70bSAndy Fleming 		}
1241*ad5fd922SJaehoon Chung 	}
1242*ad5fd922SJaehoon Chung 
1243*ad5fd922SJaehoon Chung 	mmc_set_clock(mmc, mmc->tran_speed);
1244272cc70bSAndy Fleming 
1245272cc70bSAndy Fleming 	/* fill in device description */
1246272cc70bSAndy Fleming 	mmc->block_dev.lun = 0;
1247272cc70bSAndy Fleming 	mmc->block_dev.type = 0;
1248272cc70bSAndy Fleming 	mmc->block_dev.blksz = mmc->read_bl_len;
12499b1f942cSRabin Vincent 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
12500b453ffeSRabin Vincent 	sprintf(mmc->block_dev.vendor, "Man %06x Snr %08x", mmc->cid[0] >> 8,
12510b453ffeSRabin Vincent 			(mmc->cid[2] << 8) | (mmc->cid[3] >> 24));
12520b453ffeSRabin Vincent 	sprintf(mmc->block_dev.product, "%c%c%c%c%c", mmc->cid[0] & 0xff,
12530b453ffeSRabin Vincent 			(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
12540b453ffeSRabin Vincent 			(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff);
12550b453ffeSRabin Vincent 	sprintf(mmc->block_dev.revision, "%d.%d", mmc->cid[2] >> 28,
12560b453ffeSRabin Vincent 			(mmc->cid[2] >> 24) & 0xf);
1257272cc70bSAndy Fleming 	init_part(&mmc->block_dev);
1258272cc70bSAndy Fleming 
1259272cc70bSAndy Fleming 	return 0;
1260272cc70bSAndy Fleming }
1261272cc70bSAndy Fleming 
1262272cc70bSAndy Fleming int mmc_send_if_cond(struct mmc *mmc)
1263272cc70bSAndy Fleming {
1264272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1265272cc70bSAndy Fleming 	int err;
1266272cc70bSAndy Fleming 
1267272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1268272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
1269272cc70bSAndy Fleming 	cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa;
1270272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1271272cc70bSAndy Fleming 	cmd.flags = 0;
1272272cc70bSAndy Fleming 
1273272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1274272cc70bSAndy Fleming 
1275272cc70bSAndy Fleming 	if (err)
1276272cc70bSAndy Fleming 		return err;
1277272cc70bSAndy Fleming 
1278998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1279272cc70bSAndy Fleming 		return UNUSABLE_ERR;
1280272cc70bSAndy Fleming 	else
1281272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1282272cc70bSAndy Fleming 
1283272cc70bSAndy Fleming 	return 0;
1284272cc70bSAndy Fleming }
1285272cc70bSAndy Fleming 
1286272cc70bSAndy Fleming int mmc_register(struct mmc *mmc)
1287272cc70bSAndy Fleming {
1288272cc70bSAndy Fleming 	/* Setup the universal parts of the block interface just once */
1289272cc70bSAndy Fleming 	mmc->block_dev.if_type = IF_TYPE_MMC;
1290272cc70bSAndy Fleming 	mmc->block_dev.dev = cur_dev_num++;
1291272cc70bSAndy Fleming 	mmc->block_dev.removable = 1;
1292272cc70bSAndy Fleming 	mmc->block_dev.block_read = mmc_bread;
1293272cc70bSAndy Fleming 	mmc->block_dev.block_write = mmc_bwrite;
1294e6f99a56SLei Wen 	mmc->block_dev.block_erase = mmc_berase;
12958feafcc4SJohn Rigby 	if (!mmc->b_max)
12968feafcc4SJohn Rigby 		mmc->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
1297272cc70bSAndy Fleming 
1298272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc->link);
1299272cc70bSAndy Fleming 
1300272cc70bSAndy Fleming 	list_add_tail (&mmc->link, &mmc_devices);
1301272cc70bSAndy Fleming 
1302272cc70bSAndy Fleming 	return 0;
1303272cc70bSAndy Fleming }
1304272cc70bSAndy Fleming 
1305df3fc526SMatthew McClintock #ifdef CONFIG_PARTITIONS
1306272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev)
1307272cc70bSAndy Fleming {
1308272cc70bSAndy Fleming 	struct mmc *mmc = find_mmc_device(dev);
1309272cc70bSAndy Fleming 
1310e85649c7SRabin Vincent 	return mmc ? &mmc->block_dev : NULL;
1311272cc70bSAndy Fleming }
1312df3fc526SMatthew McClintock #endif
1313272cc70bSAndy Fleming 
1314272cc70bSAndy Fleming int mmc_init(struct mmc *mmc)
1315272cc70bSAndy Fleming {
1316afd5932bSMacpaul Lin 	int err;
1317272cc70bSAndy Fleming 
131848972d90SThierry Reding 	if (mmc_getcd(mmc) == 0) {
131948972d90SThierry Reding 		mmc->has_init = 0;
132048972d90SThierry Reding 		printf("MMC: no card present\n");
132148972d90SThierry Reding 		return NO_CARD_ERR;
132248972d90SThierry Reding 	}
132348972d90SThierry Reding 
1324bc897b1dSLei Wen 	if (mmc->has_init)
1325bc897b1dSLei Wen 		return 0;
1326bc897b1dSLei Wen 
1327272cc70bSAndy Fleming 	err = mmc->init(mmc);
1328272cc70bSAndy Fleming 
1329272cc70bSAndy Fleming 	if (err)
1330272cc70bSAndy Fleming 		return err;
1331272cc70bSAndy Fleming 
1332b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1333b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1334b86b85e2SIlya Yanok 
1335272cc70bSAndy Fleming 	/* Reset the Card */
1336272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1337272cc70bSAndy Fleming 
1338272cc70bSAndy Fleming 	if (err)
1339272cc70bSAndy Fleming 		return err;
1340272cc70bSAndy Fleming 
1341bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1342bc897b1dSLei Wen 	mmc->part_num = 0;
1343bc897b1dSLei Wen 
1344272cc70bSAndy Fleming 	/* Test for SD version 2 */
1345272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1346272cc70bSAndy Fleming 
1347272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1348272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1349272cc70bSAndy Fleming 
1350272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1351272cc70bSAndy Fleming 	if (err == TIMEOUT) {
1352272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1353272cc70bSAndy Fleming 
1354272cc70bSAndy Fleming 		if (err) {
1355272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
1356272cc70bSAndy Fleming 			return UNUSABLE_ERR;
1357272cc70bSAndy Fleming 		}
1358272cc70bSAndy Fleming 	}
1359272cc70bSAndy Fleming 
1360bc897b1dSLei Wen 	err = mmc_startup(mmc);
1361bc897b1dSLei Wen 	if (err)
1362bc897b1dSLei Wen 		mmc->has_init = 0;
1363bc897b1dSLei Wen 	else
1364bc897b1dSLei Wen 		mmc->has_init = 1;
1365bc897b1dSLei Wen 	return err;
1366272cc70bSAndy Fleming }
1367272cc70bSAndy Fleming 
1368272cc70bSAndy Fleming /*
1369272cc70bSAndy Fleming  * CPU and board-specific MMC initializations.  Aliased function
1370272cc70bSAndy Fleming  * signals caller to move on
1371272cc70bSAndy Fleming  */
1372272cc70bSAndy Fleming static int __def_mmc_init(bd_t *bis)
1373272cc70bSAndy Fleming {
1374272cc70bSAndy Fleming 	return -1;
1375272cc70bSAndy Fleming }
1376272cc70bSAndy Fleming 
1377f9a109b3SPeter Tyser int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
1378f9a109b3SPeter Tyser int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
1379272cc70bSAndy Fleming 
1380272cc70bSAndy Fleming void print_mmc_devices(char separator)
1381272cc70bSAndy Fleming {
1382272cc70bSAndy Fleming 	struct mmc *m;
1383272cc70bSAndy Fleming 	struct list_head *entry;
1384272cc70bSAndy Fleming 
1385272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
1386272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
1387272cc70bSAndy Fleming 
1388272cc70bSAndy Fleming 		printf("%s: %d", m->name, m->block_dev.dev);
1389272cc70bSAndy Fleming 
1390272cc70bSAndy Fleming 		if (entry->next != &mmc_devices)
1391272cc70bSAndy Fleming 			printf("%c ", separator);
1392272cc70bSAndy Fleming 	}
1393272cc70bSAndy Fleming 
1394272cc70bSAndy Fleming 	printf("\n");
1395272cc70bSAndy Fleming }
1396272cc70bSAndy Fleming 
1397ea6ebe21SLei Wen int get_mmc_num(void)
1398ea6ebe21SLei Wen {
1399ea6ebe21SLei Wen 	return cur_dev_num;
1400ea6ebe21SLei Wen }
1401ea6ebe21SLei Wen 
1402272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1403272cc70bSAndy Fleming {
1404272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc_devices);
1405272cc70bSAndy Fleming 	cur_dev_num = 0;
1406272cc70bSAndy Fleming 
1407272cc70bSAndy Fleming 	if (board_mmc_init(bis) < 0)
1408272cc70bSAndy Fleming 		cpu_mmc_init(bis);
1409272cc70bSAndy Fleming 
1410272cc70bSAndy Fleming 	print_mmc_devices(',');
1411272cc70bSAndy Fleming 
1412272cc70bSAndy Fleming 	return 0;
1413272cc70bSAndy Fleming }
1414