xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 561968266431e16790e0d71086341f28e6930800)
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  *
71a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
8272cc70bSAndy Fleming  */
9272cc70bSAndy Fleming 
10272cc70bSAndy Fleming #include <config.h>
11272cc70bSAndy Fleming #include <common.h>
12272cc70bSAndy Fleming #include <command.h>
13272cc70bSAndy Fleming #include <mmc.h>
14272cc70bSAndy Fleming #include <part.h>
15272cc70bSAndy Fleming #include <malloc.h>
16272cc70bSAndy Fleming #include <linux/list.h>
179b1f942cSRabin Vincent #include <div64.h>
18272cc70bSAndy Fleming 
19ce0fbcd2SMatt Waddel /* Set block count limit because of 16 bit register limit on some hardware*/
20ce0fbcd2SMatt Waddel #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT
21ce0fbcd2SMatt Waddel #define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535
22ce0fbcd2SMatt Waddel #endif
23ce0fbcd2SMatt Waddel 
24272cc70bSAndy Fleming static struct list_head mmc_devices;
25272cc70bSAndy Fleming static int cur_dev_num = -1;
26272cc70bSAndy Fleming 
27d23d8d7eSNikita Kiryanov int __weak board_mmc_getwp(struct mmc *mmc)
28d23d8d7eSNikita Kiryanov {
29d23d8d7eSNikita Kiryanov 	return -1;
30d23d8d7eSNikita Kiryanov }
31d23d8d7eSNikita Kiryanov 
32d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
33d23d8d7eSNikita Kiryanov {
34d23d8d7eSNikita Kiryanov 	int wp;
35d23d8d7eSNikita Kiryanov 
36d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
37d23d8d7eSNikita Kiryanov 
38d4e1da4eSPeter Korsgaard 	if (wp < 0) {
39d4e1da4eSPeter Korsgaard 		if (mmc->getwp)
40d23d8d7eSNikita Kiryanov 			wp = mmc->getwp(mmc);
41d4e1da4eSPeter Korsgaard 		else
42d4e1da4eSPeter Korsgaard 			wp = 0;
43d4e1da4eSPeter Korsgaard 	}
44d23d8d7eSNikita Kiryanov 
45d23d8d7eSNikita Kiryanov 	return wp;
46d23d8d7eSNikita Kiryanov }
47d23d8d7eSNikita Kiryanov 
48314284b1SThierry Reding int __board_mmc_getcd(struct mmc *mmc) {
4911fdade2SStefano Babic 	return -1;
5011fdade2SStefano Babic }
5111fdade2SStefano Babic 
52314284b1SThierry Reding int board_mmc_getcd(struct mmc *mmc)__attribute__((weak,
5311fdade2SStefano Babic 	alias("__board_mmc_getcd")));
5411fdade2SStefano Babic 
55fdbb873eSKim Phillips static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
56fdbb873eSKim Phillips 			struct mmc_data *data)
57272cc70bSAndy Fleming {
585db2fe3aSRaffaele Recalcati 	int ret;
598635ff9eSMarek Vasut 
608635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
615db2fe3aSRaffaele Recalcati 	int i;
625db2fe3aSRaffaele Recalcati 	u8 *ptr;
635db2fe3aSRaffaele Recalcati 
645db2fe3aSRaffaele Recalcati 	printf("CMD_SEND:%d\n", cmd->cmdidx);
655db2fe3aSRaffaele Recalcati 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
665db2fe3aSRaffaele Recalcati 	ret = mmc->send_cmd(mmc, cmd, data);
675db2fe3aSRaffaele Recalcati 	switch (cmd->resp_type) {
685db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
695db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
705db2fe3aSRaffaele Recalcati 			break;
715db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
725db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
735db2fe3aSRaffaele Recalcati 				cmd->response[0]);
745db2fe3aSRaffaele Recalcati 			break;
755db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
765db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
775db2fe3aSRaffaele Recalcati 				cmd->response[0]);
785db2fe3aSRaffaele Recalcati 			break;
795db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
805db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
815db2fe3aSRaffaele Recalcati 				cmd->response[0]);
825db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
835db2fe3aSRaffaele Recalcati 				cmd->response[1]);
845db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
855db2fe3aSRaffaele Recalcati 				cmd->response[2]);
865db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
875db2fe3aSRaffaele Recalcati 				cmd->response[3]);
885db2fe3aSRaffaele Recalcati 			printf("\n");
895db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
905db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
915db2fe3aSRaffaele Recalcati 				int j;
925db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
93146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
945db2fe3aSRaffaele Recalcati 				ptr += 3;
955db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
965db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
975db2fe3aSRaffaele Recalcati 				printf("\n");
985db2fe3aSRaffaele Recalcati 			}
995db2fe3aSRaffaele Recalcati 			break;
1005db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1015db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1025db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1035db2fe3aSRaffaele Recalcati 			break;
1045db2fe3aSRaffaele Recalcati 		default:
1055db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1065db2fe3aSRaffaele Recalcati 			break;
1075db2fe3aSRaffaele Recalcati 	}
1085db2fe3aSRaffaele Recalcati #else
1098635ff9eSMarek Vasut 	ret = mmc->send_cmd(mmc, cmd, data);
1105db2fe3aSRaffaele Recalcati #endif
1118635ff9eSMarek Vasut 	return ret;
112272cc70bSAndy Fleming }
113272cc70bSAndy Fleming 
114fdbb873eSKim Phillips static int mmc_send_status(struct mmc *mmc, int timeout)
1155d4fc8d9SRaffaele Recalcati {
1165d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
117d617c426SJan Kloetzke 	int err, retries = 5;
1185d4fc8d9SRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
1195d4fc8d9SRaffaele Recalcati 	int status;
1205d4fc8d9SRaffaele Recalcati #endif
1215d4fc8d9SRaffaele Recalcati 
1225d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
1235d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
124aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
125aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
1265d4fc8d9SRaffaele Recalcati 
1275d4fc8d9SRaffaele Recalcati 	do {
1285d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
129d617c426SJan Kloetzke 		if (!err) {
130d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
131d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
132d617c426SJan Kloetzke 			     MMC_STATE_PRG)
1335d4fc8d9SRaffaele Recalcati 				break;
134d617c426SJan Kloetzke 			else if (cmd.response[0] & MMC_STATUS_MASK) {
135*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
136d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
137d617c426SJan Kloetzke 					cmd.response[0]);
138*56196826SPaul Burton #endif
139d617c426SJan Kloetzke 				return COMM_ERR;
140d617c426SJan Kloetzke 			}
141d617c426SJan Kloetzke 		} else if (--retries < 0)
142d617c426SJan Kloetzke 			return err;
1435d4fc8d9SRaffaele Recalcati 
1445d4fc8d9SRaffaele Recalcati 		udelay(1000);
1455d4fc8d9SRaffaele Recalcati 
1465d4fc8d9SRaffaele Recalcati 	} while (timeout--);
1475d4fc8d9SRaffaele Recalcati 
1485db2fe3aSRaffaele Recalcati #ifdef CONFIG_MMC_TRACE
1495db2fe3aSRaffaele Recalcati 	status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9;
1505db2fe3aSRaffaele Recalcati 	printf("CURR STATE:%d\n", status);
1515db2fe3aSRaffaele Recalcati #endif
1525b0c942fSJongman Heo 	if (timeout <= 0) {
153*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1545d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
155*56196826SPaul Burton #endif
1565d4fc8d9SRaffaele Recalcati 		return TIMEOUT;
1575d4fc8d9SRaffaele Recalcati 	}
1585d4fc8d9SRaffaele Recalcati 
1595d4fc8d9SRaffaele Recalcati 	return 0;
1605d4fc8d9SRaffaele Recalcati }
1615d4fc8d9SRaffaele Recalcati 
162fdbb873eSKim Phillips static int mmc_set_blocklen(struct mmc *mmc, int len)
163272cc70bSAndy Fleming {
164272cc70bSAndy Fleming 	struct mmc_cmd cmd;
165272cc70bSAndy Fleming 
166272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
167272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
168272cc70bSAndy Fleming 	cmd.cmdarg = len;
169272cc70bSAndy Fleming 
170272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
171272cc70bSAndy Fleming }
172272cc70bSAndy Fleming 
173272cc70bSAndy Fleming struct mmc *find_mmc_device(int dev_num)
174272cc70bSAndy Fleming {
175272cc70bSAndy Fleming 	struct mmc *m;
176272cc70bSAndy Fleming 	struct list_head *entry;
177272cc70bSAndy Fleming 
178272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
179272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
180272cc70bSAndy Fleming 
181272cc70bSAndy Fleming 		if (m->block_dev.dev == dev_num)
182272cc70bSAndy Fleming 			return m;
183272cc70bSAndy Fleming 	}
184272cc70bSAndy Fleming 
185*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
186272cc70bSAndy Fleming 	printf("MMC Device %d not found\n", dev_num);
187*56196826SPaul Burton #endif
188272cc70bSAndy Fleming 
189272cc70bSAndy Fleming 	return NULL;
190272cc70bSAndy Fleming }
191272cc70bSAndy Fleming 
192e6f99a56SLei Wen static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt)
193e6f99a56SLei Wen {
194e6f99a56SLei Wen 	struct mmc_cmd cmd;
195e6f99a56SLei Wen 	ulong end;
196e6f99a56SLei Wen 	int err, start_cmd, end_cmd;
197e6f99a56SLei Wen 
198e6f99a56SLei Wen 	if (mmc->high_capacity)
199e6f99a56SLei Wen 		end = start + blkcnt - 1;
200e6f99a56SLei Wen 	else {
201e6f99a56SLei Wen 		end = (start + blkcnt - 1) * mmc->write_bl_len;
202e6f99a56SLei Wen 		start *= mmc->write_bl_len;
203e6f99a56SLei Wen 	}
204e6f99a56SLei Wen 
205e6f99a56SLei Wen 	if (IS_SD(mmc)) {
206e6f99a56SLei Wen 		start_cmd = SD_CMD_ERASE_WR_BLK_START;
207e6f99a56SLei Wen 		end_cmd = SD_CMD_ERASE_WR_BLK_END;
208e6f99a56SLei Wen 	} else {
209e6f99a56SLei Wen 		start_cmd = MMC_CMD_ERASE_GROUP_START;
210e6f99a56SLei Wen 		end_cmd = MMC_CMD_ERASE_GROUP_END;
211e6f99a56SLei Wen 	}
212e6f99a56SLei Wen 
213e6f99a56SLei Wen 	cmd.cmdidx = start_cmd;
214e6f99a56SLei Wen 	cmd.cmdarg = start;
215e6f99a56SLei Wen 	cmd.resp_type = MMC_RSP_R1;
216e6f99a56SLei Wen 
217e6f99a56SLei Wen 	err = mmc_send_cmd(mmc, &cmd, NULL);
218e6f99a56SLei Wen 	if (err)
219e6f99a56SLei Wen 		goto err_out;
220e6f99a56SLei Wen 
221e6f99a56SLei Wen 	cmd.cmdidx = end_cmd;
222e6f99a56SLei Wen 	cmd.cmdarg = end;
223e6f99a56SLei Wen 
224e6f99a56SLei Wen 	err = mmc_send_cmd(mmc, &cmd, NULL);
225e6f99a56SLei Wen 	if (err)
226e6f99a56SLei Wen 		goto err_out;
227e6f99a56SLei Wen 
228e6f99a56SLei Wen 	cmd.cmdidx = MMC_CMD_ERASE;
229e6f99a56SLei Wen 	cmd.cmdarg = SECURE_ERASE;
230e6f99a56SLei Wen 	cmd.resp_type = MMC_RSP_R1b;
231e6f99a56SLei Wen 
232e6f99a56SLei Wen 	err = mmc_send_cmd(mmc, &cmd, NULL);
233e6f99a56SLei Wen 	if (err)
234e6f99a56SLei Wen 		goto err_out;
235e6f99a56SLei Wen 
236e6f99a56SLei Wen 	return 0;
237e6f99a56SLei Wen 
238e6f99a56SLei Wen err_out:
239*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
240e6f99a56SLei Wen 	puts("mmc erase failed\n");
241*56196826SPaul Burton #endif
242e6f99a56SLei Wen 	return err;
243e6f99a56SLei Wen }
244e6f99a56SLei Wen 
245e6f99a56SLei Wen static unsigned long
246ff8fef56SSascha Silbe mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt)
247e6f99a56SLei Wen {
248e6f99a56SLei Wen 	int err = 0;
249e6f99a56SLei Wen 	struct mmc *mmc = find_mmc_device(dev_num);
250e6f99a56SLei Wen 	lbaint_t blk = 0, blk_r = 0;
251d2d8afaeSJerry Huang 	int timeout = 1000;
252e6f99a56SLei Wen 
253e6f99a56SLei Wen 	if (!mmc)
254e6f99a56SLei Wen 		return -1;
255e6f99a56SLei Wen 
256*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
257e6f99a56SLei Wen 	if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size))
258e6f99a56SLei Wen 		printf("\n\nCaution! Your devices Erase group is 0x%x\n"
259ff8fef56SSascha Silbe 		       "The erase range would be change to "
260ff8fef56SSascha Silbe 		       "0x" LBAF "~0x" LBAF "\n\n",
261e6f99a56SLei Wen 		       mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1),
262e6f99a56SLei Wen 		       ((start + blkcnt + mmc->erase_grp_size)
263e6f99a56SLei Wen 		       & ~(mmc->erase_grp_size - 1)) - 1);
264*56196826SPaul Burton #endif
265e6f99a56SLei Wen 
266e6f99a56SLei Wen 	while (blk < blkcnt) {
267e6f99a56SLei Wen 		blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
268e6f99a56SLei Wen 			mmc->erase_grp_size : (blkcnt - blk);
269e6f99a56SLei Wen 		err = mmc_erase_t(mmc, start + blk, blk_r);
270e6f99a56SLei Wen 		if (err)
271e6f99a56SLei Wen 			break;
272e6f99a56SLei Wen 
273e6f99a56SLei Wen 		blk += blk_r;
274d2d8afaeSJerry Huang 
275d2d8afaeSJerry Huang 		/* Waiting for the ready status */
276d2d8afaeSJerry Huang 		if (mmc_send_status(mmc, timeout))
277d2d8afaeSJerry Huang 			return 0;
278e6f99a56SLei Wen 	}
279e6f99a56SLei Wen 
280e6f99a56SLei Wen 	return blk;
281e6f99a56SLei Wen }
282e6f99a56SLei Wen 
283272cc70bSAndy Fleming static ulong
284ff8fef56SSascha Silbe mmc_write_blocks(struct mmc *mmc, lbaint_t start, lbaint_t blkcnt, const void*src)
285272cc70bSAndy Fleming {
286272cc70bSAndy Fleming 	struct mmc_cmd cmd;
287272cc70bSAndy Fleming 	struct mmc_data data;
2885d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
289272cc70bSAndy Fleming 
290d2bf29e3SLei Wen 	if ((start + blkcnt) > mmc->block_dev.lba) {
291*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
292ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
293d2bf29e3SLei Wen 			start + blkcnt, mmc->block_dev.lba);
294*56196826SPaul Burton #endif
295d2bf29e3SLei Wen 		return 0;
296d2bf29e3SLei Wen 	}
297272cc70bSAndy Fleming 
298a586c0aaSRuud Commandeur 	if (blkcnt == 0)
299a586c0aaSRuud Commandeur 		return 0;
300a586c0aaSRuud Commandeur 	else if (blkcnt == 1)
301272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
302a586c0aaSRuud Commandeur 	else
303a586c0aaSRuud Commandeur 		cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
304272cc70bSAndy Fleming 
305272cc70bSAndy Fleming 	if (mmc->high_capacity)
306272cc70bSAndy Fleming 		cmd.cmdarg = start;
307272cc70bSAndy Fleming 	else
308def412b6SSteve Sakoman 		cmd.cmdarg = start * mmc->write_bl_len;
309272cc70bSAndy Fleming 
310272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
311272cc70bSAndy Fleming 
312272cc70bSAndy Fleming 	data.src = src;
313272cc70bSAndy Fleming 	data.blocks = blkcnt;
314def412b6SSteve Sakoman 	data.blocksize = mmc->write_bl_len;
315272cc70bSAndy Fleming 	data.flags = MMC_DATA_WRITE;
316272cc70bSAndy Fleming 
317def412b6SSteve Sakoman 	if (mmc_send_cmd(mmc, &cmd, &data)) {
318*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
319def412b6SSteve Sakoman 		printf("mmc write failed\n");
320*56196826SPaul Burton #endif
321def412b6SSteve Sakoman 		return 0;
322272cc70bSAndy Fleming 	}
323272cc70bSAndy Fleming 
324d52ebf10SThomas Chou 	/* SPI multiblock writes terminate using a special
325d52ebf10SThomas Chou 	 * token, not a STOP_TRANSMISSION request.
326d52ebf10SThomas Chou 	 */
327d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc) && blkcnt > 1) {
328272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
329272cc70bSAndy Fleming 		cmd.cmdarg = 0;
330272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1b;
331def412b6SSteve Sakoman 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
332*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
333def412b6SSteve Sakoman 			printf("mmc fail to send stop cmd\n");
334*56196826SPaul Burton #endif
335def412b6SSteve Sakoman 			return 0;
336272cc70bSAndy Fleming 		}
33793ad0d18SJan Kloetzke 	}
3385d4fc8d9SRaffaele Recalcati 
3395d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
34093ad0d18SJan Kloetzke 	if (mmc_send_status(mmc, timeout))
34193ad0d18SJan Kloetzke 		return 0;
3420158126eSLei Wen 
3430158126eSLei Wen 	return blkcnt;
3440158126eSLei Wen }
3450158126eSLei Wen 
3460158126eSLei Wen static ulong
347ff8fef56SSascha Silbe mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void*src)
3480158126eSLei Wen {
3490158126eSLei Wen 	lbaint_t cur, blocks_todo = blkcnt;
3500158126eSLei Wen 
351def412b6SSteve Sakoman 	struct mmc *mmc = find_mmc_device(dev_num);
3520158126eSLei Wen 	if (!mmc)
353def412b6SSteve Sakoman 		return 0;
3540158126eSLei Wen 
355def412b6SSteve Sakoman 	if (mmc_set_blocklen(mmc, mmc->write_bl_len))
356def412b6SSteve Sakoman 		return 0;
3570158126eSLei Wen 
3580158126eSLei Wen 	do {
3598feafcc4SJohn Rigby 		cur = (blocks_todo > mmc->b_max) ?  mmc->b_max : blocks_todo;
3600158126eSLei Wen 		if(mmc_write_blocks(mmc, start, cur, src) != cur)
361def412b6SSteve Sakoman 			return 0;
3620158126eSLei Wen 		blocks_todo -= cur;
3630158126eSLei Wen 		start += cur;
3640158126eSLei Wen 		src += cur * mmc->write_bl_len;
3650158126eSLei Wen 	} while (blocks_todo > 0);
366272cc70bSAndy Fleming 
367272cc70bSAndy Fleming 	return blkcnt;
368272cc70bSAndy Fleming }
369272cc70bSAndy Fleming 
370ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
371fdbb873eSKim Phillips 			   lbaint_t blkcnt)
372272cc70bSAndy Fleming {
373272cc70bSAndy Fleming 	struct mmc_cmd cmd;
374272cc70bSAndy Fleming 	struct mmc_data data;
375272cc70bSAndy Fleming 
3764a1a06bcSAlagu Sankar 	if (blkcnt > 1)
3774a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
3784a1a06bcSAlagu Sankar 	else
379272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
380272cc70bSAndy Fleming 
381272cc70bSAndy Fleming 	if (mmc->high_capacity)
3824a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
383272cc70bSAndy Fleming 	else
3844a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
385272cc70bSAndy Fleming 
386272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
387272cc70bSAndy Fleming 
388272cc70bSAndy Fleming 	data.dest = dst;
3894a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
390272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
391272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
392272cc70bSAndy Fleming 
3934a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
3944a1a06bcSAlagu Sankar 		return 0;
3954a1a06bcSAlagu Sankar 
3964a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
3974a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
3984a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
3994a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
4004a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
401*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
4024a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
403*56196826SPaul Burton #endif
4044a1a06bcSAlagu Sankar 			return 0;
4054a1a06bcSAlagu Sankar 		}
406272cc70bSAndy Fleming 	}
407272cc70bSAndy Fleming 
4084a1a06bcSAlagu Sankar 	return blkcnt;
409272cc70bSAndy Fleming }
410272cc70bSAndy Fleming 
411ff8fef56SSascha Silbe static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst)
412272cc70bSAndy Fleming {
4134a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
414272cc70bSAndy Fleming 
4154a1a06bcSAlagu Sankar 	if (blkcnt == 0)
4164a1a06bcSAlagu Sankar 		return 0;
4174a1a06bcSAlagu Sankar 
4184a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
419272cc70bSAndy Fleming 	if (!mmc)
420272cc70bSAndy Fleming 		return 0;
421272cc70bSAndy Fleming 
422d2bf29e3SLei Wen 	if ((start + blkcnt) > mmc->block_dev.lba) {
423*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
424ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
425d2bf29e3SLei Wen 			start + blkcnt, mmc->block_dev.lba);
426*56196826SPaul Burton #endif
427d2bf29e3SLei Wen 		return 0;
428d2bf29e3SLei Wen 	}
429272cc70bSAndy Fleming 
4304a1a06bcSAlagu Sankar 	if (mmc_set_blocklen(mmc, mmc->read_bl_len))
431272cc70bSAndy Fleming 		return 0;
432272cc70bSAndy Fleming 
4334a1a06bcSAlagu Sankar 	do {
4348feafcc4SJohn Rigby 		cur = (blocks_todo > mmc->b_max) ?  mmc->b_max : blocks_todo;
4354a1a06bcSAlagu Sankar 		if(mmc_read_blocks(mmc, dst, start, cur) != cur)
4364a1a06bcSAlagu Sankar 			return 0;
4374a1a06bcSAlagu Sankar 		blocks_todo -= cur;
4384a1a06bcSAlagu Sankar 		start += cur;
4394a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
4404a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
441272cc70bSAndy Fleming 
442272cc70bSAndy Fleming 	return blkcnt;
443272cc70bSAndy Fleming }
444272cc70bSAndy Fleming 
445fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
446272cc70bSAndy Fleming {
447272cc70bSAndy Fleming 	struct mmc_cmd cmd;
448272cc70bSAndy Fleming 	int err;
449272cc70bSAndy Fleming 
450272cc70bSAndy Fleming 	udelay(1000);
451272cc70bSAndy Fleming 
452272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
453272cc70bSAndy Fleming 	cmd.cmdarg = 0;
454272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
455272cc70bSAndy Fleming 
456272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
457272cc70bSAndy Fleming 
458272cc70bSAndy Fleming 	if (err)
459272cc70bSAndy Fleming 		return err;
460272cc70bSAndy Fleming 
461272cc70bSAndy Fleming 	udelay(2000);
462272cc70bSAndy Fleming 
463272cc70bSAndy Fleming 	return 0;
464272cc70bSAndy Fleming }
465272cc70bSAndy Fleming 
466fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
467272cc70bSAndy Fleming {
468272cc70bSAndy Fleming 	int timeout = 1000;
469272cc70bSAndy Fleming 	int err;
470272cc70bSAndy Fleming 	struct mmc_cmd cmd;
471272cc70bSAndy Fleming 
472272cc70bSAndy Fleming 	do {
473272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
474272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
475272cc70bSAndy Fleming 		cmd.cmdarg = 0;
476272cc70bSAndy Fleming 
477272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
478272cc70bSAndy Fleming 
479272cc70bSAndy Fleming 		if (err)
480272cc70bSAndy Fleming 			return err;
481272cc70bSAndy Fleming 
482272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
483272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
484250de12bSStefano Babic 
485250de12bSStefano Babic 		/*
486250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
487250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
488250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
489250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
490250de12bSStefano Babic 		 * specified.
491250de12bSStefano Babic 		 */
492d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
493d52ebf10SThomas Chou 			(mmc->voltages & 0xff8000);
494272cc70bSAndy Fleming 
495272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
496272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
497272cc70bSAndy Fleming 
498272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
499272cc70bSAndy Fleming 
500272cc70bSAndy Fleming 		if (err)
501272cc70bSAndy Fleming 			return err;
502272cc70bSAndy Fleming 
503272cc70bSAndy Fleming 		udelay(1000);
504272cc70bSAndy Fleming 	} while ((!(cmd.response[0] & OCR_BUSY)) && timeout--);
505272cc70bSAndy Fleming 
506272cc70bSAndy Fleming 	if (timeout <= 0)
507272cc70bSAndy Fleming 		return UNUSABLE_ERR;
508272cc70bSAndy Fleming 
509272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
510272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
511272cc70bSAndy Fleming 
512d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
513d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
514d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
515d52ebf10SThomas Chou 		cmd.cmdarg = 0;
516d52ebf10SThomas Chou 
517d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
518d52ebf10SThomas Chou 
519d52ebf10SThomas Chou 		if (err)
520d52ebf10SThomas Chou 			return err;
521d52ebf10SThomas Chou 	}
522d52ebf10SThomas Chou 
523998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
524272cc70bSAndy Fleming 
525272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
526272cc70bSAndy Fleming 	mmc->rca = 0;
527272cc70bSAndy Fleming 
528272cc70bSAndy Fleming 	return 0;
529272cc70bSAndy Fleming }
530272cc70bSAndy Fleming 
531e9550449SChe-Liang Chiou /* We pass in the cmd since otherwise the init seems to fail */
532e9550449SChe-Liang Chiou static int mmc_send_op_cond_iter(struct mmc *mmc, struct mmc_cmd *cmd,
533e9550449SChe-Liang Chiou 		int use_arg)
534272cc70bSAndy Fleming {
535272cc70bSAndy Fleming 	int err;
536272cc70bSAndy Fleming 
537e9550449SChe-Liang Chiou 	cmd->cmdidx = MMC_CMD_SEND_OP_COND;
538e9550449SChe-Liang Chiou 	cmd->resp_type = MMC_RSP_R3;
539e9550449SChe-Liang Chiou 	cmd->cmdarg = 0;
540e9550449SChe-Liang Chiou 	if (use_arg && !mmc_host_is_spi(mmc)) {
541e9550449SChe-Liang Chiou 		cmd->cmdarg =
542e9550449SChe-Liang Chiou 			(mmc->voltages &
543e9550449SChe-Liang Chiou 			(mmc->op_cond_response & OCR_VOLTAGE_MASK)) |
544e9550449SChe-Liang Chiou 			(mmc->op_cond_response & OCR_ACCESS_MODE);
545e9550449SChe-Liang Chiou 
546e9550449SChe-Liang Chiou 		if (mmc->host_caps & MMC_MODE_HC)
547e9550449SChe-Liang Chiou 			cmd->cmdarg |= OCR_HCS;
548e9550449SChe-Liang Chiou 	}
549e9550449SChe-Liang Chiou 	err = mmc_send_cmd(mmc, cmd, NULL);
550e9550449SChe-Liang Chiou 	if (err)
551e9550449SChe-Liang Chiou 		return err;
552e9550449SChe-Liang Chiou 	mmc->op_cond_response = cmd->response[0];
553e9550449SChe-Liang Chiou 	return 0;
554e9550449SChe-Liang Chiou }
555e9550449SChe-Liang Chiou 
556e9550449SChe-Liang Chiou int mmc_send_op_cond(struct mmc *mmc)
557e9550449SChe-Liang Chiou {
558e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
559e9550449SChe-Liang Chiou 	int err, i;
560e9550449SChe-Liang Chiou 
561272cc70bSAndy Fleming 	/* Some cards seem to need this */
562272cc70bSAndy Fleming 	mmc_go_idle(mmc);
563272cc70bSAndy Fleming 
56431cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
565e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 1;
566e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
567e9550449SChe-Liang Chiou 		err = mmc_send_op_cond_iter(mmc, &cmd, i != 0);
56831cacbabSRaffaele Recalcati 		if (err)
56931cacbabSRaffaele Recalcati 			return err;
57031cacbabSRaffaele Recalcati 
571e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
572e9550449SChe-Liang Chiou 		if (mmc->op_cond_response & OCR_BUSY)
573e9550449SChe-Liang Chiou 			return 0;
574e9550449SChe-Liang Chiou 	}
575e9550449SChe-Liang Chiou 	return IN_PROGRESS;
576e9550449SChe-Liang Chiou }
57731cacbabSRaffaele Recalcati 
578e9550449SChe-Liang Chiou int mmc_complete_op_cond(struct mmc *mmc)
579e9550449SChe-Liang Chiou {
580e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
581e9550449SChe-Liang Chiou 	int timeout = 1000;
582e9550449SChe-Liang Chiou 	uint start;
583e9550449SChe-Liang Chiou 	int err;
584e9550449SChe-Liang Chiou 
585e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
586e9550449SChe-Liang Chiou 	start = get_timer(0);
587272cc70bSAndy Fleming 	do {
588e9550449SChe-Liang Chiou 		err = mmc_send_op_cond_iter(mmc, &cmd, 1);
589272cc70bSAndy Fleming 		if (err)
590272cc70bSAndy Fleming 			return err;
591e9550449SChe-Liang Chiou 		if (get_timer(start) > timeout)
592272cc70bSAndy Fleming 			return UNUSABLE_ERR;
593e9550449SChe-Liang Chiou 		udelay(100);
594e9550449SChe-Liang Chiou 	} while (!(mmc->op_cond_response & OCR_BUSY));
595272cc70bSAndy Fleming 
596d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
597d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
598d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
599d52ebf10SThomas Chou 		cmd.cmdarg = 0;
600d52ebf10SThomas Chou 
601d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
602d52ebf10SThomas Chou 
603d52ebf10SThomas Chou 		if (err)
604d52ebf10SThomas Chou 			return err;
605d52ebf10SThomas Chou 	}
606d52ebf10SThomas Chou 
607272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
608998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
609272cc70bSAndy Fleming 
610272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
611272cc70bSAndy Fleming 	mmc->rca = 0;
612272cc70bSAndy Fleming 
613272cc70bSAndy Fleming 	return 0;
614272cc70bSAndy Fleming }
615272cc70bSAndy Fleming 
616272cc70bSAndy Fleming 
617fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
618272cc70bSAndy Fleming {
619272cc70bSAndy Fleming 	struct mmc_cmd cmd;
620272cc70bSAndy Fleming 	struct mmc_data data;
621272cc70bSAndy Fleming 	int err;
622272cc70bSAndy Fleming 
623272cc70bSAndy Fleming 	/* Get the Card Status Register */
624272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
625272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
626272cc70bSAndy Fleming 	cmd.cmdarg = 0;
627272cc70bSAndy Fleming 
628cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
629272cc70bSAndy Fleming 	data.blocks = 1;
6308bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
631272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
632272cc70bSAndy Fleming 
633272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
634272cc70bSAndy Fleming 
635272cc70bSAndy Fleming 	return err;
636272cc70bSAndy Fleming }
637272cc70bSAndy Fleming 
638272cc70bSAndy Fleming 
639fdbb873eSKim Phillips static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
640272cc70bSAndy Fleming {
641272cc70bSAndy Fleming 	struct mmc_cmd cmd;
6425d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
6435d4fc8d9SRaffaele Recalcati 	int ret;
644272cc70bSAndy Fleming 
645272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
646272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
647272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
648272cc70bSAndy Fleming 				 (index << 16) |
649272cc70bSAndy Fleming 				 (value << 8);
650272cc70bSAndy Fleming 
6515d4fc8d9SRaffaele Recalcati 	ret = mmc_send_cmd(mmc, &cmd, NULL);
6525d4fc8d9SRaffaele Recalcati 
6535d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
65493ad0d18SJan Kloetzke 	if (!ret)
65593ad0d18SJan Kloetzke 		ret = mmc_send_status(mmc, timeout);
6565d4fc8d9SRaffaele Recalcati 
6575d4fc8d9SRaffaele Recalcati 	return ret;
6585d4fc8d9SRaffaele Recalcati 
659272cc70bSAndy Fleming }
660272cc70bSAndy Fleming 
661fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
662272cc70bSAndy Fleming {
6638bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
664272cc70bSAndy Fleming 	char cardtype;
665272cc70bSAndy Fleming 	int err;
666272cc70bSAndy Fleming 
667272cc70bSAndy Fleming 	mmc->card_caps = 0;
668272cc70bSAndy Fleming 
669d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
670d52ebf10SThomas Chou 		return 0;
671d52ebf10SThomas Chou 
672272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
673272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
674272cc70bSAndy Fleming 		return 0;
675272cc70bSAndy Fleming 
676272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
677272cc70bSAndy Fleming 
678272cc70bSAndy Fleming 	if (err)
679272cc70bSAndy Fleming 		return err;
680272cc70bSAndy Fleming 
6810560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
682272cc70bSAndy Fleming 
683272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
684272cc70bSAndy Fleming 
685272cc70bSAndy Fleming 	if (err)
686272cc70bSAndy Fleming 		return err;
687272cc70bSAndy Fleming 
688272cc70bSAndy Fleming 	/* Now check to see that it worked */
689272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
690272cc70bSAndy Fleming 
691272cc70bSAndy Fleming 	if (err)
692272cc70bSAndy Fleming 		return err;
693272cc70bSAndy Fleming 
694272cc70bSAndy Fleming 	/* No high-speed support */
6950560db18SLei Wen 	if (!ext_csd[EXT_CSD_HS_TIMING])
696272cc70bSAndy Fleming 		return 0;
697272cc70bSAndy Fleming 
698272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
699272cc70bSAndy Fleming 	if (cardtype & MMC_HS_52MHZ)
700272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
701272cc70bSAndy Fleming 	else
702272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
703272cc70bSAndy Fleming 
704272cc70bSAndy Fleming 	return 0;
705272cc70bSAndy Fleming }
706272cc70bSAndy Fleming 
707f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
708f866a46dSStephen Warren {
709f866a46dSStephen Warren 	switch (part_num) {
710f866a46dSStephen Warren 	case 0:
711f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
712f866a46dSStephen Warren 		break;
713f866a46dSStephen Warren 	case 1:
714f866a46dSStephen Warren 	case 2:
715f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
716f866a46dSStephen Warren 		break;
717f866a46dSStephen Warren 	case 3:
718f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
719f866a46dSStephen Warren 		break;
720f866a46dSStephen Warren 	case 4:
721f866a46dSStephen Warren 	case 5:
722f866a46dSStephen Warren 	case 6:
723f866a46dSStephen Warren 	case 7:
724f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
725f866a46dSStephen Warren 		break;
726f866a46dSStephen Warren 	default:
727f866a46dSStephen Warren 		return -1;
728f866a46dSStephen Warren 	}
729f866a46dSStephen Warren 
730f866a46dSStephen Warren 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
731f866a46dSStephen Warren 
732f866a46dSStephen Warren 	return 0;
733f866a46dSStephen Warren }
734f866a46dSStephen Warren 
735bc897b1dSLei Wen int mmc_switch_part(int dev_num, unsigned int part_num)
736bc897b1dSLei Wen {
737bc897b1dSLei Wen 	struct mmc *mmc = find_mmc_device(dev_num);
738f866a46dSStephen Warren 	int ret;
739bc897b1dSLei Wen 
740bc897b1dSLei Wen 	if (!mmc)
741bc897b1dSLei Wen 		return -1;
742bc897b1dSLei Wen 
743f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
744bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
745bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
746f866a46dSStephen Warren 	if (ret)
747f866a46dSStephen Warren 		return ret;
748f866a46dSStephen Warren 
749f866a46dSStephen Warren 	return mmc_set_capacity(mmc, part_num);
750bc897b1dSLei Wen }
751bc897b1dSLei Wen 
75248972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
75348972d90SThierry Reding {
75448972d90SThierry Reding 	int cd;
75548972d90SThierry Reding 
75648972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
75748972d90SThierry Reding 
758d4e1da4eSPeter Korsgaard 	if (cd < 0) {
759d4e1da4eSPeter Korsgaard 		if (mmc->getcd)
76048972d90SThierry Reding 			cd = mmc->getcd(mmc);
761d4e1da4eSPeter Korsgaard 		else
762d4e1da4eSPeter Korsgaard 			cd = 1;
763d4e1da4eSPeter Korsgaard 	}
76448972d90SThierry Reding 
76548972d90SThierry Reding 	return cd;
76648972d90SThierry Reding }
76748972d90SThierry Reding 
768fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
769272cc70bSAndy Fleming {
770272cc70bSAndy Fleming 	struct mmc_cmd cmd;
771272cc70bSAndy Fleming 	struct mmc_data data;
772272cc70bSAndy Fleming 
773272cc70bSAndy Fleming 	/* Switch the frequency */
774272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
775272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
776272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
777272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
778272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
779272cc70bSAndy Fleming 
780272cc70bSAndy Fleming 	data.dest = (char *)resp;
781272cc70bSAndy Fleming 	data.blocksize = 64;
782272cc70bSAndy Fleming 	data.blocks = 1;
783272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
784272cc70bSAndy Fleming 
785272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
786272cc70bSAndy Fleming }
787272cc70bSAndy Fleming 
788272cc70bSAndy Fleming 
789fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
790272cc70bSAndy Fleming {
791272cc70bSAndy Fleming 	int err;
792272cc70bSAndy Fleming 	struct mmc_cmd cmd;
793f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
794f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
795272cc70bSAndy Fleming 	struct mmc_data data;
796272cc70bSAndy Fleming 	int timeout;
797272cc70bSAndy Fleming 
798272cc70bSAndy Fleming 	mmc->card_caps = 0;
799272cc70bSAndy Fleming 
800d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
801d52ebf10SThomas Chou 		return 0;
802d52ebf10SThomas Chou 
803272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
804272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
805272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
806272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
807272cc70bSAndy Fleming 
808272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
809272cc70bSAndy Fleming 
810272cc70bSAndy Fleming 	if (err)
811272cc70bSAndy Fleming 		return err;
812272cc70bSAndy Fleming 
813272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
814272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
815272cc70bSAndy Fleming 	cmd.cmdarg = 0;
816272cc70bSAndy Fleming 
817272cc70bSAndy Fleming 	timeout = 3;
818272cc70bSAndy Fleming 
819272cc70bSAndy Fleming retry_scr:
820f781dd38SAnton staaf 	data.dest = (char *)scr;
821272cc70bSAndy Fleming 	data.blocksize = 8;
822272cc70bSAndy Fleming 	data.blocks = 1;
823272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
824272cc70bSAndy Fleming 
825272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
826272cc70bSAndy Fleming 
827272cc70bSAndy Fleming 	if (err) {
828272cc70bSAndy Fleming 		if (timeout--)
829272cc70bSAndy Fleming 			goto retry_scr;
830272cc70bSAndy Fleming 
831272cc70bSAndy Fleming 		return err;
832272cc70bSAndy Fleming 	}
833272cc70bSAndy Fleming 
8344e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
8354e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
836272cc70bSAndy Fleming 
837272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
838272cc70bSAndy Fleming 		case 0:
839272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
840272cc70bSAndy Fleming 			break;
841272cc70bSAndy Fleming 		case 1:
842272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_10;
843272cc70bSAndy Fleming 			break;
844272cc70bSAndy Fleming 		case 2:
845272cc70bSAndy Fleming 			mmc->version = SD_VERSION_2;
8461741c64dSJaehoon Chung 			if ((mmc->scr[0] >> 15) & 0x1)
8471741c64dSJaehoon Chung 				mmc->version = SD_VERSION_3;
848272cc70bSAndy Fleming 			break;
849272cc70bSAndy Fleming 		default:
850272cc70bSAndy Fleming 			mmc->version = SD_VERSION_1_0;
851272cc70bSAndy Fleming 			break;
852272cc70bSAndy Fleming 	}
853272cc70bSAndy Fleming 
854b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
855b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
856b44c7083SAlagu Sankar 
857272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
858272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
859272cc70bSAndy Fleming 		return 0;
860272cc70bSAndy Fleming 
861272cc70bSAndy Fleming 	timeout = 4;
862272cc70bSAndy Fleming 	while (timeout--) {
863272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
864f781dd38SAnton staaf 				(u8 *)switch_status);
865272cc70bSAndy Fleming 
866272cc70bSAndy Fleming 		if (err)
867272cc70bSAndy Fleming 			return err;
868272cc70bSAndy Fleming 
869272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
8704e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
871272cc70bSAndy Fleming 			break;
872272cc70bSAndy Fleming 	}
873272cc70bSAndy Fleming 
874272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
8754e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
876272cc70bSAndy Fleming 		return 0;
877272cc70bSAndy Fleming 
8782c3fbf4cSMacpaul Lin 	/*
8792c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
8802c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
8812c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
8822c3fbf4cSMacpaul Lin 	 * mode between the host.
8832c3fbf4cSMacpaul Lin 	 */
8842c3fbf4cSMacpaul Lin 	if (!((mmc->host_caps & MMC_MODE_HS_52MHz) &&
8852c3fbf4cSMacpaul Lin 		(mmc->host_caps & MMC_MODE_HS)))
8862c3fbf4cSMacpaul Lin 		return 0;
8872c3fbf4cSMacpaul Lin 
888f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
889272cc70bSAndy Fleming 
890272cc70bSAndy Fleming 	if (err)
891272cc70bSAndy Fleming 		return err;
892272cc70bSAndy Fleming 
8934e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
894272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
895272cc70bSAndy Fleming 
896272cc70bSAndy Fleming 	return 0;
897272cc70bSAndy Fleming }
898272cc70bSAndy Fleming 
899272cc70bSAndy Fleming /* frequency bases */
900272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
9015f837c2cSMike Frysinger static const int fbase[] = {
902272cc70bSAndy Fleming 	10000,
903272cc70bSAndy Fleming 	100000,
904272cc70bSAndy Fleming 	1000000,
905272cc70bSAndy Fleming 	10000000,
906272cc70bSAndy Fleming };
907272cc70bSAndy Fleming 
908272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
909272cc70bSAndy Fleming  * to platforms without floating point.
910272cc70bSAndy Fleming  */
9115f837c2cSMike Frysinger static const int multipliers[] = {
912272cc70bSAndy Fleming 	0,	/* reserved */
913272cc70bSAndy Fleming 	10,
914272cc70bSAndy Fleming 	12,
915272cc70bSAndy Fleming 	13,
916272cc70bSAndy Fleming 	15,
917272cc70bSAndy Fleming 	20,
918272cc70bSAndy Fleming 	25,
919272cc70bSAndy Fleming 	30,
920272cc70bSAndy Fleming 	35,
921272cc70bSAndy Fleming 	40,
922272cc70bSAndy Fleming 	45,
923272cc70bSAndy Fleming 	50,
924272cc70bSAndy Fleming 	55,
925272cc70bSAndy Fleming 	60,
926272cc70bSAndy Fleming 	70,
927272cc70bSAndy Fleming 	80,
928272cc70bSAndy Fleming };
929272cc70bSAndy Fleming 
930fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
931272cc70bSAndy Fleming {
932272cc70bSAndy Fleming 	mmc->set_ios(mmc);
933272cc70bSAndy Fleming }
934272cc70bSAndy Fleming 
935272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
936272cc70bSAndy Fleming {
937272cc70bSAndy Fleming 	if (clock > mmc->f_max)
938272cc70bSAndy Fleming 		clock = mmc->f_max;
939272cc70bSAndy Fleming 
940272cc70bSAndy Fleming 	if (clock < mmc->f_min)
941272cc70bSAndy Fleming 		clock = mmc->f_min;
942272cc70bSAndy Fleming 
943272cc70bSAndy Fleming 	mmc->clock = clock;
944272cc70bSAndy Fleming 
945272cc70bSAndy Fleming 	mmc_set_ios(mmc);
946272cc70bSAndy Fleming }
947272cc70bSAndy Fleming 
948fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width)
949272cc70bSAndy Fleming {
950272cc70bSAndy Fleming 	mmc->bus_width = width;
951272cc70bSAndy Fleming 
952272cc70bSAndy Fleming 	mmc_set_ios(mmc);
953272cc70bSAndy Fleming }
954272cc70bSAndy Fleming 
955fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
956272cc70bSAndy Fleming {
957f866a46dSStephen Warren 	int err, i;
958272cc70bSAndy Fleming 	uint mult, freq;
959639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
960272cc70bSAndy Fleming 	struct mmc_cmd cmd;
9618bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
9628bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
9635d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
964272cc70bSAndy Fleming 
965d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
966d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
967d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
968d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
969d52ebf10SThomas Chou 		cmd.cmdarg = 1;
970d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
971d52ebf10SThomas Chou 
972d52ebf10SThomas Chou 		if (err)
973d52ebf10SThomas Chou 			return err;
974d52ebf10SThomas Chou 	}
975d52ebf10SThomas Chou #endif
976d52ebf10SThomas Chou 
977272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
978d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
979d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
980272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
981272cc70bSAndy Fleming 	cmd.cmdarg = 0;
982272cc70bSAndy Fleming 
983272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
984272cc70bSAndy Fleming 
985272cc70bSAndy Fleming 	if (err)
986272cc70bSAndy Fleming 		return err;
987272cc70bSAndy Fleming 
988272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
989272cc70bSAndy Fleming 
990272cc70bSAndy Fleming 	/*
991272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
992272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
993272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
994272cc70bSAndy Fleming 	 */
995d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
996272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
997272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
998272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
999272cc70bSAndy Fleming 
1000272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1001272cc70bSAndy Fleming 
1002272cc70bSAndy Fleming 		if (err)
1003272cc70bSAndy Fleming 			return err;
1004272cc70bSAndy Fleming 
1005272cc70bSAndy Fleming 		if (IS_SD(mmc))
1006998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1007d52ebf10SThomas Chou 	}
1008272cc70bSAndy Fleming 
1009272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1010272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1011272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1012272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1013272cc70bSAndy Fleming 
1014272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1015272cc70bSAndy Fleming 
10165d4fc8d9SRaffaele Recalcati 	/* Waiting for the ready status */
10175d4fc8d9SRaffaele Recalcati 	mmc_send_status(mmc, timeout);
10185d4fc8d9SRaffaele Recalcati 
1019272cc70bSAndy Fleming 	if (err)
1020272cc70bSAndy Fleming 		return err;
1021272cc70bSAndy Fleming 
1022998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1023998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1024998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1025998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1026272cc70bSAndy Fleming 
1027272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
10280b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1029272cc70bSAndy Fleming 
1030272cc70bSAndy Fleming 		switch (version) {
1031272cc70bSAndy Fleming 			case 0:
1032272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
1033272cc70bSAndy Fleming 				break;
1034272cc70bSAndy Fleming 			case 1:
1035272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_4;
1036272cc70bSAndy Fleming 				break;
1037272cc70bSAndy Fleming 			case 2:
1038272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_2_2;
1039272cc70bSAndy Fleming 				break;
1040272cc70bSAndy Fleming 			case 3:
1041272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_3;
1042272cc70bSAndy Fleming 				break;
1043272cc70bSAndy Fleming 			case 4:
1044272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_4;
1045272cc70bSAndy Fleming 				break;
1046272cc70bSAndy Fleming 			default:
1047272cc70bSAndy Fleming 				mmc->version = MMC_VERSION_1_2;
1048272cc70bSAndy Fleming 				break;
1049272cc70bSAndy Fleming 		}
1050272cc70bSAndy Fleming 	}
1051272cc70bSAndy Fleming 
1052272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
10530b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
10540b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1055272cc70bSAndy Fleming 
1056272cc70bSAndy Fleming 	mmc->tran_speed = freq * mult;
1057272cc70bSAndy Fleming 
1058998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1059272cc70bSAndy Fleming 
1060272cc70bSAndy Fleming 	if (IS_SD(mmc))
1061272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1062272cc70bSAndy Fleming 	else
1063998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1064272cc70bSAndy Fleming 
1065272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1066272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1067272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1068272cc70bSAndy Fleming 		cmult = 8;
1069272cc70bSAndy Fleming 	} else {
1070272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1071272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1072272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1073272cc70bSAndy Fleming 	}
1074272cc70bSAndy Fleming 
1075f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1076f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1077f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1078f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1079f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1080f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1081272cc70bSAndy Fleming 
10828bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
10838bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1084272cc70bSAndy Fleming 
10858bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
10868bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1087272cc70bSAndy Fleming 
1088272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1089d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1090272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1091fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1092272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1093272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1094272cc70bSAndy Fleming 
1095272cc70bSAndy Fleming 		if (err)
1096272cc70bSAndy Fleming 			return err;
1097d52ebf10SThomas Chou 	}
1098272cc70bSAndy Fleming 
1099e6f99a56SLei Wen 	/*
1100e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1101e6f99a56SLei Wen 	 */
1102e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1103bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1104d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
1105d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
1106d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
1107fdbb873eSKim Phillips 		if (!err && (ext_csd[EXT_CSD_REV] >= 2)) {
1108639b7827SYoshihiro Shimoda 			/*
1109639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
1110639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
1111639b7827SYoshihiro Shimoda 			 * than 2GB
1112639b7827SYoshihiro Shimoda 			 */
11130560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
11140560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
11150560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
11160560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
11178bfa195eSSimon Glass 			capacity *= MMC_MAX_BLOCK_LEN;
1118b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
1119f866a46dSStephen Warren 				mmc->capacity_user = capacity;
1120d23e2c09SSukumar Ghorai 		}
1121bc897b1dSLei Wen 
112264f4a619SJaehoon Chung 		switch (ext_csd[EXT_CSD_REV]) {
112364f4a619SJaehoon Chung 		case 1:
112464f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_1;
112564f4a619SJaehoon Chung 			break;
112664f4a619SJaehoon Chung 		case 2:
112764f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_2;
112864f4a619SJaehoon Chung 			break;
112964f4a619SJaehoon Chung 		case 3:
113064f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_3;
113164f4a619SJaehoon Chung 			break;
113264f4a619SJaehoon Chung 		case 5:
113364f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_41;
113464f4a619SJaehoon Chung 			break;
113564f4a619SJaehoon Chung 		case 6:
113664f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_5;
113764f4a619SJaehoon Chung 			break;
113864f4a619SJaehoon Chung 		}
113964f4a619SJaehoon Chung 
1140e6f99a56SLei Wen 		/*
1141e6f99a56SLei Wen 		 * Check whether GROUP_DEF is set, if yes, read out
1142e6f99a56SLei Wen 		 * group size from ext_csd directly, or calculate
1143e6f99a56SLei Wen 		 * the group size from the csd value.
1144e6f99a56SLei Wen 		 */
11458bfa195eSSimon Glass 		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF]) {
11460560db18SLei Wen 			mmc->erase_grp_size =
11478bfa195eSSimon Glass 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] *
11488bfa195eSSimon Glass 					MMC_MAX_BLOCK_LEN * 1024;
11498bfa195eSSimon Glass 		} else {
1150e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
1151e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1152e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1153e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
1154e6f99a56SLei Wen 				* (erase_gmul + 1);
1155e6f99a56SLei Wen 		}
1156e6f99a56SLei Wen 
1157bc897b1dSLei Wen 		/* store the partition info of emmc */
11588948ea83SStephen Warren 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
11598948ea83SStephen Warren 		    ext_csd[EXT_CSD_BOOT_MULT])
11600560db18SLei Wen 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
1161f866a46dSStephen Warren 
1162f866a46dSStephen Warren 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
1163f866a46dSStephen Warren 
1164f866a46dSStephen Warren 		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
1165f866a46dSStephen Warren 
1166f866a46dSStephen Warren 		for (i = 0; i < 4; i++) {
1167f866a46dSStephen Warren 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
1168f866a46dSStephen Warren 			mmc->capacity_gp[i] = (ext_csd[idx + 2] << 16) +
1169f866a46dSStephen Warren 				(ext_csd[idx + 1] << 8) + ext_csd[idx];
1170f866a46dSStephen Warren 			mmc->capacity_gp[i] *=
1171f866a46dSStephen Warren 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1172f866a46dSStephen Warren 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1173d23e2c09SSukumar Ghorai 		}
1174f866a46dSStephen Warren 	}
1175f866a46dSStephen Warren 
1176f866a46dSStephen Warren 	err = mmc_set_capacity(mmc, mmc->part_num);
1177f866a46dSStephen Warren 	if (err)
1178f866a46dSStephen Warren 		return err;
1179d23e2c09SSukumar Ghorai 
1180272cc70bSAndy Fleming 	if (IS_SD(mmc))
1181272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1182272cc70bSAndy Fleming 	else
1183272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1184272cc70bSAndy Fleming 
1185272cc70bSAndy Fleming 	if (err)
1186272cc70bSAndy Fleming 		return err;
1187272cc70bSAndy Fleming 
1188272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
1189272cc70bSAndy Fleming 	mmc->card_caps &= mmc->host_caps;
1190272cc70bSAndy Fleming 
1191272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1192272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1193272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1194272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1195272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1196272cc70bSAndy Fleming 
1197272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1198272cc70bSAndy Fleming 			if (err)
1199272cc70bSAndy Fleming 				return err;
1200272cc70bSAndy Fleming 
1201272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1202272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1203272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1204272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1205272cc70bSAndy Fleming 			if (err)
1206272cc70bSAndy Fleming 				return err;
1207272cc70bSAndy Fleming 
1208272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1209272cc70bSAndy Fleming 		}
1210272cc70bSAndy Fleming 
1211272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
1212ad5fd922SJaehoon Chung 			mmc->tran_speed = 50000000;
1213272cc70bSAndy Fleming 		else
1214ad5fd922SJaehoon Chung 			mmc->tran_speed = 25000000;
1215272cc70bSAndy Fleming 	} else {
12167798f6dbSAndy Fleming 		int idx;
12177798f6dbSAndy Fleming 
12187798f6dbSAndy Fleming 		/* An array of possible bus widths in order of preference */
12197798f6dbSAndy Fleming 		static unsigned ext_csd_bits[] = {
12207798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_8,
12217798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_4,
12227798f6dbSAndy Fleming 			EXT_CSD_BUS_WIDTH_1,
12237798f6dbSAndy Fleming 		};
12247798f6dbSAndy Fleming 
12257798f6dbSAndy Fleming 		/* An array to map CSD bus widths to host cap bits */
12267798f6dbSAndy Fleming 		static unsigned ext_to_hostcaps[] = {
12277798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
12287798f6dbSAndy Fleming 			[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
12297798f6dbSAndy Fleming 		};
12307798f6dbSAndy Fleming 
12317798f6dbSAndy Fleming 		/* An array to map chosen bus width to an integer */
12327798f6dbSAndy Fleming 		static unsigned widths[] = {
12337798f6dbSAndy Fleming 			8, 4, 1,
12347798f6dbSAndy Fleming 		};
12357798f6dbSAndy Fleming 
12367798f6dbSAndy Fleming 		for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
12377798f6dbSAndy Fleming 			unsigned int extw = ext_csd_bits[idx];
12387798f6dbSAndy Fleming 
12397798f6dbSAndy Fleming 			/*
12407798f6dbSAndy Fleming 			 * Check to make sure the controller supports
12417798f6dbSAndy Fleming 			 * this bus width, if it's more than 1
12427798f6dbSAndy Fleming 			 */
12437798f6dbSAndy Fleming 			if (extw != EXT_CSD_BUS_WIDTH_1 &&
12447798f6dbSAndy Fleming 					!(mmc->host_caps & ext_to_hostcaps[extw]))
12457798f6dbSAndy Fleming 				continue;
12467798f6dbSAndy Fleming 
1247272cc70bSAndy Fleming 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
12487798f6dbSAndy Fleming 					EXT_CSD_BUS_WIDTH, extw);
1249272cc70bSAndy Fleming 
1250272cc70bSAndy Fleming 			if (err)
12514137894eSLei Wen 				continue;
1252272cc70bSAndy Fleming 
12537798f6dbSAndy Fleming 			mmc_set_bus_width(mmc, widths[idx]);
1254272cc70bSAndy Fleming 
12554137894eSLei Wen 			err = mmc_send_ext_csd(mmc, test_csd);
12564137894eSLei Wen 			if (!err && ext_csd[EXT_CSD_PARTITIONING_SUPPORT] \
12574137894eSLei Wen 				    == test_csd[EXT_CSD_PARTITIONING_SUPPORT]
12584137894eSLei Wen 				 && ext_csd[EXT_CSD_ERASE_GROUP_DEF] \
12594137894eSLei Wen 				    == test_csd[EXT_CSD_ERASE_GROUP_DEF] \
12604137894eSLei Wen 				 && ext_csd[EXT_CSD_REV] \
12614137894eSLei Wen 				    == test_csd[EXT_CSD_REV]
12624137894eSLei Wen 				 && ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] \
12634137894eSLei Wen 				    == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
12644137894eSLei Wen 				 && memcmp(&ext_csd[EXT_CSD_SEC_CNT], \
12654137894eSLei Wen 					&test_csd[EXT_CSD_SEC_CNT], 4) == 0) {
1266272cc70bSAndy Fleming 
12677798f6dbSAndy Fleming 				mmc->card_caps |= ext_to_hostcaps[extw];
12684137894eSLei Wen 				break;
12694137894eSLei Wen 			}
1270272cc70bSAndy Fleming 		}
1271272cc70bSAndy Fleming 
1272272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS) {
1273272cc70bSAndy Fleming 			if (mmc->card_caps & MMC_MODE_HS_52MHz)
1274ad5fd922SJaehoon Chung 				mmc->tran_speed = 52000000;
1275272cc70bSAndy Fleming 			else
1276ad5fd922SJaehoon Chung 				mmc->tran_speed = 26000000;
1277272cc70bSAndy Fleming 		}
1278ad5fd922SJaehoon Chung 	}
1279ad5fd922SJaehoon Chung 
1280ad5fd922SJaehoon Chung 	mmc_set_clock(mmc, mmc->tran_speed);
1281272cc70bSAndy Fleming 
1282272cc70bSAndy Fleming 	/* fill in device description */
1283272cc70bSAndy Fleming 	mmc->block_dev.lun = 0;
1284272cc70bSAndy Fleming 	mmc->block_dev.type = 0;
1285272cc70bSAndy Fleming 	mmc->block_dev.blksz = mmc->read_bl_len;
12860472fbfdSEgbert Eich 	mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz);
12879b1f942cSRabin Vincent 	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
1288*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1289babce5f6STaylor Hutt 	sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x",
1290babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1291babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1292babce5f6STaylor Hutt 	sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
12930b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1294babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1295babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1296babce5f6STaylor Hutt 	sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1297babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
1298*56196826SPaul Burton #else
1299*56196826SPaul Burton 	mmc->block_dev.vendor[0] = 0;
1300*56196826SPaul Burton 	mmc->block_dev.product[0] = 0;
1301*56196826SPaul Burton 	mmc->block_dev.revision[0] = 0;
1302*56196826SPaul Burton #endif
1303122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1304272cc70bSAndy Fleming 	init_part(&mmc->block_dev);
1305122efd43SMikhail Kshevetskiy #endif
1306272cc70bSAndy Fleming 
1307272cc70bSAndy Fleming 	return 0;
1308272cc70bSAndy Fleming }
1309272cc70bSAndy Fleming 
1310fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1311272cc70bSAndy Fleming {
1312272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1313272cc70bSAndy Fleming 	int err;
1314272cc70bSAndy Fleming 
1315272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1316272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
1317272cc70bSAndy Fleming 	cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa;
1318272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1319272cc70bSAndy Fleming 
1320272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1321272cc70bSAndy Fleming 
1322272cc70bSAndy Fleming 	if (err)
1323272cc70bSAndy Fleming 		return err;
1324272cc70bSAndy Fleming 
1325998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1326272cc70bSAndy Fleming 		return UNUSABLE_ERR;
1327272cc70bSAndy Fleming 	else
1328272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1329272cc70bSAndy Fleming 
1330272cc70bSAndy Fleming 	return 0;
1331272cc70bSAndy Fleming }
1332272cc70bSAndy Fleming 
1333272cc70bSAndy Fleming int mmc_register(struct mmc *mmc)
1334272cc70bSAndy Fleming {
1335272cc70bSAndy Fleming 	/* Setup the universal parts of the block interface just once */
1336272cc70bSAndy Fleming 	mmc->block_dev.if_type = IF_TYPE_MMC;
1337272cc70bSAndy Fleming 	mmc->block_dev.dev = cur_dev_num++;
1338272cc70bSAndy Fleming 	mmc->block_dev.removable = 1;
1339272cc70bSAndy Fleming 	mmc->block_dev.block_read = mmc_bread;
1340272cc70bSAndy Fleming 	mmc->block_dev.block_write = mmc_bwrite;
1341e6f99a56SLei Wen 	mmc->block_dev.block_erase = mmc_berase;
13428feafcc4SJohn Rigby 	if (!mmc->b_max)
13438feafcc4SJohn Rigby 		mmc->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
1344272cc70bSAndy Fleming 
1345272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc->link);
1346272cc70bSAndy Fleming 
1347272cc70bSAndy Fleming 	list_add_tail (&mmc->link, &mmc_devices);
1348272cc70bSAndy Fleming 
1349272cc70bSAndy Fleming 	return 0;
1350272cc70bSAndy Fleming }
1351272cc70bSAndy Fleming 
1352df3fc526SMatthew McClintock #ifdef CONFIG_PARTITIONS
1353272cc70bSAndy Fleming block_dev_desc_t *mmc_get_dev(int dev)
1354272cc70bSAndy Fleming {
1355272cc70bSAndy Fleming 	struct mmc *mmc = find_mmc_device(dev);
13566bb4b4bcSBenoît Thébaudeau 	if (!mmc || mmc_init(mmc))
135740242bc3SŁukasz Majewski 		return NULL;
1358272cc70bSAndy Fleming 
135940242bc3SŁukasz Majewski 	return &mmc->block_dev;
1360272cc70bSAndy Fleming }
1361df3fc526SMatthew McClintock #endif
1362272cc70bSAndy Fleming 
1363e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1364272cc70bSAndy Fleming {
1365afd5932bSMacpaul Lin 	int err;
1366272cc70bSAndy Fleming 
136748972d90SThierry Reding 	if (mmc_getcd(mmc) == 0) {
136848972d90SThierry Reding 		mmc->has_init = 0;
1369*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
137048972d90SThierry Reding 		printf("MMC: no card present\n");
1371*56196826SPaul Burton #endif
137248972d90SThierry Reding 		return NO_CARD_ERR;
137348972d90SThierry Reding 	}
137448972d90SThierry Reding 
1375bc897b1dSLei Wen 	if (mmc->has_init)
1376bc897b1dSLei Wen 		return 0;
1377bc897b1dSLei Wen 
1378272cc70bSAndy Fleming 	err = mmc->init(mmc);
1379272cc70bSAndy Fleming 
1380272cc70bSAndy Fleming 	if (err)
1381272cc70bSAndy Fleming 		return err;
1382272cc70bSAndy Fleming 
1383b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1384b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1385b86b85e2SIlya Yanok 
1386272cc70bSAndy Fleming 	/* Reset the Card */
1387272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1388272cc70bSAndy Fleming 
1389272cc70bSAndy Fleming 	if (err)
1390272cc70bSAndy Fleming 		return err;
1391272cc70bSAndy Fleming 
1392bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1393bc897b1dSLei Wen 	mmc->part_num = 0;
1394bc897b1dSLei Wen 
1395272cc70bSAndy Fleming 	/* Test for SD version 2 */
1396272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1397272cc70bSAndy Fleming 
1398272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1399272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1400272cc70bSAndy Fleming 
1401272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1402272cc70bSAndy Fleming 	if (err == TIMEOUT) {
1403272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1404272cc70bSAndy Fleming 
1405e9550449SChe-Liang Chiou 		if (err && err != IN_PROGRESS) {
1406*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1407272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
1408*56196826SPaul Burton #endif
1409272cc70bSAndy Fleming 			return UNUSABLE_ERR;
1410272cc70bSAndy Fleming 		}
1411272cc70bSAndy Fleming 	}
1412272cc70bSAndy Fleming 
1413e9550449SChe-Liang Chiou 	if (err == IN_PROGRESS)
1414e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
1415e9550449SChe-Liang Chiou 
1416e9550449SChe-Liang Chiou 	return err;
1417e9550449SChe-Liang Chiou }
1418e9550449SChe-Liang Chiou 
1419e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
1420e9550449SChe-Liang Chiou {
1421e9550449SChe-Liang Chiou 	int err = 0;
1422e9550449SChe-Liang Chiou 
1423e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
1424e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
1425e9550449SChe-Liang Chiou 
1426e9550449SChe-Liang Chiou 	if (!err)
1427bc897b1dSLei Wen 		err = mmc_startup(mmc);
1428bc897b1dSLei Wen 	if (err)
1429bc897b1dSLei Wen 		mmc->has_init = 0;
1430bc897b1dSLei Wen 	else
1431bc897b1dSLei Wen 		mmc->has_init = 1;
1432e9550449SChe-Liang Chiou 	mmc->init_in_progress = 0;
1433e9550449SChe-Liang Chiou 	return err;
1434e9550449SChe-Liang Chiou }
1435e9550449SChe-Liang Chiou 
1436e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
1437e9550449SChe-Liang Chiou {
1438e9550449SChe-Liang Chiou 	int err = IN_PROGRESS;
1439e9550449SChe-Liang Chiou 	unsigned start = get_timer(0);
1440e9550449SChe-Liang Chiou 
1441e9550449SChe-Liang Chiou 	if (mmc->has_init)
1442e9550449SChe-Liang Chiou 		return 0;
1443e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
1444e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
1445e9550449SChe-Liang Chiou 
1446e9550449SChe-Liang Chiou 	if (!err || err == IN_PROGRESS)
1447e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
1448e9550449SChe-Liang Chiou 	debug("%s: %d, time %lu\n", __func__, err, get_timer(start));
1449bc897b1dSLei Wen 	return err;
1450272cc70bSAndy Fleming }
1451272cc70bSAndy Fleming 
1452272cc70bSAndy Fleming /*
1453272cc70bSAndy Fleming  * CPU and board-specific MMC initializations.  Aliased function
1454272cc70bSAndy Fleming  * signals caller to move on
1455272cc70bSAndy Fleming  */
1456272cc70bSAndy Fleming static int __def_mmc_init(bd_t *bis)
1457272cc70bSAndy Fleming {
1458272cc70bSAndy Fleming 	return -1;
1459272cc70bSAndy Fleming }
1460272cc70bSAndy Fleming 
1461f9a109b3SPeter Tyser int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
1462f9a109b3SPeter Tyser int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
1463272cc70bSAndy Fleming 
1464*56196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1465*56196826SPaul Burton 
1466272cc70bSAndy Fleming void print_mmc_devices(char separator)
1467272cc70bSAndy Fleming {
1468272cc70bSAndy Fleming 	struct mmc *m;
1469272cc70bSAndy Fleming 	struct list_head *entry;
1470272cc70bSAndy Fleming 
1471272cc70bSAndy Fleming 	list_for_each(entry, &mmc_devices) {
1472272cc70bSAndy Fleming 		m = list_entry(entry, struct mmc, link);
1473272cc70bSAndy Fleming 
1474272cc70bSAndy Fleming 		printf("%s: %d", m->name, m->block_dev.dev);
1475272cc70bSAndy Fleming 
1476272cc70bSAndy Fleming 		if (entry->next != &mmc_devices)
1477272cc70bSAndy Fleming 			printf("%c ", separator);
1478272cc70bSAndy Fleming 	}
1479272cc70bSAndy Fleming 
1480272cc70bSAndy Fleming 	printf("\n");
1481272cc70bSAndy Fleming }
1482272cc70bSAndy Fleming 
1483*56196826SPaul Burton #else
1484*56196826SPaul Burton void print_mmc_devices(char separator) { }
1485*56196826SPaul Burton #endif
1486*56196826SPaul Burton 
1487ea6ebe21SLei Wen int get_mmc_num(void)
1488ea6ebe21SLei Wen {
1489ea6ebe21SLei Wen 	return cur_dev_num;
1490ea6ebe21SLei Wen }
1491ea6ebe21SLei Wen 
1492e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
1493e9550449SChe-Liang Chiou {
1494e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
1495e9550449SChe-Liang Chiou }
1496e9550449SChe-Liang Chiou 
1497e9550449SChe-Liang Chiou static void do_preinit(void)
1498e9550449SChe-Liang Chiou {
1499e9550449SChe-Liang Chiou 	struct mmc *m;
1500e9550449SChe-Liang Chiou 	struct list_head *entry;
1501e9550449SChe-Liang Chiou 
1502e9550449SChe-Liang Chiou 	list_for_each(entry, &mmc_devices) {
1503e9550449SChe-Liang Chiou 		m = list_entry(entry, struct mmc, link);
1504e9550449SChe-Liang Chiou 
1505e9550449SChe-Liang Chiou 		if (m->preinit)
1506e9550449SChe-Liang Chiou 			mmc_start_init(m);
1507e9550449SChe-Liang Chiou 	}
1508e9550449SChe-Liang Chiou }
1509e9550449SChe-Liang Chiou 
1510e9550449SChe-Liang Chiou 
1511272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1512272cc70bSAndy Fleming {
1513272cc70bSAndy Fleming 	INIT_LIST_HEAD (&mmc_devices);
1514272cc70bSAndy Fleming 	cur_dev_num = 0;
1515272cc70bSAndy Fleming 
1516272cc70bSAndy Fleming 	if (board_mmc_init(bis) < 0)
1517272cc70bSAndy Fleming 		cpu_mmc_init(bis);
1518272cc70bSAndy Fleming 
1519bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
1520272cc70bSAndy Fleming 	print_mmc_devices(',');
1521bb0dc108SYing Zhang #endif
1522272cc70bSAndy Fleming 
1523e9550449SChe-Liang Chiou 	do_preinit();
1524272cc70bSAndy Fleming 	return 0;
1525272cc70bSAndy Fleming }
15263690d6d6SAmar 
15273690d6d6SAmar #ifdef CONFIG_SUPPORT_EMMC_BOOT
15283690d6d6SAmar /*
15293690d6d6SAmar  * This function changes the size of boot partition and the size of rpmb
15303690d6d6SAmar  * partition present on EMMC devices.
15313690d6d6SAmar  *
15323690d6d6SAmar  * Input Parameters:
15333690d6d6SAmar  * struct *mmc: pointer for the mmc device strcuture
15343690d6d6SAmar  * bootsize: size of boot partition
15353690d6d6SAmar  * rpmbsize: size of rpmb partition
15363690d6d6SAmar  *
15373690d6d6SAmar  * Returns 0 on success.
15383690d6d6SAmar  */
15393690d6d6SAmar 
15403690d6d6SAmar int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
15413690d6d6SAmar 				unsigned long rpmbsize)
15423690d6d6SAmar {
15433690d6d6SAmar 	int err;
15443690d6d6SAmar 	struct mmc_cmd cmd;
15453690d6d6SAmar 
15463690d6d6SAmar 	/* Only use this command for raw EMMC moviNAND. Enter backdoor mode */
15473690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
15483690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
15493690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG1;
15503690d6d6SAmar 
15513690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
15523690d6d6SAmar 	if (err) {
15533690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error1 = %d\n", err);
15543690d6d6SAmar 		return err;
15553690d6d6SAmar 	}
15563690d6d6SAmar 
15573690d6d6SAmar 	/* Boot partition changing mode */
15583690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
15593690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
15603690d6d6SAmar 	cmd.cmdarg = MMC_CMD62_ARG2;
15613690d6d6SAmar 
15623690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
15633690d6d6SAmar 	if (err) {
15643690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error2 = %d\n", err);
15653690d6d6SAmar 		return err;
15663690d6d6SAmar 	}
15673690d6d6SAmar 	/* boot partition size is multiple of 128KB */
15683690d6d6SAmar 	bootsize = (bootsize * 1024) / 128;
15693690d6d6SAmar 
15703690d6d6SAmar 	/* Arg: boot partition size */
15713690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
15723690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
15733690d6d6SAmar 	cmd.cmdarg = bootsize;
15743690d6d6SAmar 
15753690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
15763690d6d6SAmar 	if (err) {
15773690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error3 = %d\n", err);
15783690d6d6SAmar 		return err;
15793690d6d6SAmar 	}
15803690d6d6SAmar 	/* RPMB partition size is multiple of 128KB */
15813690d6d6SAmar 	rpmbsize = (rpmbsize * 1024) / 128;
15823690d6d6SAmar 	/* Arg: RPMB partition size */
15833690d6d6SAmar 	cmd.cmdidx = MMC_CMD_RES_MAN;
15843690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
15853690d6d6SAmar 	cmd.cmdarg = rpmbsize;
15863690d6d6SAmar 
15873690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
15883690d6d6SAmar 	if (err) {
15893690d6d6SAmar 		debug("mmc_boot_partition_size_change: Error4 = %d\n", err);
15903690d6d6SAmar 		return err;
15913690d6d6SAmar 	}
15923690d6d6SAmar 	return 0;
15933690d6d6SAmar }
15943690d6d6SAmar 
15953690d6d6SAmar /*
15963690d6d6SAmar  * This function shall form and send the commands to open / close the
15973690d6d6SAmar  * boot partition specified by user.
15983690d6d6SAmar  *
15993690d6d6SAmar  * Input Parameters:
16003690d6d6SAmar  * ack: 0x0 - No boot acknowledge sent (default)
16013690d6d6SAmar  *	0x1 - Boot acknowledge sent during boot operation
16023690d6d6SAmar  * part_num: User selects boot data that will be sent to master
16033690d6d6SAmar  *	0x0 - Device not boot enabled (default)
16043690d6d6SAmar  *	0x1 - Boot partition 1 enabled for boot
16053690d6d6SAmar  *	0x2 - Boot partition 2 enabled for boot
16063690d6d6SAmar  * access: User selects partitions to access
16073690d6d6SAmar  *	0x0 : No access to boot partition (default)
16083690d6d6SAmar  *	0x1 : R/W boot partition 1
16093690d6d6SAmar  *	0x2 : R/W boot partition 2
16103690d6d6SAmar  *	0x3 : R/W Replay Protected Memory Block (RPMB)
16113690d6d6SAmar  *
16123690d6d6SAmar  * Returns 0 on success.
16133690d6d6SAmar  */
16143690d6d6SAmar int mmc_boot_part_access(struct mmc *mmc, u8 ack, u8 part_num, u8 access)
16153690d6d6SAmar {
16163690d6d6SAmar 	int err;
16173690d6d6SAmar 	struct mmc_cmd cmd;
16183690d6d6SAmar 
16193690d6d6SAmar 	/* Boot ack enable, boot partition enable , boot partition access */
16203690d6d6SAmar 	cmd.cmdidx = MMC_CMD_SWITCH;
16213690d6d6SAmar 	cmd.resp_type = MMC_RSP_R1b;
16223690d6d6SAmar 
16233690d6d6SAmar 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
16243690d6d6SAmar 			(EXT_CSD_PART_CONF << 16) |
16253690d6d6SAmar 			((EXT_CSD_BOOT_ACK(ack) |
16263690d6d6SAmar 			EXT_CSD_BOOT_PART_NUM(part_num) |
16273690d6d6SAmar 			EXT_CSD_PARTITION_ACCESS(access)) << 8);
16283690d6d6SAmar 
16293690d6d6SAmar 	err = mmc_send_cmd(mmc, &cmd, NULL);
16303690d6d6SAmar 	if (err) {
16313690d6d6SAmar 		if (access) {
16323690d6d6SAmar 			debug("mmc boot partition#%d open fail:Error1 = %d\n",
16333690d6d6SAmar 			      part_num, err);
16343690d6d6SAmar 		} else {
16353690d6d6SAmar 			debug("mmc boot partition#%d close fail:Error = %d\n",
16363690d6d6SAmar 			      part_num, err);
16373690d6d6SAmar 		}
16383690d6d6SAmar 		return err;
16393690d6d6SAmar 	}
16403690d6d6SAmar 
16413690d6d6SAmar 	if (access) {
16423690d6d6SAmar 		/* 4bit transfer mode at booting time. */
16433690d6d6SAmar 		cmd.cmdidx = MMC_CMD_SWITCH;
16443690d6d6SAmar 		cmd.resp_type = MMC_RSP_R1b;
16453690d6d6SAmar 
16463690d6d6SAmar 		cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
16473690d6d6SAmar 				(EXT_CSD_BOOT_BUS_WIDTH << 16) |
16483690d6d6SAmar 				((1 << 0) << 8);
16493690d6d6SAmar 
16503690d6d6SAmar 		err = mmc_send_cmd(mmc, &cmd, NULL);
16513690d6d6SAmar 		if (err) {
16523690d6d6SAmar 			debug("mmc boot partition#%d open fail:Error2 = %d\n",
16533690d6d6SAmar 			      part_num, err);
16543690d6d6SAmar 			return err;
16553690d6d6SAmar 		}
16563690d6d6SAmar 	}
16573690d6d6SAmar 	return 0;
16583690d6d6SAmar }
16593690d6d6SAmar #endif
1660