xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 31cacbabf07ce00f5250b9826d5e48d4bbee1f94)
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 
4311fdade2SStefano Babic int __board_mmc_getcd(u8 *cd, struct mmc *mmc) {
4411fdade2SStefano Babic 	return -1;
4511fdade2SStefano Babic }
4611fdade2SStefano Babic 
4711fdade2SStefano Babic int board_mmc_getcd(u8 *cd, struct mmc *mmc)__attribute__((weak,
4811fdade2SStefano Babic 	alias("__board_mmc_getcd")));
4911fdade2SStefano Babic 
50272cc70bSAndy Fleming int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
51272cc70bSAndy Fleming {
52272cc70bSAndy Fleming 	return mmc->send_cmd(mmc, cmd, data);
53272cc70bSAndy Fleming }
54272cc70bSAndy Fleming 
555d4fc8d9SRaffaele Recalcati int mmc_send_status(struct mmc *mmc, int timeout)
565d4fc8d9SRaffaele Recalcati {
575d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
585d4fc8d9SRaffaele Recalcati 	int err;
595d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
605d4fc8d9SRaffaele Recalcati 	int status;
615d4fc8d9SRaffaele Recalcati #endif
625d4fc8d9SRaffaele Recalcati 
635d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
645d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
655d4fc8d9SRaffaele Recalcati 	cmd.cmdarg = 0;
665d4fc8d9SRaffaele Recalcati 	cmd.flags = 0;
675d4fc8d9SRaffaele Recalcati 
685d4fc8d9SRaffaele Recalcati 	do {
695d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
705d4fc8d9SRaffaele Recalcati 		if (err)
715d4fc8d9SRaffaele Recalcati 			return err;
725d4fc8d9SRaffaele Recalcati 		else if (cmd.response[0] & MMC_STATUS_RDY_FOR_DATA)
735d4fc8d9SRaffaele Recalcati 			break;
745d4fc8d9SRaffaele Recalcati 
755d4fc8d9SRaffaele Recalcati 		udelay(1000);
765d4fc8d9SRaffaele Recalcati 
775d4fc8d9SRaffaele Recalcati 		if (cmd.response[0] & MMC_STATUS_MASK) {
785d4fc8d9SRaffaele Recalcati 			printf("Status Error: 0x%08X\n", cmd.response[0]);
795d4fc8d9SRaffaele Recalcati 			return COMM_ERR;
805d4fc8d9SRaffaele Recalcati 		}
815d4fc8d9SRaffaele Recalcati 	} while (timeout--);
825d4fc8d9SRaffaele Recalcati 
835d4fc8d9SRaffaele Recalcati 	if (!timeout) {
845d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
855d4fc8d9SRaffaele Recalcati 		return TIMEOUT;
865d4fc8d9SRaffaele Recalcati 	}
875d4fc8d9SRaffaele Recalcati 
885d4fc8d9SRaffaele Recalcati 	return 0;
895d4fc8d9SRaffaele Recalcati }
905d4fc8d9SRaffaele Recalcati 
91272cc70bSAndy Fleming int mmc_set_blocklen(struct mmc *mmc, int len)
92272cc70bSAndy Fleming {
93272cc70bSAndy Fleming 	struct mmc_cmd cmd;
94272cc70bSAndy Fleming 
95272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
96272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
97272cc70bSAndy Fleming 	cmd.cmdarg = len;
98272cc70bSAndy Fleming 	cmd.flags = 0;
99272cc70bSAndy Fleming 
100272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
101272cc70bSAndy Fleming }
102272cc70bSAndy Fleming 
103272cc70bSAndy Fleming struct mmc *find_mmc_device(int dev_num)
104272cc70bSAndy Fleming {
105272cc70bSAndy Fleming 	struct mmc *m;
106272cc70bSAndy Fleming 	struct list_head *entry;
107272cc70bSAndy Fleming 
108272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
109272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
110272cc70bSAndy Fleming 
111272cc70bSAndy Fleming 		if (m->block_dev.dev == dev_num)
112272cc70bSAndy Fleming 			return m;
113272cc70bSAndy Fleming 	}
114272cc70bSAndy Fleming 
115272cc70bSAndy Fleming 	printf("MMC Device %d not found\n", dev_num);
116272cc70bSAndy Fleming 
117272cc70bSAndy Fleming 	return NULL;
118272cc70bSAndy Fleming }
119272cc70bSAndy Fleming 
120272cc70bSAndy Fleming static ulong
1210158126eSLei Wen mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)
122272cc70bSAndy Fleming {
123272cc70bSAndy Fleming 	struct mmc_cmd cmd;
124272cc70bSAndy Fleming 	struct mmc_data data;
1255d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
126272cc70bSAndy Fleming 
127d2bf29e3SLei Wen 	if ((start + blkcnt) > mmc->block_dev.lba) {
128def412b6SSteve Sakoman 		printf("MMC: block number 0x%lx exceeds max(0x%lx)\n",
129d2bf29e3SLei Wen 			start + blkcnt, mmc->block_dev.lba);
130d2bf29e3SLei Wen 		return 0;
131d2bf29e3SLei Wen 	}
132272cc70bSAndy Fleming 
133272cc70bSAndy Fleming 	if (blkcnt > 1)
134272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
135272cc70bSAndy Fleming 	else
136272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
137272cc70bSAndy Fleming 
138272cc70bSAndy Fleming 	if (mmc->high_capacity)
139272cc70bSAndy Fleming 		cmd.cmdarg = start;
140272cc70bSAndy Fleming 	else
141def412b6SSteve Sakoman 		cmd.cmdarg = start * mmc->write_bl_len;
142272cc70bSAndy Fleming 
143272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
144272cc70bSAndy Fleming 	cmd.flags = 0;
145272cc70bSAndy Fleming 
146272cc70bSAndy Fleming 	data.src = src;
147272cc70bSAndy Fleming 	data.blocks = blkcnt;
148def412b6SSteve Sakoman 	data.blocksize = mmc->write_bl_len;
149272cc70bSAndy Fleming 	data.flags = MMC_DATA_WRITE;
150272cc70bSAndy Fleming 
151def412b6SSteve Sakoman 	if (mmc_send_cmd(mmc, &cmd, &data)) {
152def412b6SSteve Sakoman 		printf("mmc write failed\n");
153def412b6SSteve Sakoman 		return 0;
154272cc70bSAndy Fleming 	}
155272cc70bSAndy Fleming 
156d52ebf10SThomas Chou 	/* SPI multiblock writes terminate using a special
157d52ebf10SThomas Chou 	 * token, not a STOP_TRANSMISSION request.
158d52ebf10SThomas Chou 	 */
159d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc) && blkcnt > 1) {
160272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
161272cc70bSAndy Fleming 		cmd.cmdarg = 0;
162272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1b;
163272cc70bSAndy Fleming 		cmd.flags = 0;
164def412b6SSteve Sakoman 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
165def412b6SSteve Sakoman 			printf("mmc fail to send stop cmd\n");
166def412b6SSteve Sakoman 			return 0;
167272cc70bSAndy Fleming 		}
1685d4fc8d9SRaffaele Recalcati 
1695d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
1705d4fc8d9SRaffaele Recalcati 		mmc_send_status(mmc, timeout);
1710158126eSLei Wen 	}
1720158126eSLei Wen 
1730158126eSLei Wen 	return blkcnt;
1740158126eSLei Wen }
1750158126eSLei Wen 
1760158126eSLei Wen static ulong
1770158126eSLei Wen mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)
1780158126eSLei Wen {
1790158126eSLei Wen 	lbaint_t cur, blocks_todo = blkcnt;
1800158126eSLei Wen 
181def412b6SSteve Sakoman 	struct mmc *mmc = find_mmc_device(dev_num);
1820158126eSLei Wen 	if (!mmc)
183def412b6SSteve Sakoman 		return 0;
1840158126eSLei Wen 
185def412b6SSteve Sakoman 	if (mmc_set_blocklen(mmc, mmc->write_bl_len))
186def412b6SSteve Sakoman 		return 0;
1870158126eSLei Wen 
1880158126eSLei Wen 	do {
189ce0fbcd2SMatt Waddel 		cur = (blocks_todo > CONFIG_SYS_MMC_MAX_BLK_COUNT) ?
190ce0fbcd2SMatt Waddel 		       CONFIG_SYS_MMC_MAX_BLK_COUNT : blocks_todo;
1910158126eSLei Wen 		if(mmc_write_blocks(mmc, start, cur, src) != cur)
192def412b6SSteve Sakoman 			return 0;
1930158126eSLei Wen 		blocks_todo -= cur;
1940158126eSLei Wen 		start += cur;
1950158126eSLei Wen 		src += cur * mmc->write_bl_len;
1960158126eSLei Wen 	} while (blocks_todo > 0);
197272cc70bSAndy Fleming 
198272cc70bSAndy Fleming 	return blkcnt;
199272cc70bSAndy Fleming }
200272cc70bSAndy Fleming 
2014a1a06bcSAlagu Sankar int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt)
202272cc70bSAndy Fleming {
203272cc70bSAndy Fleming 	struct mmc_cmd cmd;
204272cc70bSAndy Fleming 	struct mmc_data data;
2055d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
206272cc70bSAndy Fleming 
2074a1a06bcSAlagu Sankar 	if (blkcnt > 1)
2084a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
2094a1a06bcSAlagu Sankar 	else
210272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
211272cc70bSAndy Fleming 
212272cc70bSAndy Fleming 	if (mmc->high_capacity)
2134a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
214272cc70bSAndy Fleming 	else
2154a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
216272cc70bSAndy Fleming 
217272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
218272cc70bSAndy Fleming 	cmd.flags = 0;
219272cc70bSAndy Fleming 
220272cc70bSAndy Fleming 	data.dest = dst;
2214a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
222272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
223272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
224272cc70bSAndy Fleming 
2254a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
2264a1a06bcSAlagu Sankar 		return 0;
2274a1a06bcSAlagu Sankar 
2284a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
2294a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
2304a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
2314a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
2324a1a06bcSAlagu Sankar 		cmd.flags = 0;
2334a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
2344a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
2354a1a06bcSAlagu Sankar 			return 0;
2364a1a06bcSAlagu Sankar 		}
2375d4fc8d9SRaffaele Recalcati 
2385d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
2395d4fc8d9SRaffaele Recalcati 		mmc_send_status(mmc, timeout);
240272cc70bSAndy Fleming 	}
241272cc70bSAndy Fleming 
2424a1a06bcSAlagu Sankar 	return blkcnt;
243272cc70bSAndy Fleming }
244272cc70bSAndy Fleming 
245272cc70bSAndy Fleming static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
246272cc70bSAndy Fleming {
2474a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
248272cc70bSAndy Fleming 
2494a1a06bcSAlagu Sankar 	if (blkcnt == 0)
2504a1a06bcSAlagu Sankar 		return 0;
2514a1a06bcSAlagu Sankar 
2524a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
253272cc70bSAndy Fleming 	if (!mmc)
254272cc70bSAndy Fleming 		return 0;
255272cc70bSAndy Fleming 
256d2bf29e3SLei Wen 	if ((start + blkcnt) > mmc->block_dev.lba) {
2574a1a06bcSAlagu Sankar 		printf("MMC: block number 0x%lx exceeds max(0x%lx)\n",
258d2bf29e3SLei Wen 			start + blkcnt, mmc->block_dev.lba);
259d2bf29e3SLei Wen 		return 0;
260d2bf29e3SLei Wen 	}
261272cc70bSAndy Fleming 
2624a1a06bcSAlagu Sankar 	if (mmc_set_blocklen(mmc, mmc->read_bl_len))
263272cc70bSAndy Fleming 		return 0;
264272cc70bSAndy Fleming 
2654a1a06bcSAlagu Sankar 	do {
266ce0fbcd2SMatt Waddel 		cur = (blocks_todo > CONFIG_SYS_MMC_MAX_BLK_COUNT) ?
267ce0fbcd2SMatt Waddel 		       CONFIG_SYS_MMC_MAX_BLK_COUNT : blocks_todo;
2684a1a06bcSAlagu Sankar 		if(mmc_read_blocks(mmc, dst, start, cur) != cur)
2694a1a06bcSAlagu Sankar 			return 0;
2704a1a06bcSAlagu Sankar 		blocks_todo -= cur;
2714a1a06bcSAlagu Sankar 		start += cur;
2724a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
2734a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
274272cc70bSAndy Fleming 
275272cc70bSAndy Fleming 	return blkcnt;
276272cc70bSAndy Fleming }
277272cc70bSAndy Fleming 
278272cc70bSAndy Fleming int mmc_go_idle(struct mmc* mmc)
279272cc70bSAndy Fleming {
280272cc70bSAndy Fleming 	struct mmc_cmd cmd;
281272cc70bSAndy Fleming 	int err;
282272cc70bSAndy Fleming 
283272cc70bSAndy Fleming 	udelay(1000);
284272cc70bSAndy Fleming 
285272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
286272cc70bSAndy Fleming 	cmd.cmdarg = 0;
287272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
288272cc70bSAndy Fleming 	cmd.flags = 0;
289272cc70bSAndy Fleming 
290272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
291272cc70bSAndy Fleming 
292272cc70bSAndy Fleming 	if (err)
293272cc70bSAndy Fleming 		return err;
294272cc70bSAndy Fleming 
295272cc70bSAndy Fleming 	udelay(2000);
296272cc70bSAndy Fleming 
297272cc70bSAndy Fleming 	return 0;
298272cc70bSAndy Fleming }
299272cc70bSAndy Fleming 
300272cc70bSAndy Fleming int
301272cc70bSAndy Fleming sd_send_op_cond(struct mmc *mmc)
302272cc70bSAndy Fleming {
303272cc70bSAndy Fleming 	int timeout = 1000;
304272cc70bSAndy Fleming 	int err;
305272cc70bSAndy Fleming 	struct mmc_cmd cmd;
306272cc70bSAndy Fleming 
307272cc70bSAndy Fleming 	do {
308272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
309272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
310272cc70bSAndy Fleming 		cmd.cmdarg = 0;
311272cc70bSAndy Fleming 		cmd.flags = 0;
312272cc70bSAndy Fleming 
313272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
314272cc70bSAndy Fleming 
315272cc70bSAndy Fleming 		if (err)
316272cc70bSAndy Fleming 			return err;
317272cc70bSAndy Fleming 
318272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
319272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
320250de12bSStefano Babic 
321250de12bSStefano Babic 		/*
322250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
323250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
324250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
325250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
326250de12bSStefano Babic 		 * specified.
327250de12bSStefano Babic 		 */
328d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
329d52ebf10SThomas Chou 			(mmc->voltages & 0xff8000);
330272cc70bSAndy Fleming 
331272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
332272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
333272cc70bSAndy Fleming 
334272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
335272cc70bSAndy Fleming 
336272cc70bSAndy Fleming 		if (err)
337272cc70bSAndy Fleming 			return err;
338272cc70bSAndy Fleming 
339272cc70bSAndy Fleming 		udelay(1000);
340272cc70bSAndy Fleming 	} while ((!(cmd.response[0] & OCR_BUSY)) && timeout--);
341272cc70bSAndy Fleming 
342272cc70bSAndy Fleming 	if (timeout <= 0)
343272cc70bSAndy Fleming 		return UNUSABLE_ERR;
344272cc70bSAndy Fleming 
345272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
346272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
347272cc70bSAndy Fleming 
348d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
349d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
350d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
351d52ebf10SThomas Chou 		cmd.cmdarg = 0;
352d52ebf10SThomas Chou 		cmd.flags = 0;
353d52ebf10SThomas Chou 
354d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
355d52ebf10SThomas Chou 
356d52ebf10SThomas Chou 		if (err)
357d52ebf10SThomas Chou 			return err;
358d52ebf10SThomas Chou 	}
359d52ebf10SThomas Chou 
360998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
361272cc70bSAndy Fleming 
362272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
363272cc70bSAndy Fleming 	mmc->rca = 0;
364272cc70bSAndy Fleming 
365272cc70bSAndy Fleming 	return 0;
366272cc70bSAndy Fleming }
367272cc70bSAndy Fleming 
368272cc70bSAndy Fleming int mmc_send_op_cond(struct mmc *mmc)
369272cc70bSAndy Fleming {
370*31cacbabSRaffaele Recalcati 	int timeout = 10000;
371272cc70bSAndy Fleming 	struct mmc_cmd cmd;
372272cc70bSAndy Fleming 	int err;
373272cc70bSAndy Fleming 
374272cc70bSAndy Fleming 	/* Some cards seem to need this */
375272cc70bSAndy Fleming 	mmc_go_idle(mmc);
376272cc70bSAndy Fleming 
377*31cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
378*31cacbabSRaffaele Recalcati  	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
379*31cacbabSRaffaele Recalcati  	cmd.resp_type = MMC_RSP_R3;
380*31cacbabSRaffaele Recalcati  	cmd.cmdarg = 0;
381*31cacbabSRaffaele Recalcati  	cmd.flags = 0;
382*31cacbabSRaffaele Recalcati 
383*31cacbabSRaffaele Recalcati  	err = mmc_send_cmd(mmc, &cmd, NULL);
384*31cacbabSRaffaele Recalcati 
385*31cacbabSRaffaele Recalcati  	if (err)
386*31cacbabSRaffaele Recalcati  		return err;
387*31cacbabSRaffaele Recalcati 
388*31cacbabSRaffaele Recalcati  	udelay(1000);
389*31cacbabSRaffaele Recalcati 
390272cc70bSAndy Fleming 	do {
391272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SEND_OP_COND;
392272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
393*31cacbabSRaffaele Recalcati 		cmd.cmdarg = (mmc_host_is_spi(mmc) ? 0 :
394*31cacbabSRaffaele Recalcati 				(mmc->voltages &
395*31cacbabSRaffaele Recalcati 				(cmd.response[0] & OCR_VOLTAGE_MASK)) |
396*31cacbabSRaffaele Recalcati 				(cmd.response[0] & OCR_ACCESS_MODE));
397272cc70bSAndy Fleming 		cmd.flags = 0;
398272cc70bSAndy Fleming 
399272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
400272cc70bSAndy Fleming 
401272cc70bSAndy Fleming 		if (err)
402272cc70bSAndy Fleming 			return err;
403272cc70bSAndy Fleming 
404272cc70bSAndy Fleming 		udelay(1000);
405272cc70bSAndy Fleming 	} while (!(cmd.response[0] & OCR_BUSY) && timeout--);
406272cc70bSAndy Fleming 
407272cc70bSAndy Fleming 	if (timeout <= 0)
408272cc70bSAndy Fleming 		return UNUSABLE_ERR;
409272cc70bSAndy Fleming 
410d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
411d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
412d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
413d52ebf10SThomas Chou 		cmd.cmdarg = 0;
414d52ebf10SThomas Chou 		cmd.flags = 0;
415d52ebf10SThomas Chou 
416d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
417d52ebf10SThomas Chou 
418d52ebf10SThomas Chou 		if (err)
419d52ebf10SThomas Chou 			return err;
420d52ebf10SThomas Chou 	}
421d52ebf10SThomas Chou 
422272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
423998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
424272cc70bSAndy Fleming 
425272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
426272cc70bSAndy Fleming 	mmc->rca = 0;
427272cc70bSAndy Fleming 
428272cc70bSAndy Fleming 	return 0;
429272cc70bSAndy Fleming }
430272cc70bSAndy Fleming 
431272cc70bSAndy Fleming 
432272cc70bSAndy Fleming int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd)
433272cc70bSAndy Fleming {
434272cc70bSAndy Fleming 	struct mmc_cmd cmd;
435272cc70bSAndy Fleming 	struct mmc_data data;
436272cc70bSAndy Fleming 	int err;
437272cc70bSAndy Fleming 
438272cc70bSAndy Fleming 	/* Get the Card Status Register */
439272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
440272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
441272cc70bSAndy Fleming 	cmd.cmdarg = 0;
442272cc70bSAndy Fleming 	cmd.flags = 0;
443272cc70bSAndy Fleming 
444272cc70bSAndy Fleming 	data.dest = ext_csd;
445272cc70bSAndy Fleming 	data.blocks = 1;
446272cc70bSAndy Fleming 	data.blocksize = 512;
447272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
448272cc70bSAndy Fleming 
449272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
450272cc70bSAndy Fleming 
451272cc70bSAndy Fleming 	return err;
452272cc70bSAndy Fleming }
453272cc70bSAndy Fleming 
454272cc70bSAndy Fleming 
455272cc70bSAndy Fleming int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
456272cc70bSAndy Fleming {
457272cc70bSAndy Fleming 	struct mmc_cmd cmd;
4585d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
4595d4fc8d9SRaffaele Recalcati 	int ret;
460272cc70bSAndy Fleming 
461272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
462272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
463272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
464272cc70bSAndy Fleming 				 (index << 16) |
465272cc70bSAndy Fleming 				 (value << 8);
466272cc70bSAndy Fleming 	cmd.flags = 0;
467272cc70bSAndy Fleming 
4685d4fc8d9SRaffaele Recalcati 	ret = mmc_send_cmd(mmc, &cmd, NULL);
4695d4fc8d9SRaffaele Recalcati 
4705d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
4715d4fc8d9SRaffaele Recalcati 	mmc_send_status(mmc, timeout);
4725d4fc8d9SRaffaele Recalcati 
4735d4fc8d9SRaffaele Recalcati 	return ret;
4745d4fc8d9SRaffaele Recalcati 
475272cc70bSAndy Fleming }
476272cc70bSAndy Fleming 
477272cc70bSAndy Fleming int mmc_change_freq(struct mmc *mmc)
478272cc70bSAndy Fleming {
479272cc70bSAndy Fleming 	char ext_csd[512];
480272cc70bSAndy Fleming 	char cardtype;
481272cc70bSAndy Fleming 	int err;
482272cc70bSAndy Fleming 
483272cc70bSAndy Fleming 	mmc->card_caps = 0;
484272cc70bSAndy Fleming 
485d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
486d52ebf10SThomas Chou 		return 0;
487d52ebf10SThomas Chou 
488272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
489272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
490272cc70bSAndy Fleming 		return 0;
491272cc70bSAndy Fleming 
492272cc70bSAndy Fleming 	mmc->card_caps |= MMC_MODE_4BIT;
493272cc70bSAndy Fleming 
494272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
495272cc70bSAndy Fleming 
496272cc70bSAndy Fleming 	if (err)
497272cc70bSAndy Fleming 		return err;
498272cc70bSAndy Fleming 
499272cc70bSAndy Fleming 	if (ext_csd[212] || ext_csd[213] || ext_csd[214] || ext_csd[215])
500272cc70bSAndy Fleming 		mmc->high_capacity = 1;
501272cc70bSAndy Fleming 
502272cc70bSAndy Fleming 	cardtype = ext_csd[196] & 0xf;
503272cc70bSAndy Fleming 
504272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
505272cc70bSAndy Fleming 
506272cc70bSAndy Fleming 	if (err)
507272cc70bSAndy Fleming 		return err;
508272cc70bSAndy Fleming 
509272cc70bSAndy Fleming 	/* Now check to see that it worked */
510272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
511272cc70bSAndy Fleming 
512272cc70bSAndy Fleming 	if (err)
513272cc70bSAndy Fleming 		return err;
514272cc70bSAndy Fleming 
515272cc70bSAndy Fleming 	/* No high-speed support */
516272cc70bSAndy Fleming 	if (!ext_csd[185])
517272cc70bSAndy Fleming 		return 0;
518272cc70bSAndy Fleming 
519272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
520272cc70bSAndy Fleming 	if (cardtype & MMC_HS_52MHZ)
521272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
522272cc70bSAndy Fleming 	else
523272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
524272cc70bSAndy Fleming 
525272cc70bSAndy Fleming 	return 0;
526272cc70bSAndy Fleming }
527272cc70bSAndy Fleming 
528272cc70bSAndy Fleming int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
529272cc70bSAndy Fleming {
530272cc70bSAndy Fleming 	struct mmc_cmd cmd;
531272cc70bSAndy Fleming 	struct mmc_data data;
532272cc70bSAndy Fleming 
533272cc70bSAndy Fleming 	/* Switch the frequency */
534272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
535272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
536272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
537272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
538272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
539272cc70bSAndy Fleming 	cmd.flags = 0;
540272cc70bSAndy Fleming 
541272cc70bSAndy Fleming 	data.dest = (char *)resp;
542272cc70bSAndy Fleming 	data.blocksize = 64;
543272cc70bSAndy Fleming 	data.blocks = 1;
544272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
545272cc70bSAndy Fleming 
546272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
547272cc70bSAndy Fleming }
548272cc70bSAndy Fleming 
549272cc70bSAndy Fleming 
550272cc70bSAndy Fleming int sd_change_freq(struct mmc *mmc)
551272cc70bSAndy Fleming {
552272cc70bSAndy Fleming 	int err;
553272cc70bSAndy Fleming 	struct mmc_cmd cmd;
554272cc70bSAndy Fleming 	uint scr[2];
555272cc70bSAndy Fleming 	uint switch_status[16];
556272cc70bSAndy Fleming 	struct mmc_data data;
557272cc70bSAndy Fleming 	int timeout;
558272cc70bSAndy Fleming 
559272cc70bSAndy Fleming 	mmc->card_caps = 0;
560272cc70bSAndy Fleming 
561d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
562d52ebf10SThomas Chou 		return 0;
563d52ebf10SThomas Chou 
564272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
565272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
566272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
567272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
568272cc70bSAndy Fleming 	cmd.flags = 0;
569272cc70bSAndy Fleming 
570272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
571272cc70bSAndy Fleming 
572272cc70bSAndy Fleming 	if (err)
573272cc70bSAndy Fleming 		return err;
574272cc70bSAndy Fleming 
575272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
576272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
577272cc70bSAndy Fleming 	cmd.cmdarg = 0;
578272cc70bSAndy Fleming 	cmd.flags = 0;
579272cc70bSAndy Fleming 
580272cc70bSAndy Fleming 	timeout = 3;
581272cc70bSAndy Fleming 
582272cc70bSAndy Fleming retry_scr:
583272cc70bSAndy Fleming 	data.dest = (char *)&scr;
584272cc70bSAndy Fleming 	data.blocksize = 8;
585272cc70bSAndy Fleming 	data.blocks = 1;
586272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
587272cc70bSAndy Fleming 
588272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
589272cc70bSAndy Fleming 
590272cc70bSAndy Fleming 	if (err) {
591272cc70bSAndy Fleming 		if (timeout--)
592272cc70bSAndy Fleming 			goto retry_scr;
593272cc70bSAndy Fleming 
594272cc70bSAndy Fleming 		return err;
595272cc70bSAndy Fleming 	}
596272cc70bSAndy Fleming 
5974e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
5984e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
599272cc70bSAndy Fleming 
600272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
601272cc70bSAndy Fleming 		case 0:
602272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
603272cc70bSAndy Fleming 			break;
604272cc70bSAndy Fleming 		case 1:
605272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_10;
606272cc70bSAndy Fleming 			break;
607272cc70bSAndy Fleming 		case 2:
608272cc70bSAndy Fleming 			mmc->version = SD_VERSION_2;
609272cc70bSAndy Fleming 			break;
610272cc70bSAndy Fleming 		default:
611272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
612272cc70bSAndy Fleming 			break;
613272cc70bSAndy Fleming 	}
614272cc70bSAndy Fleming 
615b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
616b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
617b44c7083SAlagu Sankar 
618272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
619272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
620272cc70bSAndy Fleming 		return 0;
621272cc70bSAndy Fleming 
622272cc70bSAndy Fleming 	timeout = 4;
623272cc70bSAndy Fleming 	while (timeout--) {
624272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
625272cc70bSAndy Fleming 				(u8 *)&switch_status);
626272cc70bSAndy Fleming 
627272cc70bSAndy Fleming 		if (err)
628272cc70bSAndy Fleming 			return err;
629272cc70bSAndy Fleming 
630272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
6314e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
632272cc70bSAndy Fleming 			break;
633272cc70bSAndy Fleming 	}
634272cc70bSAndy Fleming 
635272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
6364e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
637272cc70bSAndy Fleming 		return 0;
638272cc70bSAndy Fleming 
639272cc70bSAndy Fleming 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)&switch_status);
640272cc70bSAndy Fleming 
641272cc70bSAndy Fleming 	if (err)
642272cc70bSAndy Fleming 		return err;
643272cc70bSAndy Fleming 
6444e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
645272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
646272cc70bSAndy Fleming 
647272cc70bSAndy Fleming 	return 0;
648272cc70bSAndy Fleming }
649272cc70bSAndy Fleming 
650272cc70bSAndy Fleming /* frequency bases */
651272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
6525f837c2cSMike Frysinger static const int fbase[] = {
653272cc70bSAndy Fleming 	10000,
654272cc70bSAndy Fleming 	100000,
655272cc70bSAndy Fleming 	1000000,
656272cc70bSAndy Fleming 	10000000,
657272cc70bSAndy Fleming };
658272cc70bSAndy Fleming 
659272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
660272cc70bSAndy Fleming  * to platforms without floating point.
661272cc70bSAndy Fleming  */
6625f837c2cSMike Frysinger static const int multipliers[] = {
663272cc70bSAndy Fleming 	0,	/* reserved */
664272cc70bSAndy Fleming 	10,
665272cc70bSAndy Fleming 	12,
666272cc70bSAndy Fleming 	13,
667272cc70bSAndy Fleming 	15,
668272cc70bSAndy Fleming 	20,
669272cc70bSAndy Fleming 	25,
670272cc70bSAndy Fleming 	30,
671272cc70bSAndy Fleming 	35,
672272cc70bSAndy Fleming 	40,
673272cc70bSAndy Fleming 	45,
674272cc70bSAndy Fleming 	50,
675272cc70bSAndy Fleming 	55,
676272cc70bSAndy Fleming 	60,
677272cc70bSAndy Fleming 	70,
678272cc70bSAndy Fleming 	80,
679272cc70bSAndy Fleming };
680272cc70bSAndy Fleming 
681272cc70bSAndy Fleming void mmc_set_ios(struct mmc *mmc)
682272cc70bSAndy Fleming {
683272cc70bSAndy Fleming 	mmc->set_ios(mmc);
684272cc70bSAndy Fleming }
685272cc70bSAndy Fleming 
686272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
687272cc70bSAndy Fleming {
688272cc70bSAndy Fleming 	if (clock > mmc->f_max)
689272cc70bSAndy Fleming 		clock = mmc->f_max;
690272cc70bSAndy Fleming 
691272cc70bSAndy Fleming 	if (clock < mmc->f_min)
692272cc70bSAndy Fleming 		clock = mmc->f_min;
693272cc70bSAndy Fleming 
694272cc70bSAndy Fleming 	mmc->clock = clock;
695272cc70bSAndy Fleming 
696272cc70bSAndy Fleming 	mmc_set_ios(mmc);
697272cc70bSAndy Fleming }
698272cc70bSAndy Fleming 
699272cc70bSAndy Fleming void mmc_set_bus_width(struct mmc *mmc, uint width)
700272cc70bSAndy Fleming {
701272cc70bSAndy Fleming 	mmc->bus_width = width;
702272cc70bSAndy Fleming 
703272cc70bSAndy Fleming 	mmc_set_ios(mmc);
704272cc70bSAndy Fleming }
705272cc70bSAndy Fleming 
706272cc70bSAndy Fleming int mmc_startup(struct mmc *mmc)
707272cc70bSAndy Fleming {
708272cc70bSAndy Fleming 	int err;
709272cc70bSAndy Fleming 	uint mult, freq;
710272cc70bSAndy Fleming 	u64 cmult, csize;
711272cc70bSAndy Fleming 	struct mmc_cmd cmd;
712d23e2c09SSukumar Ghorai 	char ext_csd[512];
7135d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
714272cc70bSAndy Fleming 
715d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
716d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
717d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
718d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
719d52ebf10SThomas Chou 		cmd.cmdarg = 1;
720d52ebf10SThomas Chou 		cmd.flags = 0;
721d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
722d52ebf10SThomas Chou 
723d52ebf10SThomas Chou 		if (err)
724d52ebf10SThomas Chou 			return err;
725d52ebf10SThomas Chou 	}
726d52ebf10SThomas Chou #endif
727d52ebf10SThomas Chou 
728272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
729d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
730d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
731272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
732272cc70bSAndy Fleming 	cmd.cmdarg = 0;
733272cc70bSAndy Fleming 	cmd.flags = 0;
734272cc70bSAndy Fleming 
735272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
736272cc70bSAndy Fleming 
737272cc70bSAndy Fleming 	if (err)
738272cc70bSAndy Fleming 		return err;
739272cc70bSAndy Fleming 
740272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
741272cc70bSAndy Fleming 
742272cc70bSAndy Fleming 	/*
743272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
744272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
745272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
746272cc70bSAndy Fleming 	 */
747d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
748272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
749272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
750272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
751272cc70bSAndy Fleming 		cmd.flags = 0;
752272cc70bSAndy Fleming 
753272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
754272cc70bSAndy Fleming 
755272cc70bSAndy Fleming 		if (err)
756272cc70bSAndy Fleming 			return err;
757272cc70bSAndy Fleming 
758272cc70bSAndy Fleming 		if (IS_SD(mmc))
759998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
760d52ebf10SThomas Chou 	}
761272cc70bSAndy Fleming 
762272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
763272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
764272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
765272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
766272cc70bSAndy Fleming 	cmd.flags = 0;
767272cc70bSAndy Fleming 
768272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
769272cc70bSAndy Fleming 
7705d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
7715d4fc8d9SRaffaele Recalcati 	mmc_send_status(mmc, timeout);
7725d4fc8d9SRaffaele Recalcati 
773272cc70bSAndy Fleming 	if (err)
774272cc70bSAndy Fleming 		return err;
775272cc70bSAndy Fleming 
776998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
777998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
778998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
779998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
780272cc70bSAndy Fleming 
781272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
7820b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
783272cc70bSAndy Fleming 
784272cc70bSAndy Fleming 		switch (version) {
785272cc70bSAndy Fleming 			case 0:
786272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
787272cc70bSAndy Fleming 				break;
788272cc70bSAndy Fleming 			case 1:
789272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_4;
790272cc70bSAndy Fleming 				break;
791272cc70bSAndy Fleming 			case 2:
792272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_2_2;
793272cc70bSAndy Fleming 				break;
794272cc70bSAndy Fleming 			case 3:
795272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_3;
796272cc70bSAndy Fleming 				break;
797272cc70bSAndy Fleming 			case 4:
798272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_4;
799272cc70bSAndy Fleming 				break;
800272cc70bSAndy Fleming 			default:
801272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
802272cc70bSAndy Fleming 				break;
803272cc70bSAndy Fleming 		}
804272cc70bSAndy Fleming 	}
805272cc70bSAndy Fleming 
806272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
8070b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
8080b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
809272cc70bSAndy Fleming 
810272cc70bSAndy Fleming 	mmc->tran_speed = freq * mult;
811272cc70bSAndy Fleming 
812998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
813272cc70bSAndy Fleming 
814272cc70bSAndy Fleming 	if (IS_SD(mmc))
815272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
816272cc70bSAndy Fleming 	else
817998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
818272cc70bSAndy Fleming 
819272cc70bSAndy Fleming 	if (mmc->high_capacity) {
820272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
821272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
822272cc70bSAndy Fleming 		cmult = 8;
823272cc70bSAndy Fleming 	} else {
824272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
825272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
826272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
827272cc70bSAndy Fleming 	}
828272cc70bSAndy Fleming 
829272cc70bSAndy Fleming 	mmc->capacity = (csize + 1) << (cmult + 2);
830272cc70bSAndy Fleming 	mmc->capacity *= mmc->read_bl_len;
831272cc70bSAndy Fleming 
832272cc70bSAndy Fleming 	if (mmc->read_bl_len > 512)
833272cc70bSAndy Fleming 		mmc->read_bl_len = 512;
834272cc70bSAndy Fleming 
835272cc70bSAndy Fleming 	if (mmc->write_bl_len > 512)
836272cc70bSAndy Fleming 		mmc->write_bl_len = 512;
837272cc70bSAndy Fleming 
838272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
839d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
840272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
841272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1b;
842272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
843272cc70bSAndy Fleming 		cmd.flags = 0;
844272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
845272cc70bSAndy Fleming 
846272cc70bSAndy Fleming 		if (err)
847272cc70bSAndy Fleming 			return err;
848d52ebf10SThomas Chou 	}
849272cc70bSAndy Fleming 
850d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
851d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
852d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
853d23e2c09SSukumar Ghorai 		if (!err & (ext_csd[192] >= 2)) {
854d23e2c09SSukumar Ghorai 			mmc->capacity = ext_csd[212] << 0 | ext_csd[213] << 8 |
855d23e2c09SSukumar Ghorai 					ext_csd[214] << 16 | ext_csd[215] << 24;
856d23e2c09SSukumar Ghorai 			mmc->capacity *= 512;
857d23e2c09SSukumar Ghorai 		}
858d23e2c09SSukumar Ghorai 	}
859d23e2c09SSukumar Ghorai 
860272cc70bSAndy Fleming 	if (IS_SD(mmc))
861272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
862272cc70bSAndy Fleming 	else
863272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
864272cc70bSAndy Fleming 
865272cc70bSAndy Fleming 	if (err)
866272cc70bSAndy Fleming 		return err;
867272cc70bSAndy Fleming 
868272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
869272cc70bSAndy Fleming 	mmc->card_caps &= mmc->host_caps;
870272cc70bSAndy Fleming 
871272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
872272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
873272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
874272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
875272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
876272cc70bSAndy Fleming 			cmd.flags = 0;
877272cc70bSAndy Fleming 
878272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
879272cc70bSAndy Fleming 			if (err)
880272cc70bSAndy Fleming 				return err;
881272cc70bSAndy Fleming 
882272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
883272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
884272cc70bSAndy Fleming 			cmd.cmdarg = 2;
885272cc70bSAndy Fleming 			cmd.flags = 0;
886272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
887272cc70bSAndy Fleming 			if (err)
888272cc70bSAndy Fleming 				return err;
889272cc70bSAndy Fleming 
890272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
891272cc70bSAndy Fleming 		}
892272cc70bSAndy Fleming 
893272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
894272cc70bSAndy Fleming 			mmc_set_clock(mmc, 50000000);
895272cc70bSAndy Fleming 		else
896272cc70bSAndy Fleming 			mmc_set_clock(mmc, 25000000);
897272cc70bSAndy Fleming 	} else {
898272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
899272cc70bSAndy Fleming 			/* Set the card to use 4 bit*/
900272cc70bSAndy Fleming 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
901272cc70bSAndy Fleming 					EXT_CSD_BUS_WIDTH,
902272cc70bSAndy Fleming 					EXT_CSD_BUS_WIDTH_4);
903272cc70bSAndy Fleming 
904272cc70bSAndy Fleming 			if (err)
905272cc70bSAndy Fleming 				return err;
906272cc70bSAndy Fleming 
907272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
908272cc70bSAndy Fleming 		} else if (mmc->card_caps & MMC_MODE_8BIT) {
909272cc70bSAndy Fleming 			/* Set the card to use 8 bit*/
910272cc70bSAndy Fleming 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
911272cc70bSAndy Fleming 					EXT_CSD_BUS_WIDTH,
912272cc70bSAndy Fleming 					EXT_CSD_BUS_WIDTH_8);
913272cc70bSAndy Fleming 
914272cc70bSAndy Fleming 			if (err)
915272cc70bSAndy Fleming 				return err;
916272cc70bSAndy Fleming 
917272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 8);
918272cc70bSAndy Fleming 		}
919272cc70bSAndy Fleming 
920272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS) {
921272cc70bSAndy Fleming 			if (mmc->card_caps & MMC_MODE_HS_52MHz)
922272cc70bSAndy Fleming 				mmc_set_clock(mmc, 52000000);
923272cc70bSAndy Fleming 			else
924272cc70bSAndy Fleming 				mmc_set_clock(mmc, 26000000);
925272cc70bSAndy Fleming 		} else
926272cc70bSAndy Fleming 			mmc_set_clock(mmc, 20000000);
927272cc70bSAndy Fleming 	}
928272cc70bSAndy Fleming 
929272cc70bSAndy Fleming 	/* fill in device description */
930272cc70bSAndy Fleming 	mmc->block_dev.lun = 0;
931272cc70bSAndy Fleming 	mmc->block_dev.type = 0;
932272cc70bSAndy Fleming 	mmc->block_dev.blksz = mmc->read_bl_len;
9339b1f942cSRabin Vincent 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
9340b453ffeSRabin Vincent 	sprintf(mmc->block_dev.vendor, "Man %06x Snr %08x", mmc->cid[0] >> 8,
9350b453ffeSRabin Vincent 			(mmc->cid[2] << 8) | (mmc->cid[3] >> 24));
9360b453ffeSRabin Vincent 	sprintf(mmc->block_dev.product, "%c%c%c%c%c", mmc->cid[0] & 0xff,
9370b453ffeSRabin Vincent 			(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
9380b453ffeSRabin Vincent 			(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff);
9390b453ffeSRabin Vincent 	sprintf(mmc->block_dev.revision, "%d.%d", mmc->cid[2] >> 28,
9400b453ffeSRabin Vincent 			(mmc->cid[2] >> 24) & 0xf);
941272cc70bSAndy Fleming 	init_part(&mmc->block_dev);
942272cc70bSAndy Fleming 
943272cc70bSAndy Fleming 	return 0;
944272cc70bSAndy Fleming }
945272cc70bSAndy Fleming 
946272cc70bSAndy Fleming int mmc_send_if_cond(struct mmc *mmc)
947272cc70bSAndy Fleming {
948272cc70bSAndy Fleming 	struct mmc_cmd cmd;
949272cc70bSAndy Fleming 	int err;
950272cc70bSAndy Fleming 
951272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
952272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
953272cc70bSAndy Fleming 	cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa;
954272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
955272cc70bSAndy Fleming 	cmd.flags = 0;
956272cc70bSAndy Fleming 
957272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
958272cc70bSAndy Fleming 
959272cc70bSAndy Fleming 	if (err)
960272cc70bSAndy Fleming 		return err;
961272cc70bSAndy Fleming 
962998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
963272cc70bSAndy Fleming 		return UNUSABLE_ERR;
964272cc70bSAndy Fleming 	else
965272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
966272cc70bSAndy Fleming 
967272cc70bSAndy Fleming 	return 0;
968272cc70bSAndy Fleming }
969272cc70bSAndy Fleming 
970272cc70bSAndy Fleming int mmc_register(struct mmc *mmc)
971272cc70bSAndy Fleming {
972272cc70bSAndy Fleming 	/* Setup the universal parts of the block interface just once */
973272cc70bSAndy Fleming 	mmc->block_dev.if_type = IF_TYPE_MMC;
974272cc70bSAndy Fleming 	mmc->block_dev.dev = cur_dev_num++;
975272cc70bSAndy Fleming 	mmc->block_dev.removable = 1;
976272cc70bSAndy Fleming 	mmc->block_dev.block_read = mmc_bread;
977272cc70bSAndy Fleming 	mmc->block_dev.block_write = mmc_bwrite;
978272cc70bSAndy Fleming 
979272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc->link);
980272cc70bSAndy Fleming 
981272cc70bSAndy Fleming 	list_add_tail (&mmc->link, &mmc_devices);
982272cc70bSAndy Fleming 
983272cc70bSAndy Fleming 	return 0;
984272cc70bSAndy Fleming }
985272cc70bSAndy Fleming 
986272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev)
987272cc70bSAndy Fleming {
988272cc70bSAndy Fleming 	struct mmc *mmc = find_mmc_device(dev);
989272cc70bSAndy Fleming 
990e85649c7SRabin Vincent 	return mmc ? &mmc->block_dev : NULL;
991272cc70bSAndy Fleming }
992272cc70bSAndy Fleming 
993272cc70bSAndy Fleming int mmc_init(struct mmc *mmc)
994272cc70bSAndy Fleming {
995272cc70bSAndy Fleming 	int err;
996272cc70bSAndy Fleming 
997272cc70bSAndy Fleming 	err = mmc->init(mmc);
998272cc70bSAndy Fleming 
999272cc70bSAndy Fleming 	if (err)
1000272cc70bSAndy Fleming 		return err;
1001272cc70bSAndy Fleming 
1002b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1003b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1004b86b85e2SIlya Yanok 
1005272cc70bSAndy Fleming 	/* Reset the Card */
1006272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1007272cc70bSAndy Fleming 
1008272cc70bSAndy Fleming 	if (err)
1009272cc70bSAndy Fleming 		return err;
1010272cc70bSAndy Fleming 
1011272cc70bSAndy Fleming 	/* Test for SD version 2 */
1012272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1013272cc70bSAndy Fleming 
1014272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1015272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1016272cc70bSAndy Fleming 
1017272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1018272cc70bSAndy Fleming 	if (err == TIMEOUT) {
1019272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1020272cc70bSAndy Fleming 
1021272cc70bSAndy Fleming 		if (err) {
1022272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
1023272cc70bSAndy Fleming 			return UNUSABLE_ERR;
1024272cc70bSAndy Fleming 		}
1025272cc70bSAndy Fleming 	}
1026272cc70bSAndy Fleming 
1027272cc70bSAndy Fleming 	return mmc_startup(mmc);
1028272cc70bSAndy Fleming }
1029272cc70bSAndy Fleming 
1030272cc70bSAndy Fleming /*
1031272cc70bSAndy Fleming  * CPU and board-specific MMC initializations.  Aliased function
1032272cc70bSAndy Fleming  * signals caller to move on
1033272cc70bSAndy Fleming  */
1034272cc70bSAndy Fleming static int __def_mmc_init(bd_t *bis)
1035272cc70bSAndy Fleming {
1036272cc70bSAndy Fleming 	return -1;
1037272cc70bSAndy Fleming }
1038272cc70bSAndy Fleming 
1039f9a109b3SPeter Tyser int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
1040f9a109b3SPeter Tyser int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
1041272cc70bSAndy Fleming 
1042272cc70bSAndy Fleming void print_mmc_devices(char separator)
1043272cc70bSAndy Fleming {
1044272cc70bSAndy Fleming 	struct mmc *m;
1045272cc70bSAndy Fleming 	struct list_head *entry;
1046272cc70bSAndy Fleming 
1047272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
1048272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
1049272cc70bSAndy Fleming 
1050272cc70bSAndy Fleming 		printf("%s: %d", m->name, m->block_dev.dev);
1051272cc70bSAndy Fleming 
1052272cc70bSAndy Fleming 		if (entry->next != &mmc_devices)
1053272cc70bSAndy Fleming 			printf("%c ", separator);
1054272cc70bSAndy Fleming 	}
1055272cc70bSAndy Fleming 
1056272cc70bSAndy Fleming 	printf("\n");
1057272cc70bSAndy Fleming }
1058272cc70bSAndy Fleming 
1059272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1060272cc70bSAndy Fleming {
1061272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc_devices);
1062272cc70bSAndy Fleming 	cur_dev_num = 0;
1063272cc70bSAndy Fleming 
1064272cc70bSAndy Fleming 	if (board_mmc_init(bis) < 0)
1065272cc70bSAndy Fleming 		cpu_mmc_init(bis);
1066272cc70bSAndy Fleming 
1067272cc70bSAndy Fleming 	print_mmc_devices(',');
1068272cc70bSAndy Fleming 
1069272cc70bSAndy Fleming 	return 0;
1070272cc70bSAndy Fleming }
1071