xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 5d4fc8d907ed12844b9c9190601fef2919f3ec25)
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 
55*5d4fc8d9SRaffaele Recalcati int mmc_send_status(struct mmc *mmc, int timeout)
56*5d4fc8d9SRaffaele Recalcati {
57*5d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
58*5d4fc8d9SRaffaele Recalcati 	int err;
59*5d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
60*5d4fc8d9SRaffaele Recalcati 	int status;
61*5d4fc8d9SRaffaele Recalcati #endif
62*5d4fc8d9SRaffaele Recalcati 
63*5d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
64*5d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
65*5d4fc8d9SRaffaele Recalcati 	cmd.cmdarg = 0;
66*5d4fc8d9SRaffaele Recalcati 	cmd.flags = 0;
67*5d4fc8d9SRaffaele Recalcati 
68*5d4fc8d9SRaffaele Recalcati 	do {
69*5d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
70*5d4fc8d9SRaffaele Recalcati 		if (err)
71*5d4fc8d9SRaffaele Recalcati 			return err;
72*5d4fc8d9SRaffaele Recalcati 		else if (cmd.response[0] & MMC_STATUS_RDY_FOR_DATA)
73*5d4fc8d9SRaffaele Recalcati 			break;
74*5d4fc8d9SRaffaele Recalcati 
75*5d4fc8d9SRaffaele Recalcati 		udelay(1000);
76*5d4fc8d9SRaffaele Recalcati 
77*5d4fc8d9SRaffaele Recalcati 		if (cmd.response[0] & MMC_STATUS_MASK) {
78*5d4fc8d9SRaffaele Recalcati 			printf("Status Error: 0x%08X\n", cmd.response[0]);
79*5d4fc8d9SRaffaele Recalcati 			return COMM_ERR;
80*5d4fc8d9SRaffaele Recalcati 		}
81*5d4fc8d9SRaffaele Recalcati 	} while (timeout--);
82*5d4fc8d9SRaffaele Recalcati 
83*5d4fc8d9SRaffaele Recalcati 	if (!timeout) {
84*5d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
85*5d4fc8d9SRaffaele Recalcati 		return TIMEOUT;
86*5d4fc8d9SRaffaele Recalcati 	}
87*5d4fc8d9SRaffaele Recalcati 
88*5d4fc8d9SRaffaele Recalcati 	return 0;
89*5d4fc8d9SRaffaele Recalcati }
90*5d4fc8d9SRaffaele 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;
125*5d4fc8d9SRaffaele 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 		}
168*5d4fc8d9SRaffaele Recalcati 
169*5d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
170*5d4fc8d9SRaffaele 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;
205*5d4fc8d9SRaffaele 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 		}
237*5d4fc8d9SRaffaele Recalcati 
238*5d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
239*5d4fc8d9SRaffaele 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 {
370272cc70bSAndy Fleming 	int timeout = 1000;
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 
377272cc70bSAndy Fleming 	do {
378272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SEND_OP_COND;
379272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
380d52ebf10SThomas Chou 		cmd.cmdarg = OCR_HCS | (mmc_host_is_spi(mmc) ? 0 :
381d52ebf10SThomas Chou 					mmc->voltages);
382272cc70bSAndy Fleming 		cmd.flags = 0;
383272cc70bSAndy Fleming 
384272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
385272cc70bSAndy Fleming 
386272cc70bSAndy Fleming 		if (err)
387272cc70bSAndy Fleming 			return err;
388272cc70bSAndy Fleming 
389272cc70bSAndy Fleming 		udelay(1000);
390272cc70bSAndy Fleming 	} while (!(cmd.response[0] & OCR_BUSY) && timeout--);
391272cc70bSAndy Fleming 
392272cc70bSAndy Fleming 	if (timeout <= 0)
393272cc70bSAndy Fleming 		return UNUSABLE_ERR;
394272cc70bSAndy Fleming 
395d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
396d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
397d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
398d52ebf10SThomas Chou 		cmd.cmdarg = 0;
399d52ebf10SThomas Chou 		cmd.flags = 0;
400d52ebf10SThomas Chou 
401d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
402d52ebf10SThomas Chou 
403d52ebf10SThomas Chou 		if (err)
404d52ebf10SThomas Chou 			return err;
405d52ebf10SThomas Chou 	}
406d52ebf10SThomas Chou 
407272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
408998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
409272cc70bSAndy Fleming 
410272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
411272cc70bSAndy Fleming 	mmc->rca = 0;
412272cc70bSAndy Fleming 
413272cc70bSAndy Fleming 	return 0;
414272cc70bSAndy Fleming }
415272cc70bSAndy Fleming 
416272cc70bSAndy Fleming 
417272cc70bSAndy Fleming int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd)
418272cc70bSAndy Fleming {
419272cc70bSAndy Fleming 	struct mmc_cmd cmd;
420272cc70bSAndy Fleming 	struct mmc_data data;
421272cc70bSAndy Fleming 	int err;
422272cc70bSAndy Fleming 
423272cc70bSAndy Fleming 	/* Get the Card Status Register */
424272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
425272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
426272cc70bSAndy Fleming 	cmd.cmdarg = 0;
427272cc70bSAndy Fleming 	cmd.flags = 0;
428272cc70bSAndy Fleming 
429272cc70bSAndy Fleming 	data.dest = ext_csd;
430272cc70bSAndy Fleming 	data.blocks = 1;
431272cc70bSAndy Fleming 	data.blocksize = 512;
432272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
433272cc70bSAndy Fleming 
434272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
435272cc70bSAndy Fleming 
436272cc70bSAndy Fleming 	return err;
437272cc70bSAndy Fleming }
438272cc70bSAndy Fleming 
439272cc70bSAndy Fleming 
440272cc70bSAndy Fleming int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
441272cc70bSAndy Fleming {
442272cc70bSAndy Fleming 	struct mmc_cmd cmd;
443*5d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
444*5d4fc8d9SRaffaele Recalcati 	int ret;
445272cc70bSAndy Fleming 
446272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
447272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
448272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
449272cc70bSAndy Fleming 				 (index << 16) |
450272cc70bSAndy Fleming 				 (value << 8);
451272cc70bSAndy Fleming 	cmd.flags = 0;
452272cc70bSAndy Fleming 
453*5d4fc8d9SRaffaele Recalcati 	ret = mmc_send_cmd(mmc, &cmd, NULL);
454*5d4fc8d9SRaffaele Recalcati 
455*5d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
456*5d4fc8d9SRaffaele Recalcati 	mmc_send_status(mmc, timeout);
457*5d4fc8d9SRaffaele Recalcati 
458*5d4fc8d9SRaffaele Recalcati 	return ret;
459*5d4fc8d9SRaffaele Recalcati 
460272cc70bSAndy Fleming }
461272cc70bSAndy Fleming 
462272cc70bSAndy Fleming int mmc_change_freq(struct mmc *mmc)
463272cc70bSAndy Fleming {
464272cc70bSAndy Fleming 	char ext_csd[512];
465272cc70bSAndy Fleming 	char cardtype;
466272cc70bSAndy Fleming 	int err;
467272cc70bSAndy Fleming 
468272cc70bSAndy Fleming 	mmc->card_caps = 0;
469272cc70bSAndy Fleming 
470d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
471d52ebf10SThomas Chou 		return 0;
472d52ebf10SThomas Chou 
473272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
474272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
475272cc70bSAndy Fleming 		return 0;
476272cc70bSAndy Fleming 
477272cc70bSAndy Fleming 	mmc->card_caps |= MMC_MODE_4BIT;
478272cc70bSAndy Fleming 
479272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
480272cc70bSAndy Fleming 
481272cc70bSAndy Fleming 	if (err)
482272cc70bSAndy Fleming 		return err;
483272cc70bSAndy Fleming 
484272cc70bSAndy Fleming 	if (ext_csd[212] || ext_csd[213] || ext_csd[214] || ext_csd[215])
485272cc70bSAndy Fleming 		mmc->high_capacity = 1;
486272cc70bSAndy Fleming 
487272cc70bSAndy Fleming 	cardtype = ext_csd[196] & 0xf;
488272cc70bSAndy Fleming 
489272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
490272cc70bSAndy Fleming 
491272cc70bSAndy Fleming 	if (err)
492272cc70bSAndy Fleming 		return err;
493272cc70bSAndy Fleming 
494272cc70bSAndy Fleming 	/* Now check to see that it worked */
495272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
496272cc70bSAndy Fleming 
497272cc70bSAndy Fleming 	if (err)
498272cc70bSAndy Fleming 		return err;
499272cc70bSAndy Fleming 
500272cc70bSAndy Fleming 	/* No high-speed support */
501272cc70bSAndy Fleming 	if (!ext_csd[185])
502272cc70bSAndy Fleming 		return 0;
503272cc70bSAndy Fleming 
504272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
505272cc70bSAndy Fleming 	if (cardtype & MMC_HS_52MHZ)
506272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
507272cc70bSAndy Fleming 	else
508272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
509272cc70bSAndy Fleming 
510272cc70bSAndy Fleming 	return 0;
511272cc70bSAndy Fleming }
512272cc70bSAndy Fleming 
513272cc70bSAndy Fleming int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
514272cc70bSAndy Fleming {
515272cc70bSAndy Fleming 	struct mmc_cmd cmd;
516272cc70bSAndy Fleming 	struct mmc_data data;
517272cc70bSAndy Fleming 
518272cc70bSAndy Fleming 	/* Switch the frequency */
519272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
520272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
521272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
522272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
523272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
524272cc70bSAndy Fleming 	cmd.flags = 0;
525272cc70bSAndy Fleming 
526272cc70bSAndy Fleming 	data.dest = (char *)resp;
527272cc70bSAndy Fleming 	data.blocksize = 64;
528272cc70bSAndy Fleming 	data.blocks = 1;
529272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
530272cc70bSAndy Fleming 
531272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
532272cc70bSAndy Fleming }
533272cc70bSAndy Fleming 
534272cc70bSAndy Fleming 
535272cc70bSAndy Fleming int sd_change_freq(struct mmc *mmc)
536272cc70bSAndy Fleming {
537272cc70bSAndy Fleming 	int err;
538272cc70bSAndy Fleming 	struct mmc_cmd cmd;
539272cc70bSAndy Fleming 	uint scr[2];
540272cc70bSAndy Fleming 	uint switch_status[16];
541272cc70bSAndy Fleming 	struct mmc_data data;
542272cc70bSAndy Fleming 	int timeout;
543272cc70bSAndy Fleming 
544272cc70bSAndy Fleming 	mmc->card_caps = 0;
545272cc70bSAndy Fleming 
546d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
547d52ebf10SThomas Chou 		return 0;
548d52ebf10SThomas Chou 
549272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
550272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
551272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
552272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
553272cc70bSAndy Fleming 	cmd.flags = 0;
554272cc70bSAndy Fleming 
555272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
556272cc70bSAndy Fleming 
557272cc70bSAndy Fleming 	if (err)
558272cc70bSAndy Fleming 		return err;
559272cc70bSAndy Fleming 
560272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
561272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
562272cc70bSAndy Fleming 	cmd.cmdarg = 0;
563272cc70bSAndy Fleming 	cmd.flags = 0;
564272cc70bSAndy Fleming 
565272cc70bSAndy Fleming 	timeout = 3;
566272cc70bSAndy Fleming 
567272cc70bSAndy Fleming retry_scr:
568272cc70bSAndy Fleming 	data.dest = (char *)&scr;
569272cc70bSAndy Fleming 	data.blocksize = 8;
570272cc70bSAndy Fleming 	data.blocks = 1;
571272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
572272cc70bSAndy Fleming 
573272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
574272cc70bSAndy Fleming 
575272cc70bSAndy Fleming 	if (err) {
576272cc70bSAndy Fleming 		if (timeout--)
577272cc70bSAndy Fleming 			goto retry_scr;
578272cc70bSAndy Fleming 
579272cc70bSAndy Fleming 		return err;
580272cc70bSAndy Fleming 	}
581272cc70bSAndy Fleming 
5824e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
5834e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
584272cc70bSAndy Fleming 
585272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
586272cc70bSAndy Fleming 		case 0:
587272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
588272cc70bSAndy Fleming 			break;
589272cc70bSAndy Fleming 		case 1:
590272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_10;
591272cc70bSAndy Fleming 			break;
592272cc70bSAndy Fleming 		case 2:
593272cc70bSAndy Fleming 			mmc->version = SD_VERSION_2;
594272cc70bSAndy Fleming 			break;
595272cc70bSAndy Fleming 		default:
596272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
597272cc70bSAndy Fleming 			break;
598272cc70bSAndy Fleming 	}
599272cc70bSAndy Fleming 
600b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
601b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
602b44c7083SAlagu Sankar 
603272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
604272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
605272cc70bSAndy Fleming 		return 0;
606272cc70bSAndy Fleming 
607272cc70bSAndy Fleming 	timeout = 4;
608272cc70bSAndy Fleming 	while (timeout--) {
609272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
610272cc70bSAndy Fleming 				(u8 *)&switch_status);
611272cc70bSAndy Fleming 
612272cc70bSAndy Fleming 		if (err)
613272cc70bSAndy Fleming 			return err;
614272cc70bSAndy Fleming 
615272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
6164e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
617272cc70bSAndy Fleming 			break;
618272cc70bSAndy Fleming 	}
619272cc70bSAndy Fleming 
620272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
6214e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
622272cc70bSAndy Fleming 		return 0;
623272cc70bSAndy Fleming 
624272cc70bSAndy Fleming 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)&switch_status);
625272cc70bSAndy Fleming 
626272cc70bSAndy Fleming 	if (err)
627272cc70bSAndy Fleming 		return err;
628272cc70bSAndy Fleming 
6294e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
630272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
631272cc70bSAndy Fleming 
632272cc70bSAndy Fleming 	return 0;
633272cc70bSAndy Fleming }
634272cc70bSAndy Fleming 
635272cc70bSAndy Fleming /* frequency bases */
636272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
6375f837c2cSMike Frysinger static const int fbase[] = {
638272cc70bSAndy Fleming 	10000,
639272cc70bSAndy Fleming 	100000,
640272cc70bSAndy Fleming 	1000000,
641272cc70bSAndy Fleming 	10000000,
642272cc70bSAndy Fleming };
643272cc70bSAndy Fleming 
644272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
645272cc70bSAndy Fleming  * to platforms without floating point.
646272cc70bSAndy Fleming  */
6475f837c2cSMike Frysinger static const int multipliers[] = {
648272cc70bSAndy Fleming 	0,	/* reserved */
649272cc70bSAndy Fleming 	10,
650272cc70bSAndy Fleming 	12,
651272cc70bSAndy Fleming 	13,
652272cc70bSAndy Fleming 	15,
653272cc70bSAndy Fleming 	20,
654272cc70bSAndy Fleming 	25,
655272cc70bSAndy Fleming 	30,
656272cc70bSAndy Fleming 	35,
657272cc70bSAndy Fleming 	40,
658272cc70bSAndy Fleming 	45,
659272cc70bSAndy Fleming 	50,
660272cc70bSAndy Fleming 	55,
661272cc70bSAndy Fleming 	60,
662272cc70bSAndy Fleming 	70,
663272cc70bSAndy Fleming 	80,
664272cc70bSAndy Fleming };
665272cc70bSAndy Fleming 
666272cc70bSAndy Fleming void mmc_set_ios(struct mmc *mmc)
667272cc70bSAndy Fleming {
668272cc70bSAndy Fleming 	mmc->set_ios(mmc);
669272cc70bSAndy Fleming }
670272cc70bSAndy Fleming 
671272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
672272cc70bSAndy Fleming {
673272cc70bSAndy Fleming 	if (clock > mmc->f_max)
674272cc70bSAndy Fleming 		clock = mmc->f_max;
675272cc70bSAndy Fleming 
676272cc70bSAndy Fleming 	if (clock < mmc->f_min)
677272cc70bSAndy Fleming 		clock = mmc->f_min;
678272cc70bSAndy Fleming 
679272cc70bSAndy Fleming 	mmc->clock = clock;
680272cc70bSAndy Fleming 
681272cc70bSAndy Fleming 	mmc_set_ios(mmc);
682272cc70bSAndy Fleming }
683272cc70bSAndy Fleming 
684272cc70bSAndy Fleming void mmc_set_bus_width(struct mmc *mmc, uint width)
685272cc70bSAndy Fleming {
686272cc70bSAndy Fleming 	mmc->bus_width = width;
687272cc70bSAndy Fleming 
688272cc70bSAndy Fleming 	mmc_set_ios(mmc);
689272cc70bSAndy Fleming }
690272cc70bSAndy Fleming 
691272cc70bSAndy Fleming int mmc_startup(struct mmc *mmc)
692272cc70bSAndy Fleming {
693272cc70bSAndy Fleming 	int err;
694272cc70bSAndy Fleming 	uint mult, freq;
695272cc70bSAndy Fleming 	u64 cmult, csize;
696272cc70bSAndy Fleming 	struct mmc_cmd cmd;
697d23e2c09SSukumar Ghorai 	char ext_csd[512];
698*5d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
699272cc70bSAndy Fleming 
700d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
701d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
702d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
703d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
704d52ebf10SThomas Chou 		cmd.cmdarg = 1;
705d52ebf10SThomas Chou 		cmd.flags = 0;
706d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
707d52ebf10SThomas Chou 
708d52ebf10SThomas Chou 		if (err)
709d52ebf10SThomas Chou 			return err;
710d52ebf10SThomas Chou 	}
711d52ebf10SThomas Chou #endif
712d52ebf10SThomas Chou 
713272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
714d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
715d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
716272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
717272cc70bSAndy Fleming 	cmd.cmdarg = 0;
718272cc70bSAndy Fleming 	cmd.flags = 0;
719272cc70bSAndy Fleming 
720272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
721272cc70bSAndy Fleming 
722272cc70bSAndy Fleming 	if (err)
723272cc70bSAndy Fleming 		return err;
724272cc70bSAndy Fleming 
725272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
726272cc70bSAndy Fleming 
727272cc70bSAndy Fleming 	/*
728272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
729272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
730272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
731272cc70bSAndy Fleming 	 */
732d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
733272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
734272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
735272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
736272cc70bSAndy Fleming 		cmd.flags = 0;
737272cc70bSAndy Fleming 
738272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
739272cc70bSAndy Fleming 
740272cc70bSAndy Fleming 		if (err)
741272cc70bSAndy Fleming 			return err;
742272cc70bSAndy Fleming 
743272cc70bSAndy Fleming 		if (IS_SD(mmc))
744998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
745d52ebf10SThomas Chou 	}
746272cc70bSAndy Fleming 
747272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
748272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
749272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
750272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
751272cc70bSAndy Fleming 	cmd.flags = 0;
752272cc70bSAndy Fleming 
753272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
754272cc70bSAndy Fleming 
755*5d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
756*5d4fc8d9SRaffaele Recalcati 	mmc_send_status(mmc, timeout);
757*5d4fc8d9SRaffaele Recalcati 
758272cc70bSAndy Fleming 	if (err)
759272cc70bSAndy Fleming 		return err;
760272cc70bSAndy Fleming 
761998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
762998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
763998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
764998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
765272cc70bSAndy Fleming 
766272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
7670b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
768272cc70bSAndy Fleming 
769272cc70bSAndy Fleming 		switch (version) {
770272cc70bSAndy Fleming 			case 0:
771272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
772272cc70bSAndy Fleming 				break;
773272cc70bSAndy Fleming 			case 1:
774272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_4;
775272cc70bSAndy Fleming 				break;
776272cc70bSAndy Fleming 			case 2:
777272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_2_2;
778272cc70bSAndy Fleming 				break;
779272cc70bSAndy Fleming 			case 3:
780272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_3;
781272cc70bSAndy Fleming 				break;
782272cc70bSAndy Fleming 			case 4:
783272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_4;
784272cc70bSAndy Fleming 				break;
785272cc70bSAndy Fleming 			default:
786272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
787272cc70bSAndy Fleming 				break;
788272cc70bSAndy Fleming 		}
789272cc70bSAndy Fleming 	}
790272cc70bSAndy Fleming 
791272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
7920b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
7930b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
794272cc70bSAndy Fleming 
795272cc70bSAndy Fleming 	mmc->tran_speed = freq * mult;
796272cc70bSAndy Fleming 
797998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
798272cc70bSAndy Fleming 
799272cc70bSAndy Fleming 	if (IS_SD(mmc))
800272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
801272cc70bSAndy Fleming 	else
802998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
803272cc70bSAndy Fleming 
804272cc70bSAndy Fleming 	if (mmc->high_capacity) {
805272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
806272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
807272cc70bSAndy Fleming 		cmult = 8;
808272cc70bSAndy Fleming 	} else {
809272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
810272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
811272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
812272cc70bSAndy Fleming 	}
813272cc70bSAndy Fleming 
814272cc70bSAndy Fleming 	mmc->capacity = (csize + 1) << (cmult + 2);
815272cc70bSAndy Fleming 	mmc->capacity *= mmc->read_bl_len;
816272cc70bSAndy Fleming 
817272cc70bSAndy Fleming 	if (mmc->read_bl_len > 512)
818272cc70bSAndy Fleming 		mmc->read_bl_len = 512;
819272cc70bSAndy Fleming 
820272cc70bSAndy Fleming 	if (mmc->write_bl_len > 512)
821272cc70bSAndy Fleming 		mmc->write_bl_len = 512;
822272cc70bSAndy Fleming 
823272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
824d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
825272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
826272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1b;
827272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
828272cc70bSAndy Fleming 		cmd.flags = 0;
829272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
830272cc70bSAndy Fleming 
831272cc70bSAndy Fleming 		if (err)
832272cc70bSAndy Fleming 			return err;
833d52ebf10SThomas Chou 	}
834272cc70bSAndy Fleming 
835d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
836d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
837d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
838d23e2c09SSukumar Ghorai 		if (!err & (ext_csd[192] >= 2)) {
839d23e2c09SSukumar Ghorai 			mmc->capacity = ext_csd[212] << 0 | ext_csd[213] << 8 |
840d23e2c09SSukumar Ghorai 					ext_csd[214] << 16 | ext_csd[215] << 24;
841d23e2c09SSukumar Ghorai 			mmc->capacity *= 512;
842d23e2c09SSukumar Ghorai 		}
843d23e2c09SSukumar Ghorai 	}
844d23e2c09SSukumar Ghorai 
845272cc70bSAndy Fleming 	if (IS_SD(mmc))
846272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
847272cc70bSAndy Fleming 	else
848272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
849272cc70bSAndy Fleming 
850272cc70bSAndy Fleming 	if (err)
851272cc70bSAndy Fleming 		return err;
852272cc70bSAndy Fleming 
853272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
854272cc70bSAndy Fleming 	mmc->card_caps &= mmc->host_caps;
855272cc70bSAndy Fleming 
856272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
857272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
858272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
859272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
860272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
861272cc70bSAndy Fleming 			cmd.flags = 0;
862272cc70bSAndy Fleming 
863272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
864272cc70bSAndy Fleming 			if (err)
865272cc70bSAndy Fleming 				return err;
866272cc70bSAndy Fleming 
867272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
868272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
869272cc70bSAndy Fleming 			cmd.cmdarg = 2;
870272cc70bSAndy Fleming 			cmd.flags = 0;
871272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
872272cc70bSAndy Fleming 			if (err)
873272cc70bSAndy Fleming 				return err;
874272cc70bSAndy Fleming 
875272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
876272cc70bSAndy Fleming 		}
877272cc70bSAndy Fleming 
878272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
879272cc70bSAndy Fleming 			mmc_set_clock(mmc, 50000000);
880272cc70bSAndy Fleming 		else
881272cc70bSAndy Fleming 			mmc_set_clock(mmc, 25000000);
882272cc70bSAndy Fleming 	} else {
883272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
884272cc70bSAndy Fleming 			/* Set the card to use 4 bit*/
885272cc70bSAndy Fleming 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
886272cc70bSAndy Fleming 					EXT_CSD_BUS_WIDTH,
887272cc70bSAndy Fleming 					EXT_CSD_BUS_WIDTH_4);
888272cc70bSAndy Fleming 
889272cc70bSAndy Fleming 			if (err)
890272cc70bSAndy Fleming 				return err;
891272cc70bSAndy Fleming 
892272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
893272cc70bSAndy Fleming 		} else if (mmc->card_caps & MMC_MODE_8BIT) {
894272cc70bSAndy Fleming 			/* Set the card to use 8 bit*/
895272cc70bSAndy Fleming 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
896272cc70bSAndy Fleming 					EXT_CSD_BUS_WIDTH,
897272cc70bSAndy Fleming 					EXT_CSD_BUS_WIDTH_8);
898272cc70bSAndy Fleming 
899272cc70bSAndy Fleming 			if (err)
900272cc70bSAndy Fleming 				return err;
901272cc70bSAndy Fleming 
902272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 8);
903272cc70bSAndy Fleming 		}
904272cc70bSAndy Fleming 
905272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS) {
906272cc70bSAndy Fleming 			if (mmc->card_caps & MMC_MODE_HS_52MHz)
907272cc70bSAndy Fleming 				mmc_set_clock(mmc, 52000000);
908272cc70bSAndy Fleming 			else
909272cc70bSAndy Fleming 				mmc_set_clock(mmc, 26000000);
910272cc70bSAndy Fleming 		} else
911272cc70bSAndy Fleming 			mmc_set_clock(mmc, 20000000);
912272cc70bSAndy Fleming 	}
913272cc70bSAndy Fleming 
914272cc70bSAndy Fleming 	/* fill in device description */
915272cc70bSAndy Fleming 	mmc->block_dev.lun = 0;
916272cc70bSAndy Fleming 	mmc->block_dev.type = 0;
917272cc70bSAndy Fleming 	mmc->block_dev.blksz = mmc->read_bl_len;
9189b1f942cSRabin Vincent 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
9190b453ffeSRabin Vincent 	sprintf(mmc->block_dev.vendor, "Man %06x Snr %08x", mmc->cid[0] >> 8,
9200b453ffeSRabin Vincent 			(mmc->cid[2] << 8) | (mmc->cid[3] >> 24));
9210b453ffeSRabin Vincent 	sprintf(mmc->block_dev.product, "%c%c%c%c%c", mmc->cid[0] & 0xff,
9220b453ffeSRabin Vincent 			(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
9230b453ffeSRabin Vincent 			(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff);
9240b453ffeSRabin Vincent 	sprintf(mmc->block_dev.revision, "%d.%d", mmc->cid[2] >> 28,
9250b453ffeSRabin Vincent 			(mmc->cid[2] >> 24) & 0xf);
926272cc70bSAndy Fleming 	init_part(&mmc->block_dev);
927272cc70bSAndy Fleming 
928272cc70bSAndy Fleming 	return 0;
929272cc70bSAndy Fleming }
930272cc70bSAndy Fleming 
931272cc70bSAndy Fleming int mmc_send_if_cond(struct mmc *mmc)
932272cc70bSAndy Fleming {
933272cc70bSAndy Fleming 	struct mmc_cmd cmd;
934272cc70bSAndy Fleming 	int err;
935272cc70bSAndy Fleming 
936272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
937272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
938272cc70bSAndy Fleming 	cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa;
939272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
940272cc70bSAndy Fleming 	cmd.flags = 0;
941272cc70bSAndy Fleming 
942272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
943272cc70bSAndy Fleming 
944272cc70bSAndy Fleming 	if (err)
945272cc70bSAndy Fleming 		return err;
946272cc70bSAndy Fleming 
947998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
948272cc70bSAndy Fleming 		return UNUSABLE_ERR;
949272cc70bSAndy Fleming 	else
950272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
951272cc70bSAndy Fleming 
952272cc70bSAndy Fleming 	return 0;
953272cc70bSAndy Fleming }
954272cc70bSAndy Fleming 
955272cc70bSAndy Fleming int mmc_register(struct mmc *mmc)
956272cc70bSAndy Fleming {
957272cc70bSAndy Fleming 	/* Setup the universal parts of the block interface just once */
958272cc70bSAndy Fleming 	mmc->block_dev.if_type = IF_TYPE_MMC;
959272cc70bSAndy Fleming 	mmc->block_dev.dev = cur_dev_num++;
960272cc70bSAndy Fleming 	mmc->block_dev.removable = 1;
961272cc70bSAndy Fleming 	mmc->block_dev.block_read = mmc_bread;
962272cc70bSAndy Fleming 	mmc->block_dev.block_write = mmc_bwrite;
963272cc70bSAndy Fleming 
964272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc->link);
965272cc70bSAndy Fleming 
966272cc70bSAndy Fleming 	list_add_tail (&mmc->link, &mmc_devices);
967272cc70bSAndy Fleming 
968272cc70bSAndy Fleming 	return 0;
969272cc70bSAndy Fleming }
970272cc70bSAndy Fleming 
971272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev)
972272cc70bSAndy Fleming {
973272cc70bSAndy Fleming 	struct mmc *mmc = find_mmc_device(dev);
974272cc70bSAndy Fleming 
975e85649c7SRabin Vincent 	return mmc ? &mmc->block_dev : NULL;
976272cc70bSAndy Fleming }
977272cc70bSAndy Fleming 
978272cc70bSAndy Fleming int mmc_init(struct mmc *mmc)
979272cc70bSAndy Fleming {
980272cc70bSAndy Fleming 	int err;
981272cc70bSAndy Fleming 
982272cc70bSAndy Fleming 	err = mmc->init(mmc);
983272cc70bSAndy Fleming 
984272cc70bSAndy Fleming 	if (err)
985272cc70bSAndy Fleming 		return err;
986272cc70bSAndy Fleming 
987b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
988b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
989b86b85e2SIlya Yanok 
990272cc70bSAndy Fleming 	/* Reset the Card */
991272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
992272cc70bSAndy Fleming 
993272cc70bSAndy Fleming 	if (err)
994272cc70bSAndy Fleming 		return err;
995272cc70bSAndy Fleming 
996272cc70bSAndy Fleming 	/* Test for SD version 2 */
997272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
998272cc70bSAndy Fleming 
999272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1000272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1001272cc70bSAndy Fleming 
1002272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1003272cc70bSAndy Fleming 	if (err == TIMEOUT) {
1004272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1005272cc70bSAndy Fleming 
1006272cc70bSAndy Fleming 		if (err) {
1007272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
1008272cc70bSAndy Fleming 			return UNUSABLE_ERR;
1009272cc70bSAndy Fleming 		}
1010272cc70bSAndy Fleming 	}
1011272cc70bSAndy Fleming 
1012272cc70bSAndy Fleming 	return mmc_startup(mmc);
1013272cc70bSAndy Fleming }
1014272cc70bSAndy Fleming 
1015272cc70bSAndy Fleming /*
1016272cc70bSAndy Fleming  * CPU and board-specific MMC initializations.  Aliased function
1017272cc70bSAndy Fleming  * signals caller to move on
1018272cc70bSAndy Fleming  */
1019272cc70bSAndy Fleming static int __def_mmc_init(bd_t *bis)
1020272cc70bSAndy Fleming {
1021272cc70bSAndy Fleming 	return -1;
1022272cc70bSAndy Fleming }
1023272cc70bSAndy Fleming 
1024f9a109b3SPeter Tyser int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
1025f9a109b3SPeter Tyser int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
1026272cc70bSAndy Fleming 
1027272cc70bSAndy Fleming void print_mmc_devices(char separator)
1028272cc70bSAndy Fleming {
1029272cc70bSAndy Fleming 	struct mmc *m;
1030272cc70bSAndy Fleming 	struct list_head *entry;
1031272cc70bSAndy Fleming 
1032272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
1033272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
1034272cc70bSAndy Fleming 
1035272cc70bSAndy Fleming 		printf("%s: %d", m->name, m->block_dev.dev);
1036272cc70bSAndy Fleming 
1037272cc70bSAndy Fleming 		if (entry->next != &mmc_devices)
1038272cc70bSAndy Fleming 			printf("%c ", separator);
1039272cc70bSAndy Fleming 	}
1040272cc70bSAndy Fleming 
1041272cc70bSAndy Fleming 	printf("\n");
1042272cc70bSAndy Fleming }
1043272cc70bSAndy Fleming 
1044272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1045272cc70bSAndy Fleming {
1046272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc_devices);
1047272cc70bSAndy Fleming 	cur_dev_num = 0;
1048272cc70bSAndy Fleming 
1049272cc70bSAndy Fleming 	if (board_mmc_init(bis) < 0)
1050272cc70bSAndy Fleming 		cpu_mmc_init(bis);
1051272cc70bSAndy Fleming 
1052272cc70bSAndy Fleming 	print_mmc_devices(',');
1053272cc70bSAndy Fleming 
1054272cc70bSAndy Fleming 	return 0;
1055272cc70bSAndy Fleming }
1056