xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 83dc42271f79202b746bc9614817b41a6911c88f)
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>
138e3332e2SSjoerd Simons #include <dm.h>
148e3332e2SSjoerd Simons #include <dm/device-internal.h>
15d4622df3SStephen Warren #include <errno.h>
16272cc70bSAndy Fleming #include <mmc.h>
17272cc70bSAndy Fleming #include <part.h>
182051aefeSPeng Fan #include <power/regulator.h>
19272cc70bSAndy Fleming #include <malloc.h>
20cf92e05cSSimon Glass #include <memalign.h>
21272cc70bSAndy Fleming #include <linux/list.h>
229b1f942cSRabin Vincent #include <div64.h>
23da61fa5fSPaul Burton #include "mmc_private.h"
24272cc70bSAndy Fleming 
253697e599SPeng Fan static const unsigned int sd_au_size[] = {
263697e599SPeng Fan 	0,		SZ_16K / 512,		SZ_32K / 512,
273697e599SPeng Fan 	SZ_64K / 512,	SZ_128K / 512,		SZ_256K / 512,
283697e599SPeng Fan 	SZ_512K / 512,	SZ_1M / 512,		SZ_2M / 512,
293697e599SPeng Fan 	SZ_4M / 512,	SZ_8M / 512,		(SZ_8M + SZ_4M) / 512,
303697e599SPeng Fan 	SZ_16M / 512,	(SZ_16M + SZ_8M) / 512,	SZ_32M / 512,	SZ_64M / 512,
313697e599SPeng Fan };
323697e599SPeng Fan 
33aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage);
34fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc);
3501298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps);
36aff5d3c8SKishon Vijay Abraham I 
37b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
38b5b838f1SMarek Vasut static struct mmc mmc_static;
39b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num)
40b5b838f1SMarek Vasut {
41b5b838f1SMarek Vasut 	return &mmc_static;
42b5b838f1SMarek Vasut }
43b5b838f1SMarek Vasut 
44b5b838f1SMarek Vasut void mmc_do_preinit(void)
45b5b838f1SMarek Vasut {
46b5b838f1SMarek Vasut 	struct mmc *m = &mmc_static;
47b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
48b5b838f1SMarek Vasut 	mmc_set_preinit(m, 1);
49b5b838f1SMarek Vasut #endif
50b5b838f1SMarek Vasut 	if (m->preinit)
51b5b838f1SMarek Vasut 		mmc_start_init(m);
52b5b838f1SMarek Vasut }
53b5b838f1SMarek Vasut 
54b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
55b5b838f1SMarek Vasut {
56b5b838f1SMarek Vasut 	return &mmc->block_dev;
57b5b838f1SMarek Vasut }
58b5b838f1SMarek Vasut #endif
59b5b838f1SMarek Vasut 
60e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
61c10b85d6SJean-Jacques Hiblot 
62c10b85d6SJean-Jacques Hiblot static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout)
63c10b85d6SJean-Jacques Hiblot {
64c10b85d6SJean-Jacques Hiblot 	return -ENOSYS;
65c10b85d6SJean-Jacques Hiblot }
66c10b85d6SJean-Jacques Hiblot 
67750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
68d23d8d7eSNikita Kiryanov {
69d23d8d7eSNikita Kiryanov 	return -1;
70d23d8d7eSNikita Kiryanov }
71d23d8d7eSNikita Kiryanov 
72d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
73d23d8d7eSNikita Kiryanov {
74d23d8d7eSNikita Kiryanov 	int wp;
75d23d8d7eSNikita Kiryanov 
76d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
77d23d8d7eSNikita Kiryanov 
78d4e1da4eSPeter Korsgaard 	if (wp < 0) {
7993bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
8093bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
81d4e1da4eSPeter Korsgaard 		else
82d4e1da4eSPeter Korsgaard 			wp = 0;
83d4e1da4eSPeter Korsgaard 	}
84d23d8d7eSNikita Kiryanov 
85d23d8d7eSNikita Kiryanov 	return wp;
86d23d8d7eSNikita Kiryanov }
87d23d8d7eSNikita Kiryanov 
88cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc)
89cee9ab7cSJeroen Hofstee {
9011fdade2SStefano Babic 	return -1;
9111fdade2SStefano Babic }
928ca51e51SSimon Glass #endif
9311fdade2SStefano Babic 
948635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
95c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd)
96c0c76ebaSSimon Glass {
97c0c76ebaSSimon Glass 	printf("CMD_SEND:%d\n", cmd->cmdidx);
98c0c76ebaSSimon Glass 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
99c0c76ebaSSimon Glass }
100c0c76ebaSSimon Glass 
101c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
102c0c76ebaSSimon Glass {
1035db2fe3aSRaffaele Recalcati 	int i;
1045db2fe3aSRaffaele Recalcati 	u8 *ptr;
1055db2fe3aSRaffaele Recalcati 
1067863ce58SBin Meng 	if (ret) {
1077863ce58SBin Meng 		printf("\t\tRET\t\t\t %d\n", ret);
1087863ce58SBin Meng 	} else {
1095db2fe3aSRaffaele Recalcati 		switch (cmd->resp_type) {
1105db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
1115db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
1125db2fe3aSRaffaele Recalcati 			break;
1135db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
1145db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
1155db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1165db2fe3aSRaffaele Recalcati 			break;
1175db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
1185db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
1195db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1205db2fe3aSRaffaele Recalcati 			break;
1215db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
1225db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
1235db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1245db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1255db2fe3aSRaffaele Recalcati 				cmd->response[1]);
1265db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1275db2fe3aSRaffaele Recalcati 				cmd->response[2]);
1285db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1295db2fe3aSRaffaele Recalcati 				cmd->response[3]);
1305db2fe3aSRaffaele Recalcati 			printf("\n");
1315db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
1325db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
1335db2fe3aSRaffaele Recalcati 				int j;
1345db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
135146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
1365db2fe3aSRaffaele Recalcati 				ptr += 3;
1375db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
1385db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
1395db2fe3aSRaffaele Recalcati 				printf("\n");
1405db2fe3aSRaffaele Recalcati 			}
1415db2fe3aSRaffaele Recalcati 			break;
1425db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1435db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1445db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1455db2fe3aSRaffaele Recalcati 			break;
1465db2fe3aSRaffaele Recalcati 		default:
1475db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1485db2fe3aSRaffaele Recalcati 			break;
1495db2fe3aSRaffaele Recalcati 		}
1507863ce58SBin Meng 	}
151c0c76ebaSSimon Glass }
152c0c76ebaSSimon Glass 
153c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd)
154c0c76ebaSSimon Glass {
155c0c76ebaSSimon Glass 	int status;
156c0c76ebaSSimon Glass 
157c0c76ebaSSimon Glass 	status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9;
158c0c76ebaSSimon Glass 	printf("CURR STATE:%d\n", status);
159c0c76ebaSSimon Glass }
1605db2fe3aSRaffaele Recalcati #endif
161c0c76ebaSSimon Glass 
16235f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
16335f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode)
16435f9e196SJean-Jacques Hiblot {
16535f9e196SJean-Jacques Hiblot 	static const char *const names[] = {
16635f9e196SJean-Jacques Hiblot 	      [MMC_LEGACY]	= "MMC legacy",
16735f9e196SJean-Jacques Hiblot 	      [SD_LEGACY]	= "SD Legacy",
16835f9e196SJean-Jacques Hiblot 	      [MMC_HS]		= "MMC High Speed (26MHz)",
16935f9e196SJean-Jacques Hiblot 	      [SD_HS]		= "SD High Speed (50MHz)",
17035f9e196SJean-Jacques Hiblot 	      [UHS_SDR12]	= "UHS SDR12 (25MHz)",
17135f9e196SJean-Jacques Hiblot 	      [UHS_SDR25]	= "UHS SDR25 (50MHz)",
17235f9e196SJean-Jacques Hiblot 	      [UHS_SDR50]	= "UHS SDR50 (100MHz)",
17335f9e196SJean-Jacques Hiblot 	      [UHS_SDR104]	= "UHS SDR104 (208MHz)",
17435f9e196SJean-Jacques Hiblot 	      [UHS_DDR50]	= "UHS DDR50 (50MHz)",
17535f9e196SJean-Jacques Hiblot 	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
17635f9e196SJean-Jacques Hiblot 	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
17735f9e196SJean-Jacques Hiblot 	      [MMC_HS_200]	= "HS200 (200MHz)",
17835f9e196SJean-Jacques Hiblot 	};
17935f9e196SJean-Jacques Hiblot 
18035f9e196SJean-Jacques Hiblot 	if (mode >= MMC_MODES_END)
18135f9e196SJean-Jacques Hiblot 		return "Unknown mode";
18235f9e196SJean-Jacques Hiblot 	else
18335f9e196SJean-Jacques Hiblot 		return names[mode];
18435f9e196SJean-Jacques Hiblot }
18535f9e196SJean-Jacques Hiblot #endif
18635f9e196SJean-Jacques Hiblot 
18705038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
18805038576SJean-Jacques Hiblot {
18905038576SJean-Jacques Hiblot 	static const int freqs[] = {
19005038576SJean-Jacques Hiblot 	      [SD_LEGACY]	= 25000000,
19105038576SJean-Jacques Hiblot 	      [MMC_HS]		= 26000000,
19205038576SJean-Jacques Hiblot 	      [SD_HS]		= 50000000,
19305038576SJean-Jacques Hiblot 	      [UHS_SDR12]	= 25000000,
19405038576SJean-Jacques Hiblot 	      [UHS_SDR25]	= 50000000,
19505038576SJean-Jacques Hiblot 	      [UHS_SDR50]	= 100000000,
19605038576SJean-Jacques Hiblot 	      [UHS_SDR104]	= 208000000,
19705038576SJean-Jacques Hiblot 	      [UHS_DDR50]	= 50000000,
19805038576SJean-Jacques Hiblot 	      [MMC_HS_52]	= 52000000,
19905038576SJean-Jacques Hiblot 	      [MMC_DDR_52]	= 52000000,
20005038576SJean-Jacques Hiblot 	      [MMC_HS_200]	= 200000000,
20105038576SJean-Jacques Hiblot 	};
20205038576SJean-Jacques Hiblot 
20305038576SJean-Jacques Hiblot 	if (mode == MMC_LEGACY)
20405038576SJean-Jacques Hiblot 		return mmc->legacy_speed;
20505038576SJean-Jacques Hiblot 	else if (mode >= MMC_MODES_END)
20605038576SJean-Jacques Hiblot 		return 0;
20705038576SJean-Jacques Hiblot 	else
20805038576SJean-Jacques Hiblot 		return freqs[mode];
20905038576SJean-Jacques Hiblot }
21005038576SJean-Jacques Hiblot 
21135f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode)
21235f9e196SJean-Jacques Hiblot {
21335f9e196SJean-Jacques Hiblot 	mmc->selected_mode = mode;
21405038576SJean-Jacques Hiblot 	mmc->tran_speed = mmc_mode2freq(mmc, mode);
2153862b854SJean-Jacques Hiblot 	mmc->ddr_mode = mmc_is_mode_ddr(mode);
21635f9e196SJean-Jacques Hiblot 	debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
21735f9e196SJean-Jacques Hiblot 	      mmc->tran_speed / 1000000);
21835f9e196SJean-Jacques Hiblot 	return 0;
21935f9e196SJean-Jacques Hiblot }
22035f9e196SJean-Jacques Hiblot 
221e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
222c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
223c0c76ebaSSimon Glass {
224c0c76ebaSSimon Glass 	int ret;
225c0c76ebaSSimon Glass 
226c0c76ebaSSimon Glass 	mmmc_trace_before_send(mmc, cmd);
227c0c76ebaSSimon Glass 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
228c0c76ebaSSimon Glass 	mmmc_trace_after_send(mmc, cmd, ret);
229c0c76ebaSSimon Glass 
2308635ff9eSMarek Vasut 	return ret;
231272cc70bSAndy Fleming }
2328ca51e51SSimon Glass #endif
233272cc70bSAndy Fleming 
234da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
2355d4fc8d9SRaffaele Recalcati {
2365d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
237d617c426SJan Kloetzke 	int err, retries = 5;
2385d4fc8d9SRaffaele Recalcati 
2395d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
2405d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
241aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
242aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
2435d4fc8d9SRaffaele Recalcati 
2441677eef4SAndrew Gabbasov 	while (1) {
2455d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
246d617c426SJan Kloetzke 		if (!err) {
247d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
248d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
249d617c426SJan Kloetzke 			     MMC_STATE_PRG)
2505d4fc8d9SRaffaele Recalcati 				break;
251d0c221feSJean-Jacques Hiblot 
252d0c221feSJean-Jacques Hiblot 			if (cmd.response[0] & MMC_STATUS_MASK) {
25356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
254d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
255d617c426SJan Kloetzke 					cmd.response[0]);
25656196826SPaul Burton #endif
257915ffa52SJaehoon Chung 				return -ECOMM;
258d617c426SJan Kloetzke 			}
259d617c426SJan Kloetzke 		} else if (--retries < 0)
260d617c426SJan Kloetzke 			return err;
2615d4fc8d9SRaffaele Recalcati 
2621677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
2631677eef4SAndrew Gabbasov 			break;
2645d4fc8d9SRaffaele Recalcati 
2651677eef4SAndrew Gabbasov 		udelay(1000);
2661677eef4SAndrew Gabbasov 	}
2675d4fc8d9SRaffaele Recalcati 
268c0c76ebaSSimon Glass 	mmc_trace_state(mmc, &cmd);
2695b0c942fSJongman Heo 	if (timeout <= 0) {
27056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2715d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
27256196826SPaul Burton #endif
273915ffa52SJaehoon Chung 		return -ETIMEDOUT;
2745d4fc8d9SRaffaele Recalcati 	}
2755d4fc8d9SRaffaele Recalcati 
2765d4fc8d9SRaffaele Recalcati 	return 0;
2775d4fc8d9SRaffaele Recalcati }
2785d4fc8d9SRaffaele Recalcati 
279da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
280272cc70bSAndy Fleming {
281272cc70bSAndy Fleming 	struct mmc_cmd cmd;
282*83dc4227SKishon Vijay Abraham I 	int err;
283272cc70bSAndy Fleming 
284786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
285d22e3d46SJaehoon Chung 		return 0;
286d22e3d46SJaehoon Chung 
287272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
288272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
289272cc70bSAndy Fleming 	cmd.cmdarg = len;
290272cc70bSAndy Fleming 
291*83dc4227SKishon Vijay Abraham I 	err = mmc_send_cmd(mmc, &cmd, NULL);
292*83dc4227SKishon Vijay Abraham I 
293*83dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
294*83dc4227SKishon Vijay Abraham I 	if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) {
295*83dc4227SKishon Vijay Abraham I 		int retries = 4;
296*83dc4227SKishon Vijay Abraham I 		/*
297*83dc4227SKishon Vijay Abraham I 		 * It has been seen that SET_BLOCKLEN may fail on the first
298*83dc4227SKishon Vijay Abraham I 		 * attempt, let's try a few more time
299*83dc4227SKishon Vijay Abraham I 		 */
300*83dc4227SKishon Vijay Abraham I 		do {
301*83dc4227SKishon Vijay Abraham I 			err = mmc_send_cmd(mmc, &cmd, NULL);
302*83dc4227SKishon Vijay Abraham I 			if (!err)
303*83dc4227SKishon Vijay Abraham I 				break;
304*83dc4227SKishon Vijay Abraham I 		} while (retries--);
305*83dc4227SKishon Vijay Abraham I 	}
306*83dc4227SKishon Vijay Abraham I #endif
307*83dc4227SKishon Vijay Abraham I 
308*83dc4227SKishon Vijay Abraham I 	return err;
309272cc70bSAndy Fleming }
310272cc70bSAndy Fleming 
311ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
312fdbb873eSKim Phillips 			   lbaint_t blkcnt)
313272cc70bSAndy Fleming {
314272cc70bSAndy Fleming 	struct mmc_cmd cmd;
315272cc70bSAndy Fleming 	struct mmc_data data;
316272cc70bSAndy Fleming 
3174a1a06bcSAlagu Sankar 	if (blkcnt > 1)
3184a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
3194a1a06bcSAlagu Sankar 	else
320272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
321272cc70bSAndy Fleming 
322272cc70bSAndy Fleming 	if (mmc->high_capacity)
3234a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
324272cc70bSAndy Fleming 	else
3254a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
326272cc70bSAndy Fleming 
327272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
328272cc70bSAndy Fleming 
329272cc70bSAndy Fleming 	data.dest = dst;
3304a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
331272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
332272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
333272cc70bSAndy Fleming 
3344a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
3354a1a06bcSAlagu Sankar 		return 0;
3364a1a06bcSAlagu Sankar 
3374a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
3384a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
3394a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
3404a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
3414a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
34256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
3434a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
34456196826SPaul Burton #endif
3454a1a06bcSAlagu Sankar 			return 0;
3464a1a06bcSAlagu Sankar 		}
347272cc70bSAndy Fleming 	}
348272cc70bSAndy Fleming 
3494a1a06bcSAlagu Sankar 	return blkcnt;
350272cc70bSAndy Fleming }
351272cc70bSAndy Fleming 
352c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
3537dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
35433fb211dSSimon Glass #else
3557dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
3567dba0b93SSimon Glass 		void *dst)
35733fb211dSSimon Glass #endif
358272cc70bSAndy Fleming {
359c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
36033fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
36133fb211dSSimon Glass #endif
362bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
363873cc1d7SStephen Warren 	int err;
3644a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
365272cc70bSAndy Fleming 
3664a1a06bcSAlagu Sankar 	if (blkcnt == 0)
3674a1a06bcSAlagu Sankar 		return 0;
3684a1a06bcSAlagu Sankar 
3694a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
370272cc70bSAndy Fleming 	if (!mmc)
371272cc70bSAndy Fleming 		return 0;
372272cc70bSAndy Fleming 
373b5b838f1SMarek Vasut 	if (CONFIG_IS_ENABLED(MMC_TINY))
374b5b838f1SMarek Vasut 		err = mmc_switch_part(mmc, block_dev->hwpart);
375b5b838f1SMarek Vasut 	else
37669f45cd5SSimon Glass 		err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
377b5b838f1SMarek Vasut 
378873cc1d7SStephen Warren 	if (err < 0)
379873cc1d7SStephen Warren 		return 0;
380873cc1d7SStephen Warren 
381c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
38256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
383ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
384c40fdca6SSimon Glass 			start + blkcnt, block_dev->lba);
38556196826SPaul Burton #endif
386d2bf29e3SLei Wen 		return 0;
387d2bf29e3SLei Wen 	}
388272cc70bSAndy Fleming 
38911692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
39011692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
391272cc70bSAndy Fleming 		return 0;
39211692991SSimon Glass 	}
393272cc70bSAndy Fleming 
3944a1a06bcSAlagu Sankar 	do {
39593bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
39693bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
39711692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
39811692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
3994a1a06bcSAlagu Sankar 			return 0;
40011692991SSimon Glass 		}
4014a1a06bcSAlagu Sankar 		blocks_todo -= cur;
4024a1a06bcSAlagu Sankar 		start += cur;
4034a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
4044a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
405272cc70bSAndy Fleming 
406272cc70bSAndy Fleming 	return blkcnt;
407272cc70bSAndy Fleming }
408272cc70bSAndy Fleming 
409fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
410272cc70bSAndy Fleming {
411272cc70bSAndy Fleming 	struct mmc_cmd cmd;
412272cc70bSAndy Fleming 	int err;
413272cc70bSAndy Fleming 
414272cc70bSAndy Fleming 	udelay(1000);
415272cc70bSAndy Fleming 
416272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
417272cc70bSAndy Fleming 	cmd.cmdarg = 0;
418272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
419272cc70bSAndy Fleming 
420272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
421272cc70bSAndy Fleming 
422272cc70bSAndy Fleming 	if (err)
423272cc70bSAndy Fleming 		return err;
424272cc70bSAndy Fleming 
425272cc70bSAndy Fleming 	udelay(2000);
426272cc70bSAndy Fleming 
427272cc70bSAndy Fleming 	return 0;
428272cc70bSAndy Fleming }
429272cc70bSAndy Fleming 
430c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage)
431c10b85d6SJean-Jacques Hiblot {
432c10b85d6SJean-Jacques Hiblot 	struct mmc_cmd cmd;
433c10b85d6SJean-Jacques Hiblot 	int err = 0;
434c10b85d6SJean-Jacques Hiblot 
435c10b85d6SJean-Jacques Hiblot 	/*
436c10b85d6SJean-Jacques Hiblot 	 * Send CMD11 only if the request is to switch the card to
437c10b85d6SJean-Jacques Hiblot 	 * 1.8V signalling.
438c10b85d6SJean-Jacques Hiblot 	 */
439c10b85d6SJean-Jacques Hiblot 	if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
440c10b85d6SJean-Jacques Hiblot 		return mmc_set_signal_voltage(mmc, signal_voltage);
441c10b85d6SJean-Jacques Hiblot 
442c10b85d6SJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_SWITCH_UHS18V;
443c10b85d6SJean-Jacques Hiblot 	cmd.cmdarg = 0;
444c10b85d6SJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
445c10b85d6SJean-Jacques Hiblot 
446c10b85d6SJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
447c10b85d6SJean-Jacques Hiblot 	if (err)
448c10b85d6SJean-Jacques Hiblot 		return err;
449c10b85d6SJean-Jacques Hiblot 
450c10b85d6SJean-Jacques Hiblot 	if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR))
451c10b85d6SJean-Jacques Hiblot 		return -EIO;
452c10b85d6SJean-Jacques Hiblot 
453c10b85d6SJean-Jacques Hiblot 	/*
454c10b85d6SJean-Jacques Hiblot 	 * The card should drive cmd and dat[0:3] low immediately
455c10b85d6SJean-Jacques Hiblot 	 * after the response of cmd11, but wait 100 us to be sure
456c10b85d6SJean-Jacques Hiblot 	 */
457c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 0, 100);
458c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
459c10b85d6SJean-Jacques Hiblot 		udelay(100);
460c10b85d6SJean-Jacques Hiblot 	else if (err)
461c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
462c10b85d6SJean-Jacques Hiblot 
463c10b85d6SJean-Jacques Hiblot 	/*
464c10b85d6SJean-Jacques Hiblot 	 * During a signal voltage level switch, the clock must be gated
465c10b85d6SJean-Jacques Hiblot 	 * for 5 ms according to the SD spec
466c10b85d6SJean-Jacques Hiblot 	 */
467c10b85d6SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->clock, true);
468c10b85d6SJean-Jacques Hiblot 
469c10b85d6SJean-Jacques Hiblot 	err = mmc_set_signal_voltage(mmc, signal_voltage);
470c10b85d6SJean-Jacques Hiblot 	if (err)
471c10b85d6SJean-Jacques Hiblot 		return err;
472c10b85d6SJean-Jacques Hiblot 
473c10b85d6SJean-Jacques Hiblot 	/* Keep clock gated for at least 10 ms, though spec only says 5 ms */
474c10b85d6SJean-Jacques Hiblot 	mdelay(10);
475c10b85d6SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->clock, false);
476c10b85d6SJean-Jacques Hiblot 
477c10b85d6SJean-Jacques Hiblot 	/*
478c10b85d6SJean-Jacques Hiblot 	 * Failure to switch is indicated by the card holding
479c10b85d6SJean-Jacques Hiblot 	 * dat[0:3] low. Wait for at least 1 ms according to spec
480c10b85d6SJean-Jacques Hiblot 	 */
481c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 1, 1000);
482c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
483c10b85d6SJean-Jacques Hiblot 		udelay(1000);
484c10b85d6SJean-Jacques Hiblot 	else if (err)
485c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
486c10b85d6SJean-Jacques Hiblot 
487c10b85d6SJean-Jacques Hiblot 	return 0;
488c10b85d6SJean-Jacques Hiblot }
489c10b85d6SJean-Jacques Hiblot 
490c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en)
491272cc70bSAndy Fleming {
492272cc70bSAndy Fleming 	int timeout = 1000;
493272cc70bSAndy Fleming 	int err;
494272cc70bSAndy Fleming 	struct mmc_cmd cmd;
495272cc70bSAndy Fleming 
4961677eef4SAndrew Gabbasov 	while (1) {
497272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
498272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
499272cc70bSAndy Fleming 		cmd.cmdarg = 0;
500272cc70bSAndy Fleming 
501272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
502272cc70bSAndy Fleming 
503272cc70bSAndy Fleming 		if (err)
504272cc70bSAndy Fleming 			return err;
505272cc70bSAndy Fleming 
506272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
507272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
508250de12bSStefano Babic 
509250de12bSStefano Babic 		/*
510250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
511250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
512250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
513250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
514250de12bSStefano Babic 		 * specified.
515250de12bSStefano Babic 		 */
516d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
51793bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
518272cc70bSAndy Fleming 
519272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
520272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
521272cc70bSAndy Fleming 
522c10b85d6SJean-Jacques Hiblot 		if (uhs_en)
523c10b85d6SJean-Jacques Hiblot 			cmd.cmdarg |= OCR_S18R;
524c10b85d6SJean-Jacques Hiblot 
525272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
526272cc70bSAndy Fleming 
527272cc70bSAndy Fleming 		if (err)
528272cc70bSAndy Fleming 			return err;
529272cc70bSAndy Fleming 
5301677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
5311677eef4SAndrew Gabbasov 			break;
532272cc70bSAndy Fleming 
5331677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
534915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
535272cc70bSAndy Fleming 
5361677eef4SAndrew Gabbasov 		udelay(1000);
5371677eef4SAndrew Gabbasov 	}
5381677eef4SAndrew Gabbasov 
539272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
540272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
541272cc70bSAndy Fleming 
542d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
543d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
544d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
545d52ebf10SThomas Chou 		cmd.cmdarg = 0;
546d52ebf10SThomas Chou 
547d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
548d52ebf10SThomas Chou 
549d52ebf10SThomas Chou 		if (err)
550d52ebf10SThomas Chou 			return err;
551d52ebf10SThomas Chou 	}
552d52ebf10SThomas Chou 
553998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
554272cc70bSAndy Fleming 
555c10b85d6SJean-Jacques Hiblot 	if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000)
556c10b85d6SJean-Jacques Hiblot 	    == 0x41000000) {
557c10b85d6SJean-Jacques Hiblot 		err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
558c10b85d6SJean-Jacques Hiblot 		if (err)
559c10b85d6SJean-Jacques Hiblot 			return err;
560c10b85d6SJean-Jacques Hiblot 	}
561c10b85d6SJean-Jacques Hiblot 
562272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
563272cc70bSAndy Fleming 	mmc->rca = 0;
564272cc70bSAndy Fleming 
565272cc70bSAndy Fleming 	return 0;
566272cc70bSAndy Fleming }
567272cc70bSAndy Fleming 
5685289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
569272cc70bSAndy Fleming {
5705289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
571272cc70bSAndy Fleming 	int err;
572272cc70bSAndy Fleming 
5735289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
5745289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
5755289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
5765a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
5775a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
57893bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
579a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
580a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
581e9550449SChe-Liang Chiou 
5825289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
583e9550449SChe-Liang Chiou 	if (err)
584e9550449SChe-Liang Chiou 		return err;
5855289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
586e9550449SChe-Liang Chiou 	return 0;
587e9550449SChe-Liang Chiou }
588e9550449SChe-Liang Chiou 
589750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
590e9550449SChe-Liang Chiou {
591e9550449SChe-Liang Chiou 	int err, i;
592e9550449SChe-Liang Chiou 
593272cc70bSAndy Fleming 	/* Some cards seem to need this */
594272cc70bSAndy Fleming 	mmc_go_idle(mmc);
595272cc70bSAndy Fleming 
59631cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
597e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
5985289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
59931cacbabSRaffaele Recalcati 		if (err)
60031cacbabSRaffaele Recalcati 			return err;
60131cacbabSRaffaele Recalcati 
602e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
603a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
604bd47c135SAndrew Gabbasov 			break;
605e9550449SChe-Liang Chiou 	}
606bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
607bd47c135SAndrew Gabbasov 	return 0;
608e9550449SChe-Liang Chiou }
60931cacbabSRaffaele Recalcati 
610750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
611e9550449SChe-Liang Chiou {
612e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
613e9550449SChe-Liang Chiou 	int timeout = 1000;
614e9550449SChe-Liang Chiou 	uint start;
615e9550449SChe-Liang Chiou 	int err;
616e9550449SChe-Liang Chiou 
617e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
618cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
619d188b113SYangbo Lu 		/* Some cards seem to need this */
620d188b113SYangbo Lu 		mmc_go_idle(mmc);
621d188b113SYangbo Lu 
622e9550449SChe-Liang Chiou 		start = get_timer(0);
6231677eef4SAndrew Gabbasov 		while (1) {
6245289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
625272cc70bSAndy Fleming 			if (err)
626272cc70bSAndy Fleming 				return err;
6271677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
6281677eef4SAndrew Gabbasov 				break;
629e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
630915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
631e9550449SChe-Liang Chiou 			udelay(100);
6321677eef4SAndrew Gabbasov 		}
633cc17c01fSAndrew Gabbasov 	}
634272cc70bSAndy Fleming 
635d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
636d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
637d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
638d52ebf10SThomas Chou 		cmd.cmdarg = 0;
639d52ebf10SThomas Chou 
640d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
641d52ebf10SThomas Chou 
642d52ebf10SThomas Chou 		if (err)
643d52ebf10SThomas Chou 			return err;
644a626c8d4SAndrew Gabbasov 
645a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
646d52ebf10SThomas Chou 	}
647d52ebf10SThomas Chou 
648272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
649272cc70bSAndy Fleming 
650272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
651def816a2SStephen Warren 	mmc->rca = 1;
652272cc70bSAndy Fleming 
653272cc70bSAndy Fleming 	return 0;
654272cc70bSAndy Fleming }
655272cc70bSAndy Fleming 
656272cc70bSAndy Fleming 
657fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
658272cc70bSAndy Fleming {
659272cc70bSAndy Fleming 	struct mmc_cmd cmd;
660272cc70bSAndy Fleming 	struct mmc_data data;
661272cc70bSAndy Fleming 	int err;
662272cc70bSAndy Fleming 
663272cc70bSAndy Fleming 	/* Get the Card Status Register */
664272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
665272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
666272cc70bSAndy Fleming 	cmd.cmdarg = 0;
667272cc70bSAndy Fleming 
668cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
669272cc70bSAndy Fleming 	data.blocks = 1;
6708bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
671272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
672272cc70bSAndy Fleming 
673272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
674272cc70bSAndy Fleming 
675272cc70bSAndy Fleming 	return err;
676272cc70bSAndy Fleming }
677272cc70bSAndy Fleming 
678c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
679272cc70bSAndy Fleming {
680272cc70bSAndy Fleming 	struct mmc_cmd cmd;
6815d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
682a9003dc6SMaxime Ripard 	int retries = 3;
6835d4fc8d9SRaffaele Recalcati 	int ret;
684272cc70bSAndy Fleming 
685272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
686272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
687272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
688272cc70bSAndy Fleming 				 (index << 16) |
689272cc70bSAndy Fleming 				 (value << 8);
690272cc70bSAndy Fleming 
691a9003dc6SMaxime Ripard 	while (retries > 0) {
6925d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
6935d4fc8d9SRaffaele Recalcati 
6945d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
695a9003dc6SMaxime Ripard 		if (!ret) {
69693ad0d18SJan Kloetzke 			ret = mmc_send_status(mmc, timeout);
697a9003dc6SMaxime Ripard 			return ret;
698a9003dc6SMaxime Ripard 		}
699a9003dc6SMaxime Ripard 
700a9003dc6SMaxime Ripard 		retries--;
701a9003dc6SMaxime Ripard 	}
7025d4fc8d9SRaffaele Recalcati 
7035d4fc8d9SRaffaele Recalcati 	return ret;
7045d4fc8d9SRaffaele Recalcati 
705272cc70bSAndy Fleming }
706272cc70bSAndy Fleming 
7073862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
708272cc70bSAndy Fleming {
709272cc70bSAndy Fleming 	int err;
7103862b854SJean-Jacques Hiblot 	int speed_bits;
7113862b854SJean-Jacques Hiblot 
7123862b854SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
7133862b854SJean-Jacques Hiblot 
7143862b854SJean-Jacques Hiblot 	switch (mode) {
7153862b854SJean-Jacques Hiblot 	case MMC_HS:
7163862b854SJean-Jacques Hiblot 	case MMC_HS_52:
7173862b854SJean-Jacques Hiblot 	case MMC_DDR_52:
7183862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_HS;
719634d4849SKishon Vijay Abraham I 		break;
720634d4849SKishon Vijay Abraham I 	case MMC_HS_200:
721634d4849SKishon Vijay Abraham I 		speed_bits = EXT_CSD_TIMING_HS200;
722634d4849SKishon Vijay Abraham I 		break;
7233862b854SJean-Jacques Hiblot 	case MMC_LEGACY:
7243862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_LEGACY;
7253862b854SJean-Jacques Hiblot 		break;
7263862b854SJean-Jacques Hiblot 	default:
7273862b854SJean-Jacques Hiblot 		return -EINVAL;
7283862b854SJean-Jacques Hiblot 	}
7293862b854SJean-Jacques Hiblot 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
7303862b854SJean-Jacques Hiblot 			 speed_bits);
7313862b854SJean-Jacques Hiblot 	if (err)
7323862b854SJean-Jacques Hiblot 		return err;
7333862b854SJean-Jacques Hiblot 
7343862b854SJean-Jacques Hiblot 	if ((mode == MMC_HS) || (mode == MMC_HS_52)) {
7353862b854SJean-Jacques Hiblot 		/* Now check to see that it worked */
7363862b854SJean-Jacques Hiblot 		err = mmc_send_ext_csd(mmc, test_csd);
7373862b854SJean-Jacques Hiblot 		if (err)
7383862b854SJean-Jacques Hiblot 			return err;
7393862b854SJean-Jacques Hiblot 
7403862b854SJean-Jacques Hiblot 		/* No high-speed support */
7413862b854SJean-Jacques Hiblot 		if (!test_csd[EXT_CSD_HS_TIMING])
7423862b854SJean-Jacques Hiblot 			return -ENOTSUPP;
7433862b854SJean-Jacques Hiblot 	}
7443862b854SJean-Jacques Hiblot 
7453862b854SJean-Jacques Hiblot 	return 0;
7463862b854SJean-Jacques Hiblot }
7473862b854SJean-Jacques Hiblot 
7483862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc)
7493862b854SJean-Jacques Hiblot {
7503862b854SJean-Jacques Hiblot 	u8 *ext_csd = mmc->ext_csd;
7513862b854SJean-Jacques Hiblot 	char cardtype;
752272cc70bSAndy Fleming 
753d0c221feSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT;
754272cc70bSAndy Fleming 
755d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
756d52ebf10SThomas Chou 		return 0;
757d52ebf10SThomas Chou 
758272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
759272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
760272cc70bSAndy Fleming 		return 0;
761272cc70bSAndy Fleming 
7623862b854SJean-Jacques Hiblot 	if (!ext_csd) {
7633862b854SJean-Jacques Hiblot 		printf("No ext_csd found!\n"); /* this should enver happen */
7643862b854SJean-Jacques Hiblot 		return -ENOTSUPP;
7653862b854SJean-Jacques Hiblot 	}
7663862b854SJean-Jacques Hiblot 
767fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
768fc5b32fbSAndrew Gabbasov 
769634d4849SKishon Vijay Abraham I 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
770272cc70bSAndy Fleming 
771634d4849SKishon Vijay Abraham I 	if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
772634d4849SKishon Vijay Abraham I 			EXT_CSD_CARD_TYPE_HS200_1_8V)) {
773634d4849SKishon Vijay Abraham I 		mmc->card_caps |= MMC_MODE_HS200;
774634d4849SKishon Vijay Abraham I 	}
775d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
7763862b854SJean-Jacques Hiblot 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
777d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
7783862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS_52MHz;
779d22e3d46SJaehoon Chung 	}
7803862b854SJean-Jacques Hiblot 	if (cardtype & EXT_CSD_CARD_TYPE_26)
7813862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS;
782272cc70bSAndy Fleming 
783272cc70bSAndy Fleming 	return 0;
784272cc70bSAndy Fleming }
785272cc70bSAndy Fleming 
786f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
787f866a46dSStephen Warren {
788f866a46dSStephen Warren 	switch (part_num) {
789f866a46dSStephen Warren 	case 0:
790f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
791f866a46dSStephen Warren 		break;
792f866a46dSStephen Warren 	case 1:
793f866a46dSStephen Warren 	case 2:
794f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
795f866a46dSStephen Warren 		break;
796f866a46dSStephen Warren 	case 3:
797f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
798f866a46dSStephen Warren 		break;
799f866a46dSStephen Warren 	case 4:
800f866a46dSStephen Warren 	case 5:
801f866a46dSStephen Warren 	case 6:
802f866a46dSStephen Warren 	case 7:
803f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
804f866a46dSStephen Warren 		break;
805f866a46dSStephen Warren 	default:
806f866a46dSStephen Warren 		return -1;
807f866a46dSStephen Warren 	}
808f866a46dSStephen Warren 
809c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
810f866a46dSStephen Warren 
811f866a46dSStephen Warren 	return 0;
812f866a46dSStephen Warren }
813f866a46dSStephen Warren 
81401298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num)
81501298da3SJean-Jacques Hiblot {
81601298da3SJean-Jacques Hiblot 	int forbidden = 0;
81701298da3SJean-Jacques Hiblot 	bool change = false;
81801298da3SJean-Jacques Hiblot 
81901298da3SJean-Jacques Hiblot 	if (part_num & PART_ACCESS_MASK)
82001298da3SJean-Jacques Hiblot 		forbidden = MMC_CAP(MMC_HS_200);
82101298da3SJean-Jacques Hiblot 
82201298da3SJean-Jacques Hiblot 	if (MMC_CAP(mmc->selected_mode) & forbidden) {
82301298da3SJean-Jacques Hiblot 		debug("selected mode (%s) is forbidden for part %d\n",
82401298da3SJean-Jacques Hiblot 		      mmc_mode_name(mmc->selected_mode), part_num);
82501298da3SJean-Jacques Hiblot 		change = true;
82601298da3SJean-Jacques Hiblot 	} else if (mmc->selected_mode != mmc->best_mode) {
82701298da3SJean-Jacques Hiblot 		debug("selected mode is not optimal\n");
82801298da3SJean-Jacques Hiblot 		change = true;
82901298da3SJean-Jacques Hiblot 	}
83001298da3SJean-Jacques Hiblot 
83101298da3SJean-Jacques Hiblot 	if (change)
83201298da3SJean-Jacques Hiblot 		return mmc_select_mode_and_width(mmc,
83301298da3SJean-Jacques Hiblot 						 mmc->card_caps & ~forbidden);
83401298da3SJean-Jacques Hiblot 
83501298da3SJean-Jacques Hiblot 	return 0;
83601298da3SJean-Jacques Hiblot }
83701298da3SJean-Jacques Hiblot 
8387dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
839bc897b1dSLei Wen {
840f866a46dSStephen Warren 	int ret;
841bc897b1dSLei Wen 
84201298da3SJean-Jacques Hiblot 	ret = mmc_boot_part_access_chk(mmc, part_num);
84301298da3SJean-Jacques Hiblot 	if (ret)
84401298da3SJean-Jacques Hiblot 		return ret;
84501298da3SJean-Jacques Hiblot 
846f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
847bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
848bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
849f866a46dSStephen Warren 
8506dc93e70SPeter Bigot 	/*
8516dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
8526dc93e70SPeter Bigot 	 * to return to representing the raw device.
8536dc93e70SPeter Bigot 	 */
854873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
8556dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
856fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
857873cc1d7SStephen Warren 	}
8586dc93e70SPeter Bigot 
8596dc93e70SPeter Bigot 	return ret;
860bc897b1dSLei Wen }
861bc897b1dSLei Wen 
862ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
863ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
864ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
865ac9da0e0SDiego Santa Cruz {
866ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
867ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
868ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
869ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
870ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
871ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
8728dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
873ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
874ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
875ac9da0e0SDiego Santa Cruz 
876ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
877ac9da0e0SDiego Santa Cruz 		return -EINVAL;
878ac9da0e0SDiego Santa Cruz 
879ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
880ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
881ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
882ac9da0e0SDiego Santa Cruz 	}
883ac9da0e0SDiego Santa Cruz 
884ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
885ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
886ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
887ac9da0e0SDiego Santa Cruz 	}
888ac9da0e0SDiego Santa Cruz 
889ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
890ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
891ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
892ac9da0e0SDiego Santa Cruz 	}
893ac9da0e0SDiego Santa Cruz 
894ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
895ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
896ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
897ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
898ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
899ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
900ac9da0e0SDiego Santa Cruz 			return -EINVAL;
901ac9da0e0SDiego Santa Cruz 		}
902ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
903ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
904ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
905ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
906ac9da0e0SDiego Santa Cruz 		} else {
907ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
908ac9da0e0SDiego Santa Cruz 		}
909ac9da0e0SDiego Santa Cruz 	} else {
910ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
911ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
912ac9da0e0SDiego Santa Cruz 	}
913ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
914ac9da0e0SDiego Santa Cruz 
915ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
916ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
917ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
918ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
919ac9da0e0SDiego Santa Cruz 			return -EINVAL;
920ac9da0e0SDiego Santa Cruz 		}
921ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
922ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
923ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
924ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
925ac9da0e0SDiego Santa Cruz 		}
926ac9da0e0SDiego Santa Cruz 	}
927ac9da0e0SDiego Santa Cruz 
928ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
929ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
930ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
931ac9da0e0SDiego Santa Cruz 	}
932ac9da0e0SDiego Santa Cruz 
933ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
934ac9da0e0SDiego Santa Cruz 	if (err)
935ac9da0e0SDiego Santa Cruz 		return err;
936ac9da0e0SDiego Santa Cruz 
937ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
938ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
939ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
940ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
941ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
942ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
943ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
944ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
945ac9da0e0SDiego Santa Cruz 	}
946ac9da0e0SDiego Santa Cruz 
9478dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
9488dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
9498dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
9508dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
9518dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
9528dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
9538dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
9548dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
9558dda5b0eSDiego Santa Cruz 		else
9568dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
9578dda5b0eSDiego Santa Cruz 	}
9588dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
9598dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
9608dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
9618dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
9628dda5b0eSDiego Santa Cruz 			else
9638dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
9648dda5b0eSDiego Santa Cruz 		}
9658dda5b0eSDiego Santa Cruz 	}
9668dda5b0eSDiego Santa Cruz 
9678dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
9688dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
9698dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
9708dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
9718dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
9728dda5b0eSDiego Santa Cruz 	}
9738dda5b0eSDiego Santa Cruz 
974ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
975ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
976ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
977ac9da0e0SDiego Santa Cruz 		return -EPERM;
978ac9da0e0SDiego Santa Cruz 	}
979ac9da0e0SDiego Santa Cruz 
980ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
981ac9da0e0SDiego Santa Cruz 		return 0;
982ac9da0e0SDiego Santa Cruz 
983ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
984ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
985ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
986ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
987ac9da0e0SDiego Santa Cruz 
988ac9da0e0SDiego Santa Cruz 		if (err)
989ac9da0e0SDiego Santa Cruz 			return err;
990ac9da0e0SDiego Santa Cruz 
991ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
992ac9da0e0SDiego Santa Cruz 
993ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
994ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
995ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
996ac9da0e0SDiego Santa Cruz 
997ac9da0e0SDiego Santa Cruz 	}
998ac9da0e0SDiego Santa Cruz 
999ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
1000ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
1001ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1002ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
1003ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
1004ac9da0e0SDiego Santa Cruz 		if (err)
1005ac9da0e0SDiego Santa Cruz 			return err;
1006ac9da0e0SDiego Santa Cruz 	}
1007ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
1008ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1009ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
1010ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
1011ac9da0e0SDiego Santa Cruz 		if (err)
1012ac9da0e0SDiego Santa Cruz 			return err;
1013ac9da0e0SDiego Santa Cruz 	}
1014ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1015ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
1016ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1017ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
1018ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
1019ac9da0e0SDiego Santa Cruz 			if (err)
1020ac9da0e0SDiego Santa Cruz 				return err;
1021ac9da0e0SDiego Santa Cruz 		}
1022ac9da0e0SDiego Santa Cruz 	}
1023ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1024ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
1025ac9da0e0SDiego Santa Cruz 	if (err)
1026ac9da0e0SDiego Santa Cruz 		return err;
1027ac9da0e0SDiego Santa Cruz 
1028ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
1029ac9da0e0SDiego Santa Cruz 		return 0;
1030ac9da0e0SDiego Santa Cruz 
10318dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
10328dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
10338dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
10348dda5b0eSDiego Santa Cruz 	 * partitioning. */
10358dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
10368dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
10378dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
10388dda5b0eSDiego Santa Cruz 		if (err)
10398dda5b0eSDiego Santa Cruz 			return err;
10408dda5b0eSDiego Santa Cruz 	}
10418dda5b0eSDiego Santa Cruz 
1042ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
1043ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
1044ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
1045ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
1046ac9da0e0SDiego Santa Cruz 
1047ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1048ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
1049ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
1050ac9da0e0SDiego Santa Cruz 	if (err)
1051ac9da0e0SDiego Santa Cruz 		return err;
1052ac9da0e0SDiego Santa Cruz 
1053ac9da0e0SDiego Santa Cruz 	return 0;
1054ac9da0e0SDiego Santa Cruz }
1055ac9da0e0SDiego Santa Cruz 
1056e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
105748972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
105848972d90SThierry Reding {
105948972d90SThierry Reding 	int cd;
106048972d90SThierry Reding 
106148972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
106248972d90SThierry Reding 
1063d4e1da4eSPeter Korsgaard 	if (cd < 0) {
106493bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
106593bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
1066d4e1da4eSPeter Korsgaard 		else
1067d4e1da4eSPeter Korsgaard 			cd = 1;
1068d4e1da4eSPeter Korsgaard 	}
106948972d90SThierry Reding 
107048972d90SThierry Reding 	return cd;
107148972d90SThierry Reding }
10728ca51e51SSimon Glass #endif
107348972d90SThierry Reding 
1074fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
1075272cc70bSAndy Fleming {
1076272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1077272cc70bSAndy Fleming 	struct mmc_data data;
1078272cc70bSAndy Fleming 
1079272cc70bSAndy Fleming 	/* Switch the frequency */
1080272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
1081272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1082272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
1083272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
1084272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
1085272cc70bSAndy Fleming 
1086272cc70bSAndy Fleming 	data.dest = (char *)resp;
1087272cc70bSAndy Fleming 	data.blocksize = 64;
1088272cc70bSAndy Fleming 	data.blocks = 1;
1089272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1090272cc70bSAndy Fleming 
1091272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
1092272cc70bSAndy Fleming }
1093272cc70bSAndy Fleming 
1094272cc70bSAndy Fleming 
1095d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc)
1096272cc70bSAndy Fleming {
1097272cc70bSAndy Fleming 	int err;
1098272cc70bSAndy Fleming 	struct mmc_cmd cmd;
109918e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
110018e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
1101272cc70bSAndy Fleming 	struct mmc_data data;
1102272cc70bSAndy Fleming 	int timeout;
1103c10b85d6SJean-Jacques Hiblot 	u32 sd3_bus_mode;
1104272cc70bSAndy Fleming 
1105d0c221feSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT;
1106272cc70bSAndy Fleming 
1107d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
1108d52ebf10SThomas Chou 		return 0;
1109d52ebf10SThomas Chou 
1110272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
1111272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
1112272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1113272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1114272cc70bSAndy Fleming 
1115272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1116272cc70bSAndy Fleming 
1117272cc70bSAndy Fleming 	if (err)
1118272cc70bSAndy Fleming 		return err;
1119272cc70bSAndy Fleming 
1120272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
1121272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1122272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1123272cc70bSAndy Fleming 
1124272cc70bSAndy Fleming 	timeout = 3;
1125272cc70bSAndy Fleming 
1126272cc70bSAndy Fleming retry_scr:
1127f781dd38SAnton staaf 	data.dest = (char *)scr;
1128272cc70bSAndy Fleming 	data.blocksize = 8;
1129272cc70bSAndy Fleming 	data.blocks = 1;
1130272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1131272cc70bSAndy Fleming 
1132272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
1133272cc70bSAndy Fleming 
1134272cc70bSAndy Fleming 	if (err) {
1135272cc70bSAndy Fleming 		if (timeout--)
1136272cc70bSAndy Fleming 			goto retry_scr;
1137272cc70bSAndy Fleming 
1138272cc70bSAndy Fleming 		return err;
1139272cc70bSAndy Fleming 	}
1140272cc70bSAndy Fleming 
11414e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
11424e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
1143272cc70bSAndy Fleming 
1144272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
1145272cc70bSAndy Fleming 	case 0:
1146272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1147272cc70bSAndy Fleming 		break;
1148272cc70bSAndy Fleming 	case 1:
1149272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
1150272cc70bSAndy Fleming 		break;
1151272cc70bSAndy Fleming 	case 2:
1152272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
11531741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
11541741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
1155272cc70bSAndy Fleming 		break;
1156272cc70bSAndy Fleming 	default:
1157272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1158272cc70bSAndy Fleming 		break;
1159272cc70bSAndy Fleming 	}
1160272cc70bSAndy Fleming 
1161b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1162b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1163b44c7083SAlagu Sankar 
1164272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1165272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1166272cc70bSAndy Fleming 		return 0;
1167272cc70bSAndy Fleming 
1168272cc70bSAndy Fleming 	timeout = 4;
1169272cc70bSAndy Fleming 	while (timeout--) {
1170272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1171f781dd38SAnton staaf 				(u8 *)switch_status);
1172272cc70bSAndy Fleming 
1173272cc70bSAndy Fleming 		if (err)
1174272cc70bSAndy Fleming 			return err;
1175272cc70bSAndy Fleming 
1176272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
11774e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1178272cc70bSAndy Fleming 			break;
1179272cc70bSAndy Fleming 	}
1180272cc70bSAndy Fleming 
1181272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
1182d0c221feSJean-Jacques Hiblot 	if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
1183d0c221feSJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(SD_HS);
1184272cc70bSAndy Fleming 
1185c10b85d6SJean-Jacques Hiblot 	/* Version before 3.0 don't support UHS modes */
1186c10b85d6SJean-Jacques Hiblot 	if (mmc->version < SD_VERSION_3)
1187c10b85d6SJean-Jacques Hiblot 		return 0;
1188c10b85d6SJean-Jacques Hiblot 
1189c10b85d6SJean-Jacques Hiblot 	sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f;
1190c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR104)
1191c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR104);
1192c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR50)
1193c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR50);
1194c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR25)
1195c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR25);
1196c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR12)
1197c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR12);
1198c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_DDR50)
1199c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_DDR50);
1200c10b85d6SJean-Jacques Hiblot 
12012c3fbf4cSMacpaul Lin 	return 0;
1202d0c221feSJean-Jacques Hiblot }
1203d0c221feSJean-Jacques Hiblot 
1204d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
1205d0c221feSJean-Jacques Hiblot {
1206d0c221feSJean-Jacques Hiblot 	int err;
1207d0c221feSJean-Jacques Hiblot 
1208d0c221feSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
1209c10b85d6SJean-Jacques Hiblot 	int speed;
12102c3fbf4cSMacpaul Lin 
1211c10b85d6SJean-Jacques Hiblot 	switch (mode) {
1212c10b85d6SJean-Jacques Hiblot 	case SD_LEGACY:
1213c10b85d6SJean-Jacques Hiblot 	case UHS_SDR12:
1214c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR12_BUS_SPEED;
1215c10b85d6SJean-Jacques Hiblot 		break;
1216c10b85d6SJean-Jacques Hiblot 	case SD_HS:
1217c10b85d6SJean-Jacques Hiblot 	case UHS_SDR25:
1218c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR25_BUS_SPEED;
1219c10b85d6SJean-Jacques Hiblot 		break;
1220c10b85d6SJean-Jacques Hiblot 	case UHS_SDR50:
1221c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR50_BUS_SPEED;
1222c10b85d6SJean-Jacques Hiblot 		break;
1223c10b85d6SJean-Jacques Hiblot 	case UHS_DDR50:
1224c10b85d6SJean-Jacques Hiblot 		speed = UHS_DDR50_BUS_SPEED;
1225c10b85d6SJean-Jacques Hiblot 		break;
1226c10b85d6SJean-Jacques Hiblot 	case UHS_SDR104:
1227c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR104_BUS_SPEED;
1228c10b85d6SJean-Jacques Hiblot 		break;
1229c10b85d6SJean-Jacques Hiblot 	default:
1230c10b85d6SJean-Jacques Hiblot 		return -EINVAL;
1231c10b85d6SJean-Jacques Hiblot 	}
1232c10b85d6SJean-Jacques Hiblot 
1233c10b85d6SJean-Jacques Hiblot 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status);
1234272cc70bSAndy Fleming 	if (err)
1235272cc70bSAndy Fleming 		return err;
1236272cc70bSAndy Fleming 
1237c10b85d6SJean-Jacques Hiblot 	if ((__be32_to_cpu(switch_status[4]) >> 24) != speed)
1238d0c221feSJean-Jacques Hiblot 		return -ENOTSUPP;
1239d0c221feSJean-Jacques Hiblot 
1240d0c221feSJean-Jacques Hiblot 	return 0;
1241d0c221feSJean-Jacques Hiblot }
1242d0c221feSJean-Jacques Hiblot 
1243d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w)
1244d0c221feSJean-Jacques Hiblot {
1245d0c221feSJean-Jacques Hiblot 	int err;
1246d0c221feSJean-Jacques Hiblot 	struct mmc_cmd cmd;
1247d0c221feSJean-Jacques Hiblot 
1248d0c221feSJean-Jacques Hiblot 	if ((w != 4) && (w != 1))
1249d0c221feSJean-Jacques Hiblot 		return -EINVAL;
1250d0c221feSJean-Jacques Hiblot 
1251d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = MMC_CMD_APP_CMD;
1252d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1253d0c221feSJean-Jacques Hiblot 	cmd.cmdarg = mmc->rca << 16;
1254d0c221feSJean-Jacques Hiblot 
1255d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1256d0c221feSJean-Jacques Hiblot 	if (err)
1257d0c221feSJean-Jacques Hiblot 		return err;
1258d0c221feSJean-Jacques Hiblot 
1259d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1260d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1261d0c221feSJean-Jacques Hiblot 	if (w == 4)
1262d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 2;
1263d0c221feSJean-Jacques Hiblot 	else if (w == 1)
1264d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 0;
1265d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1266d0c221feSJean-Jacques Hiblot 	if (err)
1267d0c221feSJean-Jacques Hiblot 		return err;
1268272cc70bSAndy Fleming 
1269272cc70bSAndy Fleming 	return 0;
1270272cc70bSAndy Fleming }
1271272cc70bSAndy Fleming 
12723697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
12733697e599SPeng Fan {
12743697e599SPeng Fan 	int err, i;
12753697e599SPeng Fan 	struct mmc_cmd cmd;
12763697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
12773697e599SPeng Fan 	struct mmc_data data;
12783697e599SPeng Fan 	int timeout = 3;
12793697e599SPeng Fan 	unsigned int au, eo, et, es;
12803697e599SPeng Fan 
12813697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
12823697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
12833697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
12843697e599SPeng Fan 
12853697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
12863697e599SPeng Fan 	if (err)
12873697e599SPeng Fan 		return err;
12883697e599SPeng Fan 
12893697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
12903697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
12913697e599SPeng Fan 	cmd.cmdarg = 0;
12923697e599SPeng Fan 
12933697e599SPeng Fan retry_ssr:
12943697e599SPeng Fan 	data.dest = (char *)ssr;
12953697e599SPeng Fan 	data.blocksize = 64;
12963697e599SPeng Fan 	data.blocks = 1;
12973697e599SPeng Fan 	data.flags = MMC_DATA_READ;
12983697e599SPeng Fan 
12993697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
13003697e599SPeng Fan 	if (err) {
13013697e599SPeng Fan 		if (timeout--)
13023697e599SPeng Fan 			goto retry_ssr;
13033697e599SPeng Fan 
13043697e599SPeng Fan 		return err;
13053697e599SPeng Fan 	}
13063697e599SPeng Fan 
13073697e599SPeng Fan 	for (i = 0; i < 16; i++)
13083697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
13093697e599SPeng Fan 
13103697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
13113697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
13123697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
13133697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
13143697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
13153697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
13163697e599SPeng Fan 		if (es && et) {
13173697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
13183697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
13193697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
13203697e599SPeng Fan 		}
13213697e599SPeng Fan 	} else {
13223697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
13233697e599SPeng Fan 	}
13243697e599SPeng Fan 
13253697e599SPeng Fan 	return 0;
13263697e599SPeng Fan }
13273697e599SPeng Fan 
1328272cc70bSAndy Fleming /* frequency bases */
1329272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
13305f837c2cSMike Frysinger static const int fbase[] = {
1331272cc70bSAndy Fleming 	10000,
1332272cc70bSAndy Fleming 	100000,
1333272cc70bSAndy Fleming 	1000000,
1334272cc70bSAndy Fleming 	10000000,
1335272cc70bSAndy Fleming };
1336272cc70bSAndy Fleming 
1337272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1338272cc70bSAndy Fleming  * to platforms without floating point.
1339272cc70bSAndy Fleming  */
134061fe076fSSimon Glass static const u8 multipliers[] = {
1341272cc70bSAndy Fleming 	0,	/* reserved */
1342272cc70bSAndy Fleming 	10,
1343272cc70bSAndy Fleming 	12,
1344272cc70bSAndy Fleming 	13,
1345272cc70bSAndy Fleming 	15,
1346272cc70bSAndy Fleming 	20,
1347272cc70bSAndy Fleming 	25,
1348272cc70bSAndy Fleming 	30,
1349272cc70bSAndy Fleming 	35,
1350272cc70bSAndy Fleming 	40,
1351272cc70bSAndy Fleming 	45,
1352272cc70bSAndy Fleming 	50,
1353272cc70bSAndy Fleming 	55,
1354272cc70bSAndy Fleming 	60,
1355272cc70bSAndy Fleming 	70,
1356272cc70bSAndy Fleming 	80,
1357272cc70bSAndy Fleming };
1358272cc70bSAndy Fleming 
1359d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap)
1360d0c221feSJean-Jacques Hiblot {
1361d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_8BIT)
1362d0c221feSJean-Jacques Hiblot 		return 8;
1363d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_4BIT)
1364d0c221feSJean-Jacques Hiblot 		return 4;
1365d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_1BIT)
1366d0c221feSJean-Jacques Hiblot 		return 1;
1367d0c221feSJean-Jacques Hiblot 	printf("invalid bus witdh capability 0x%x\n", cap);
1368d0c221feSJean-Jacques Hiblot 	return 0;
1369d0c221feSJean-Jacques Hiblot }
1370d0c221feSJean-Jacques Hiblot 
1371e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1372ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode)
1373ec841209SKishon Vijay Abraham I {
1374ec841209SKishon Vijay Abraham I 	return -ENOTSUPP;
1375ec841209SKishon Vijay Abraham I }
1376ec841209SKishon Vijay Abraham I 
1377318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc)
1378318a7a57SJean-Jacques Hiblot {
1379318a7a57SJean-Jacques Hiblot }
1380318a7a57SJean-Jacques Hiblot 
13812a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc)
1382272cc70bSAndy Fleming {
13832a4d212fSKishon Vijay Abraham I 	int ret = 0;
13842a4d212fSKishon Vijay Abraham I 
138593bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
13862a4d212fSKishon Vijay Abraham I 		ret = mmc->cfg->ops->set_ios(mmc);
13872a4d212fSKishon Vijay Abraham I 
13882a4d212fSKishon Vijay Abraham I 	return ret;
1389272cc70bSAndy Fleming }
13908ca51e51SSimon Glass #endif
1391272cc70bSAndy Fleming 
139235f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable)
1393272cc70bSAndy Fleming {
139493bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
139593bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1396272cc70bSAndy Fleming 
139793bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
139893bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1399272cc70bSAndy Fleming 
1400272cc70bSAndy Fleming 	mmc->clock = clock;
140135f67820SKishon Vijay Abraham I 	mmc->clk_disable = disable;
1402272cc70bSAndy Fleming 
14032a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1404272cc70bSAndy Fleming }
1405272cc70bSAndy Fleming 
14062a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width)
1407272cc70bSAndy Fleming {
1408272cc70bSAndy Fleming 	mmc->bus_width = width;
1409272cc70bSAndy Fleming 
14102a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1411272cc70bSAndy Fleming }
1412272cc70bSAndy Fleming 
14134c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
14144c9d2aaaSJean-Jacques Hiblot /*
14154c9d2aaaSJean-Jacques Hiblot  * helper function to display the capabilities in a human
14164c9d2aaaSJean-Jacques Hiblot  * friendly manner. The capabilities include bus width and
14174c9d2aaaSJean-Jacques Hiblot  * supported modes.
14184c9d2aaaSJean-Jacques Hiblot  */
14194c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps)
14204c9d2aaaSJean-Jacques Hiblot {
14214c9d2aaaSJean-Jacques Hiblot 	enum bus_mode mode;
14224c9d2aaaSJean-Jacques Hiblot 
14234c9d2aaaSJean-Jacques Hiblot 	printf("%s: widths [", text);
14244c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_8BIT)
14254c9d2aaaSJean-Jacques Hiblot 		printf("8, ");
14264c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_4BIT)
14274c9d2aaaSJean-Jacques Hiblot 		printf("4, ");
1428d0c221feSJean-Jacques Hiblot 	if (caps & MMC_MODE_1BIT)
1429d0c221feSJean-Jacques Hiblot 		printf("1, ");
1430d0c221feSJean-Jacques Hiblot 	printf("\b\b] modes [");
14314c9d2aaaSJean-Jacques Hiblot 	for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
14324c9d2aaaSJean-Jacques Hiblot 		if (MMC_CAP(mode) & caps)
14334c9d2aaaSJean-Jacques Hiblot 			printf("%s, ", mmc_mode_name(mode));
14344c9d2aaaSJean-Jacques Hiblot 	printf("\b\b]\n");
14354c9d2aaaSJean-Jacques Hiblot }
14364c9d2aaaSJean-Jacques Hiblot #endif
14374c9d2aaaSJean-Jacques Hiblot 
1438d0c221feSJean-Jacques Hiblot struct mode_width_tuning {
1439d0c221feSJean-Jacques Hiblot 	enum bus_mode mode;
1440d0c221feSJean-Jacques Hiblot 	uint widths;
1441634d4849SKishon Vijay Abraham I 	uint tuning;
1442d0c221feSJean-Jacques Hiblot };
1443d0c221feSJean-Jacques Hiblot 
1444aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1445aff5d3c8SKishon Vijay Abraham I {
1446aff5d3c8SKishon Vijay Abraham I 	mmc->signal_voltage = signal_voltage;
1447aff5d3c8SKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1448aff5d3c8SKishon Vijay Abraham I }
1449aff5d3c8SKishon Vijay Abraham I 
1450d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = {
1451d0c221feSJean-Jacques Hiblot 	{
1452c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR104,
1453c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1454c10b85d6SJean-Jacques Hiblot 		.tuning = MMC_CMD_SEND_TUNING_BLOCK
1455c10b85d6SJean-Jacques Hiblot 	},
1456c10b85d6SJean-Jacques Hiblot 	{
1457c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR50,
1458c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1459c10b85d6SJean-Jacques Hiblot 	},
1460c10b85d6SJean-Jacques Hiblot 	{
1461c10b85d6SJean-Jacques Hiblot 		.mode = UHS_DDR50,
1462c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1463c10b85d6SJean-Jacques Hiblot 	},
1464c10b85d6SJean-Jacques Hiblot 	{
1465c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR25,
1466c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1467c10b85d6SJean-Jacques Hiblot 	},
1468c10b85d6SJean-Jacques Hiblot 	{
1469d0c221feSJean-Jacques Hiblot 		.mode = SD_HS,
1470d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1471d0c221feSJean-Jacques Hiblot 	},
1472d0c221feSJean-Jacques Hiblot 	{
1473c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR12,
1474c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1475c10b85d6SJean-Jacques Hiblot 	},
1476c10b85d6SJean-Jacques Hiblot 	{
1477d0c221feSJean-Jacques Hiblot 		.mode = SD_LEGACY,
1478d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1479d0c221feSJean-Jacques Hiblot 	}
1480d0c221feSJean-Jacques Hiblot };
1481d0c221feSJean-Jacques Hiblot 
1482d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \
1483d0c221feSJean-Jacques Hiblot 	for (mwt = sd_modes_by_pref;\
1484d0c221feSJean-Jacques Hiblot 	     mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\
1485d0c221feSJean-Jacques Hiblot 	     mwt++) \
1486d0c221feSJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
1487d0c221feSJean-Jacques Hiblot 
148801298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
14898ac8a263SJean-Jacques Hiblot {
14908ac8a263SJean-Jacques Hiblot 	int err;
1491d0c221feSJean-Jacques Hiblot 	uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
1492d0c221feSJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
1493c10b85d6SJean-Jacques Hiblot 	bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false;
1494c10b85d6SJean-Jacques Hiblot 	uint caps;
1495c10b85d6SJean-Jacques Hiblot 
14968ac8a263SJean-Jacques Hiblot 
14978ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
149801298da3SJean-Jacques Hiblot 	caps = card_caps & (mmc->host_caps | MMC_MODE_1BIT);
14998ac8a263SJean-Jacques Hiblot 
1500c10b85d6SJean-Jacques Hiblot 	if (!uhs_en)
1501c10b85d6SJean-Jacques Hiblot 		caps &= ~UHS_CAPS;
1502c10b85d6SJean-Jacques Hiblot 
1503c10b85d6SJean-Jacques Hiblot 	for_each_sd_mode_by_pref(caps, mwt) {
1504d0c221feSJean-Jacques Hiblot 		uint *w;
15058ac8a263SJean-Jacques Hiblot 
1506d0c221feSJean-Jacques Hiblot 		for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
1507c10b85d6SJean-Jacques Hiblot 			if (*w & caps & mwt->widths) {
1508d0c221feSJean-Jacques Hiblot 				debug("trying mode %s width %d (at %d MHz)\n",
1509d0c221feSJean-Jacques Hiblot 				      mmc_mode_name(mwt->mode),
1510d0c221feSJean-Jacques Hiblot 				      bus_width(*w),
1511d0c221feSJean-Jacques Hiblot 				      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1512d0c221feSJean-Jacques Hiblot 
1513d0c221feSJean-Jacques Hiblot 				/* configure the bus width (card + host) */
1514d0c221feSJean-Jacques Hiblot 				err = sd_select_bus_width(mmc, bus_width(*w));
15158ac8a263SJean-Jacques Hiblot 				if (err)
1516d0c221feSJean-Jacques Hiblot 					goto error;
1517d0c221feSJean-Jacques Hiblot 				mmc_set_bus_width(mmc, bus_width(*w));
15188ac8a263SJean-Jacques Hiblot 
1519d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (card) */
1520d0c221feSJean-Jacques Hiblot 				err = sd_set_card_speed(mmc, mwt->mode);
15218ac8a263SJean-Jacques Hiblot 				if (err)
1522d0c221feSJean-Jacques Hiblot 					goto error;
15238ac8a263SJean-Jacques Hiblot 
1524d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (host) */
1525d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, mwt->mode);
152635f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
15278ac8a263SJean-Jacques Hiblot 
1528c10b85d6SJean-Jacques Hiblot 				/* execute tuning if needed */
1529c10b85d6SJean-Jacques Hiblot 				if (mwt->tuning && !mmc_host_is_spi(mmc)) {
1530c10b85d6SJean-Jacques Hiblot 					err = mmc_execute_tuning(mmc,
1531c10b85d6SJean-Jacques Hiblot 								 mwt->tuning);
1532c10b85d6SJean-Jacques Hiblot 					if (err) {
1533c10b85d6SJean-Jacques Hiblot 						debug("tuning failed\n");
1534c10b85d6SJean-Jacques Hiblot 						goto error;
1535c10b85d6SJean-Jacques Hiblot 					}
1536c10b85d6SJean-Jacques Hiblot 				}
1537c10b85d6SJean-Jacques Hiblot 
15388ac8a263SJean-Jacques Hiblot 				err = sd_read_ssr(mmc);
1539d0c221feSJean-Jacques Hiblot 				if (!err)
15408ac8a263SJean-Jacques Hiblot 					return 0;
1541d0c221feSJean-Jacques Hiblot 
1542d0c221feSJean-Jacques Hiblot 				printf("bad ssr\n");
1543d0c221feSJean-Jacques Hiblot 
1544d0c221feSJean-Jacques Hiblot error:
1545d0c221feSJean-Jacques Hiblot 				/* revert to a safer bus speed */
1546d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, SD_LEGACY);
154735f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
1548d0c221feSJean-Jacques Hiblot 			}
1549d0c221feSJean-Jacques Hiblot 		}
1550d0c221feSJean-Jacques Hiblot 	}
1551d0c221feSJean-Jacques Hiblot 
1552d0c221feSJean-Jacques Hiblot 	printf("unable to select a mode\n");
1553d0c221feSJean-Jacques Hiblot 	return -ENOTSUPP;
15548ac8a263SJean-Jacques Hiblot }
15558ac8a263SJean-Jacques Hiblot 
15567382e691SJean-Jacques Hiblot /*
15577382e691SJean-Jacques Hiblot  * read the compare the part of ext csd that is constant.
15587382e691SJean-Jacques Hiblot  * This can be used to check that the transfer is working
15597382e691SJean-Jacques Hiblot  * as expected.
15607382e691SJean-Jacques Hiblot  */
15617382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
15627382e691SJean-Jacques Hiblot {
15637382e691SJean-Jacques Hiblot 	int err;
15647382e691SJean-Jacques Hiblot 	const u8 *ext_csd = mmc->ext_csd;
15657382e691SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
15667382e691SJean-Jacques Hiblot 
15677382e691SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, test_csd);
15687382e691SJean-Jacques Hiblot 	if (err)
15697382e691SJean-Jacques Hiblot 		return err;
15707382e691SJean-Jacques Hiblot 
15717382e691SJean-Jacques Hiblot 	/* Only compare read only fields */
15727382e691SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
15737382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
15747382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
15757382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
15767382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_REV]
15777382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_REV] &&
15787382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
15797382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
15807382e691SJean-Jacques Hiblot 	    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
15817382e691SJean-Jacques Hiblot 		   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
15827382e691SJean-Jacques Hiblot 		return 0;
15837382e691SJean-Jacques Hiblot 
15847382e691SJean-Jacques Hiblot 	return -EBADMSG;
15857382e691SJean-Jacques Hiblot }
15867382e691SJean-Jacques Hiblot 
15873862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = {
15888ac8a263SJean-Jacques Hiblot 	{
15893862b854SJean-Jacques Hiblot 		.mode = MMC_HS_200,
15903862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
1591634d4849SKishon Vijay Abraham I 		.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
15923862b854SJean-Jacques Hiblot 	},
15933862b854SJean-Jacques Hiblot 	{
15943862b854SJean-Jacques Hiblot 		.mode = MMC_DDR_52,
15953862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
15963862b854SJean-Jacques Hiblot 	},
15973862b854SJean-Jacques Hiblot 	{
15983862b854SJean-Jacques Hiblot 		.mode = MMC_HS_52,
15993862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
16003862b854SJean-Jacques Hiblot 	},
16013862b854SJean-Jacques Hiblot 	{
16023862b854SJean-Jacques Hiblot 		.mode = MMC_HS,
16033862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
16043862b854SJean-Jacques Hiblot 	},
16053862b854SJean-Jacques Hiblot 	{
16063862b854SJean-Jacques Hiblot 		.mode = MMC_LEGACY,
16073862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
16083862b854SJean-Jacques Hiblot 	}
16098ac8a263SJean-Jacques Hiblot };
16108ac8a263SJean-Jacques Hiblot 
16113862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \
16123862b854SJean-Jacques Hiblot 	for (mwt = mmc_modes_by_pref;\
16133862b854SJean-Jacques Hiblot 	    mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\
16143862b854SJean-Jacques Hiblot 	    mwt++) \
16153862b854SJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
16163862b854SJean-Jacques Hiblot 
16173862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width {
16183862b854SJean-Jacques Hiblot 	uint cap;
16193862b854SJean-Jacques Hiblot 	bool is_ddr;
16203862b854SJean-Jacques Hiblot 	uint ext_csd_bits;
16213862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = {
16223862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8},
16233862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4},
16243862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8},
16253862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4},
16263862b854SJean-Jacques Hiblot 	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
16273862b854SJean-Jacques Hiblot };
16283862b854SJean-Jacques Hiblot 
16293862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \
16303862b854SJean-Jacques Hiblot 	for (ecbv = ext_csd_bus_width;\
16313862b854SJean-Jacques Hiblot 	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
16323862b854SJean-Jacques Hiblot 	    ecbv++) \
16333862b854SJean-Jacques Hiblot 		if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
16343862b854SJean-Jacques Hiblot 
163501298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
16363862b854SJean-Jacques Hiblot {
16373862b854SJean-Jacques Hiblot 	int err;
16383862b854SJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
16393862b854SJean-Jacques Hiblot 	const struct ext_csd_bus_width *ecbw;
16403862b854SJean-Jacques Hiblot 
16418ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
164201298da3SJean-Jacques Hiblot 	card_caps &= (mmc->host_caps | MMC_MODE_1BIT);
16438ac8a263SJean-Jacques Hiblot 
16448ac8a263SJean-Jacques Hiblot 	/* Only version 4 of MMC supports wider bus widths */
16458ac8a263SJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
16468ac8a263SJean-Jacques Hiblot 		return 0;
16478ac8a263SJean-Jacques Hiblot 
1648dfda9d88SJean-Jacques Hiblot 	if (!mmc->ext_csd) {
1649dfda9d88SJean-Jacques Hiblot 		debug("No ext_csd found!\n"); /* this should enver happen */
1650dfda9d88SJean-Jacques Hiblot 		return -ENOTSUPP;
1651dfda9d88SJean-Jacques Hiblot 	}
1652dfda9d88SJean-Jacques Hiblot 
165301298da3SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->legacy_speed, false);
165401298da3SJean-Jacques Hiblot 
165501298da3SJean-Jacques Hiblot 	for_each_mmc_mode_by_pref(card_caps, mwt) {
165601298da3SJean-Jacques Hiblot 		for_each_supported_width(card_caps & mwt->widths,
16573862b854SJean-Jacques Hiblot 					 mmc_is_mode_ddr(mwt->mode), ecbw) {
16583862b854SJean-Jacques Hiblot 			debug("trying mode %s width %d (at %d MHz)\n",
16593862b854SJean-Jacques Hiblot 			      mmc_mode_name(mwt->mode),
16603862b854SJean-Jacques Hiblot 			      bus_width(ecbw->cap),
16613862b854SJean-Jacques Hiblot 			      mmc_mode2freq(mmc, mwt->mode) / 1000000);
16623862b854SJean-Jacques Hiblot 			/* configure the bus width (card + host) */
16633862b854SJean-Jacques Hiblot 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
16643862b854SJean-Jacques Hiblot 				    EXT_CSD_BUS_WIDTH,
16653862b854SJean-Jacques Hiblot 				    ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG);
16663862b854SJean-Jacques Hiblot 			if (err)
16673862b854SJean-Jacques Hiblot 				goto error;
16683862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
16693862b854SJean-Jacques Hiblot 
16703862b854SJean-Jacques Hiblot 			/* configure the bus speed (card) */
16713862b854SJean-Jacques Hiblot 			err = mmc_set_card_speed(mmc, mwt->mode);
16723862b854SJean-Jacques Hiblot 			if (err)
16733862b854SJean-Jacques Hiblot 				goto error;
16743862b854SJean-Jacques Hiblot 
16758ac8a263SJean-Jacques Hiblot 			/*
16763862b854SJean-Jacques Hiblot 			 * configure the bus width AND the ddr mode (card)
16773862b854SJean-Jacques Hiblot 			 * The host side will be taken care of in the next step
16788ac8a263SJean-Jacques Hiblot 			 */
16793862b854SJean-Jacques Hiblot 			if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
16803862b854SJean-Jacques Hiblot 				err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
16813862b854SJean-Jacques Hiblot 						 EXT_CSD_BUS_WIDTH,
16823862b854SJean-Jacques Hiblot 						 ecbw->ext_csd_bits);
16833862b854SJean-Jacques Hiblot 				if (err)
16843862b854SJean-Jacques Hiblot 					goto error;
16858ac8a263SJean-Jacques Hiblot 			}
16868ac8a263SJean-Jacques Hiblot 
16873862b854SJean-Jacques Hiblot 			/* configure the bus mode (host) */
16883862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, mwt->mode);
168935f67820SKishon Vijay Abraham I 			mmc_set_clock(mmc, mmc->tran_speed, false);
16908ac8a263SJean-Jacques Hiblot 
1691634d4849SKishon Vijay Abraham I 			/* execute tuning if needed */
1692634d4849SKishon Vijay Abraham I 			if (mwt->tuning) {
1693634d4849SKishon Vijay Abraham I 				err = mmc_execute_tuning(mmc, mwt->tuning);
1694634d4849SKishon Vijay Abraham I 				if (err) {
1695634d4849SKishon Vijay Abraham I 					debug("tuning failed\n");
1696634d4849SKishon Vijay Abraham I 					goto error;
1697634d4849SKishon Vijay Abraham I 				}
1698634d4849SKishon Vijay Abraham I 			}
1699634d4849SKishon Vijay Abraham I 
17003862b854SJean-Jacques Hiblot 			/* do a transfer to check the configuration */
17017382e691SJean-Jacques Hiblot 			err = mmc_read_and_compare_ext_csd(mmc);
17027382e691SJean-Jacques Hiblot 			if (!err)
17033862b854SJean-Jacques Hiblot 				return 0;
17043862b854SJean-Jacques Hiblot error:
17053862b854SJean-Jacques Hiblot 			/* if an error occured, revert to a safer bus mode */
17063862b854SJean-Jacques Hiblot 			mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
17073862b854SJean-Jacques Hiblot 				   EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
17083862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_LEGACY);
17093862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, 1);
17103862b854SJean-Jacques Hiblot 		}
17118ac8a263SJean-Jacques Hiblot 	}
17128ac8a263SJean-Jacques Hiblot 
17133862b854SJean-Jacques Hiblot 	printf("unable to select a mode\n");
17148ac8a263SJean-Jacques Hiblot 
17153862b854SJean-Jacques Hiblot 	return -ENOTSUPP;
17168ac8a263SJean-Jacques Hiblot }
17178ac8a263SJean-Jacques Hiblot 
1718dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
1719c744b6f6SJean-Jacques Hiblot {
1720c744b6f6SJean-Jacques Hiblot 	int err, i;
1721c744b6f6SJean-Jacques Hiblot 	u64 capacity;
1722c744b6f6SJean-Jacques Hiblot 	bool has_parts = false;
1723c744b6f6SJean-Jacques Hiblot 	bool part_completed;
1724dfda9d88SJean-Jacques Hiblot 	u8 *ext_csd;
1725c744b6f6SJean-Jacques Hiblot 
1726c744b6f6SJean-Jacques Hiblot 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
1727c744b6f6SJean-Jacques Hiblot 		return 0;
1728c744b6f6SJean-Jacques Hiblot 
1729dfda9d88SJean-Jacques Hiblot 	ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN);
1730dfda9d88SJean-Jacques Hiblot 	if (!ext_csd)
1731dfda9d88SJean-Jacques Hiblot 		return -ENOMEM;
1732dfda9d88SJean-Jacques Hiblot 
1733dfda9d88SJean-Jacques Hiblot 	mmc->ext_csd = ext_csd;
1734dfda9d88SJean-Jacques Hiblot 
1735c744b6f6SJean-Jacques Hiblot 	/* check  ext_csd version and capacity */
1736c744b6f6SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, ext_csd);
1737c744b6f6SJean-Jacques Hiblot 	if (err)
1738c744b6f6SJean-Jacques Hiblot 		return err;
1739c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_REV] >= 2) {
1740c744b6f6SJean-Jacques Hiblot 		/*
1741c744b6f6SJean-Jacques Hiblot 		 * According to the JEDEC Standard, the value of
1742c744b6f6SJean-Jacques Hiblot 		 * ext_csd's capacity is valid if the value is more
1743c744b6f6SJean-Jacques Hiblot 		 * than 2GB
1744c744b6f6SJean-Jacques Hiblot 		 */
1745c744b6f6SJean-Jacques Hiblot 		capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
1746c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
1747c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
1748c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1749c744b6f6SJean-Jacques Hiblot 		capacity *= MMC_MAX_BLOCK_LEN;
1750c744b6f6SJean-Jacques Hiblot 		if ((capacity >> 20) > 2 * 1024)
1751c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1752c744b6f6SJean-Jacques Hiblot 	}
1753c744b6f6SJean-Jacques Hiblot 
1754c744b6f6SJean-Jacques Hiblot 	switch (ext_csd[EXT_CSD_REV]) {
1755c744b6f6SJean-Jacques Hiblot 	case 1:
1756c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_1;
1757c744b6f6SJean-Jacques Hiblot 		break;
1758c744b6f6SJean-Jacques Hiblot 	case 2:
1759c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_2;
1760c744b6f6SJean-Jacques Hiblot 		break;
1761c744b6f6SJean-Jacques Hiblot 	case 3:
1762c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_3;
1763c744b6f6SJean-Jacques Hiblot 		break;
1764c744b6f6SJean-Jacques Hiblot 	case 5:
1765c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_41;
1766c744b6f6SJean-Jacques Hiblot 		break;
1767c744b6f6SJean-Jacques Hiblot 	case 6:
1768c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_5;
1769c744b6f6SJean-Jacques Hiblot 		break;
1770c744b6f6SJean-Jacques Hiblot 	case 7:
1771c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_0;
1772c744b6f6SJean-Jacques Hiblot 		break;
1773c744b6f6SJean-Jacques Hiblot 	case 8:
1774c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_1;
1775c744b6f6SJean-Jacques Hiblot 		break;
1776c744b6f6SJean-Jacques Hiblot 	}
1777c744b6f6SJean-Jacques Hiblot 
1778c744b6f6SJean-Jacques Hiblot 	/* The partition data may be non-zero but it is only
1779c744b6f6SJean-Jacques Hiblot 	 * effective if PARTITION_SETTING_COMPLETED is set in
1780c744b6f6SJean-Jacques Hiblot 	 * EXT_CSD, so ignore any data if this bit is not set,
1781c744b6f6SJean-Jacques Hiblot 	 * except for enabling the high-capacity group size
1782c744b6f6SJean-Jacques Hiblot 	 * definition (see below).
1783c744b6f6SJean-Jacques Hiblot 	 */
1784c744b6f6SJean-Jacques Hiblot 	part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
1785c744b6f6SJean-Jacques Hiblot 			    EXT_CSD_PARTITION_SETTING_COMPLETED);
1786c744b6f6SJean-Jacques Hiblot 
1787c744b6f6SJean-Jacques Hiblot 	/* store the partition info of emmc */
1788c744b6f6SJean-Jacques Hiblot 	mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
1789c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
1790c744b6f6SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_BOOT_MULT])
1791c744b6f6SJean-Jacques Hiblot 		mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
1792c744b6f6SJean-Jacques Hiblot 	if (part_completed &&
1793c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
1794c744b6f6SJean-Jacques Hiblot 		mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
1795c744b6f6SJean-Jacques Hiblot 
1796c744b6f6SJean-Jacques Hiblot 	mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
1797c744b6f6SJean-Jacques Hiblot 
1798c744b6f6SJean-Jacques Hiblot 	mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
1799c744b6f6SJean-Jacques Hiblot 
1800c744b6f6SJean-Jacques Hiblot 	for (i = 0; i < 4; i++) {
1801c744b6f6SJean-Jacques Hiblot 		int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
1802c744b6f6SJean-Jacques Hiblot 		uint mult = (ext_csd[idx + 2] << 16) +
1803c744b6f6SJean-Jacques Hiblot 			(ext_csd[idx + 1] << 8) + ext_csd[idx];
1804c744b6f6SJean-Jacques Hiblot 		if (mult)
1805c744b6f6SJean-Jacques Hiblot 			has_parts = true;
1806c744b6f6SJean-Jacques Hiblot 		if (!part_completed)
1807c744b6f6SJean-Jacques Hiblot 			continue;
1808c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] = mult;
1809c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *=
1810c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1811c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1812c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] <<= 19;
1813c744b6f6SJean-Jacques Hiblot 	}
1814c744b6f6SJean-Jacques Hiblot 
1815c744b6f6SJean-Jacques Hiblot 	if (part_completed) {
1816c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size =
1817c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
1818c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
1819c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_SIZE_MULT];
1820c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1821c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1822c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size <<= 19;
1823c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_start =
1824c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
1825c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
1826c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
1827c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_START_ADDR];
1828c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity)
1829c744b6f6SJean-Jacques Hiblot 			mmc->enh_user_start <<= 9;
1830c744b6f6SJean-Jacques Hiblot 	}
1831c744b6f6SJean-Jacques Hiblot 
1832c744b6f6SJean-Jacques Hiblot 	/*
1833c744b6f6SJean-Jacques Hiblot 	 * Host needs to enable ERASE_GRP_DEF bit if device is
1834c744b6f6SJean-Jacques Hiblot 	 * partitioned. This bit will be lost every time after a reset
1835c744b6f6SJean-Jacques Hiblot 	 * or power off. This will affect erase size.
1836c744b6f6SJean-Jacques Hiblot 	 */
1837c744b6f6SJean-Jacques Hiblot 	if (part_completed)
1838c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1839c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
1840c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
1841c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1842c744b6f6SJean-Jacques Hiblot 	if (has_parts) {
1843c744b6f6SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1844c744b6f6SJean-Jacques Hiblot 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1845c744b6f6SJean-Jacques Hiblot 
1846c744b6f6SJean-Jacques Hiblot 		if (err)
1847c744b6f6SJean-Jacques Hiblot 			return err;
1848c744b6f6SJean-Jacques Hiblot 
1849c744b6f6SJean-Jacques Hiblot 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1850c744b6f6SJean-Jacques Hiblot 	}
1851c744b6f6SJean-Jacques Hiblot 
1852c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
1853c744b6f6SJean-Jacques Hiblot 		/* Read out group size from ext_csd */
1854c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size =
1855c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1856c744b6f6SJean-Jacques Hiblot 		/*
1857c744b6f6SJean-Jacques Hiblot 		 * if high capacity and partition setting completed
1858c744b6f6SJean-Jacques Hiblot 		 * SEC_COUNT is valid even if it is smaller than 2 GiB
1859c744b6f6SJean-Jacques Hiblot 		 * JEDEC Standard JESD84-B45, 6.2.4
1860c744b6f6SJean-Jacques Hiblot 		 */
1861c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity && part_completed) {
1862c744b6f6SJean-Jacques Hiblot 			capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1863c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1864c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1865c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1866c744b6f6SJean-Jacques Hiblot 			capacity *= MMC_MAX_BLOCK_LEN;
1867c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1868c744b6f6SJean-Jacques Hiblot 		}
1869c744b6f6SJean-Jacques Hiblot 	} else {
1870c744b6f6SJean-Jacques Hiblot 		/* Calculate the group size from the csd value. */
1871c744b6f6SJean-Jacques Hiblot 		int erase_gsz, erase_gmul;
1872c744b6f6SJean-Jacques Hiblot 
1873c744b6f6SJean-Jacques Hiblot 		erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1874c744b6f6SJean-Jacques Hiblot 		erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1875c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size = (erase_gsz + 1)
1876c744b6f6SJean-Jacques Hiblot 			* (erase_gmul + 1);
1877c744b6f6SJean-Jacques Hiblot 	}
1878c744b6f6SJean-Jacques Hiblot 
1879c744b6f6SJean-Jacques Hiblot 	mmc->hc_wp_grp_size = 1024
1880c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1881c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1882c744b6f6SJean-Jacques Hiblot 
1883c744b6f6SJean-Jacques Hiblot 	mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1884c744b6f6SJean-Jacques Hiblot 
1885c744b6f6SJean-Jacques Hiblot 	return 0;
1886c744b6f6SJean-Jacques Hiblot }
1887c744b6f6SJean-Jacques Hiblot 
1888fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1889272cc70bSAndy Fleming {
1890f866a46dSStephen Warren 	int err, i;
1891272cc70bSAndy Fleming 	uint mult, freq;
1892c744b6f6SJean-Jacques Hiblot 	u64 cmult, csize;
1893272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1894c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1895272cc70bSAndy Fleming 
1896d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1897d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1898d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1899d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1900d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1901d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1902d52ebf10SThomas Chou 		if (err)
1903d52ebf10SThomas Chou 			return err;
1904d52ebf10SThomas Chou 	}
1905d52ebf10SThomas Chou #endif
1906d52ebf10SThomas Chou 
1907272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1908d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1909d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1910272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1911272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1912272cc70bSAndy Fleming 
1913272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1914272cc70bSAndy Fleming 
1915*83dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
1916*83dc4227SKishon Vijay Abraham I 	if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) {
1917*83dc4227SKishon Vijay Abraham I 		int retries = 4;
1918*83dc4227SKishon Vijay Abraham I 		/*
1919*83dc4227SKishon Vijay Abraham I 		 * It has been seen that SEND_CID may fail on the first
1920*83dc4227SKishon Vijay Abraham I 		 * attempt, let's try a few more time
1921*83dc4227SKishon Vijay Abraham I 		 */
1922*83dc4227SKishon Vijay Abraham I 		do {
1923*83dc4227SKishon Vijay Abraham I 			err = mmc_send_cmd(mmc, &cmd, NULL);
1924*83dc4227SKishon Vijay Abraham I 			if (!err)
1925*83dc4227SKishon Vijay Abraham I 				break;
1926*83dc4227SKishon Vijay Abraham I 		} while (retries--);
1927*83dc4227SKishon Vijay Abraham I 	}
1928*83dc4227SKishon Vijay Abraham I #endif
1929*83dc4227SKishon Vijay Abraham I 
1930272cc70bSAndy Fleming 	if (err)
1931272cc70bSAndy Fleming 		return err;
1932272cc70bSAndy Fleming 
1933272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1934272cc70bSAndy Fleming 
1935272cc70bSAndy Fleming 	/*
1936272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1937272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1938272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1939272cc70bSAndy Fleming 	 */
1940d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1941272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1942272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1943272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1944272cc70bSAndy Fleming 
1945272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1946272cc70bSAndy Fleming 
1947272cc70bSAndy Fleming 		if (err)
1948272cc70bSAndy Fleming 			return err;
1949272cc70bSAndy Fleming 
1950272cc70bSAndy Fleming 		if (IS_SD(mmc))
1951998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1952d52ebf10SThomas Chou 	}
1953272cc70bSAndy Fleming 
1954272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1955272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1956272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1957272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1958272cc70bSAndy Fleming 
1959272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1960272cc70bSAndy Fleming 
1961272cc70bSAndy Fleming 	if (err)
1962272cc70bSAndy Fleming 		return err;
1963272cc70bSAndy Fleming 
1964998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1965998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1966998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1967998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1968272cc70bSAndy Fleming 
1969272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
19700b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1971272cc70bSAndy Fleming 
1972272cc70bSAndy Fleming 		switch (version) {
1973272cc70bSAndy Fleming 		case 0:
1974272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1975272cc70bSAndy Fleming 			break;
1976272cc70bSAndy Fleming 		case 1:
1977272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1978272cc70bSAndy Fleming 			break;
1979272cc70bSAndy Fleming 		case 2:
1980272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1981272cc70bSAndy Fleming 			break;
1982272cc70bSAndy Fleming 		case 3:
1983272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1984272cc70bSAndy Fleming 			break;
1985272cc70bSAndy Fleming 		case 4:
1986272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1987272cc70bSAndy Fleming 			break;
1988272cc70bSAndy Fleming 		default:
1989272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1990272cc70bSAndy Fleming 			break;
1991272cc70bSAndy Fleming 		}
1992272cc70bSAndy Fleming 	}
1993272cc70bSAndy Fleming 
1994272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
19950b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
19960b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1997272cc70bSAndy Fleming 
199835f9e196SJean-Jacques Hiblot 	mmc->legacy_speed = freq * mult;
199935f9e196SJean-Jacques Hiblot 	mmc_select_mode(mmc, MMC_LEGACY);
2000272cc70bSAndy Fleming 
2001ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
2002998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
2003272cc70bSAndy Fleming 
2004272cc70bSAndy Fleming 	if (IS_SD(mmc))
2005272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
2006272cc70bSAndy Fleming 	else
2007998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
2008272cc70bSAndy Fleming 
2009272cc70bSAndy Fleming 	if (mmc->high_capacity) {
2010272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
2011272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
2012272cc70bSAndy Fleming 		cmult = 8;
2013272cc70bSAndy Fleming 	} else {
2014272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
2015272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
2016272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
2017272cc70bSAndy Fleming 	}
2018272cc70bSAndy Fleming 
2019f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
2020f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
2021f866a46dSStephen Warren 	mmc->capacity_boot = 0;
2022f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
2023f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
2024f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
2025272cc70bSAndy Fleming 
20268bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
20278bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
2028272cc70bSAndy Fleming 
20298bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
20308bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
2031272cc70bSAndy Fleming 
2032ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
2033ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
2034ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
2035ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
2036ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
2037ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
2038ab71188cSMarkus Niebel 	}
2039ab71188cSMarkus Niebel 
2040272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
2041d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2042272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
2043fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
2044272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
2045272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
2046272cc70bSAndy Fleming 
2047272cc70bSAndy Fleming 		if (err)
2048272cc70bSAndy Fleming 			return err;
2049d52ebf10SThomas Chou 	}
2050272cc70bSAndy Fleming 
2051e6f99a56SLei Wen 	/*
2052e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
2053e6f99a56SLei Wen 	 */
2054e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
2055bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
2056c744b6f6SJean-Jacques Hiblot 
2057dfda9d88SJean-Jacques Hiblot 	err = mmc_startup_v4(mmc);
20589cf199ebSDiego Santa Cruz 	if (err)
20599cf199ebSDiego Santa Cruz 		return err;
2060f866a46dSStephen Warren 
2061c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
2062f866a46dSStephen Warren 	if (err)
2063f866a46dSStephen Warren 		return err;
2064d23e2c09SSukumar Ghorai 
206501298da3SJean-Jacques Hiblot 	if (IS_SD(mmc)) {
206601298da3SJean-Jacques Hiblot 		err = sd_get_capabilities(mmc);
206701298da3SJean-Jacques Hiblot 		if (err)
206801298da3SJean-Jacques Hiblot 			return err;
206901298da3SJean-Jacques Hiblot 		err = sd_select_mode_and_width(mmc, mmc->card_caps);
207001298da3SJean-Jacques Hiblot 	} else {
207101298da3SJean-Jacques Hiblot 		err = mmc_get_capabilities(mmc);
207201298da3SJean-Jacques Hiblot 		if (err)
207301298da3SJean-Jacques Hiblot 			return err;
207401298da3SJean-Jacques Hiblot 		mmc_select_mode_and_width(mmc, mmc->card_caps);
207501298da3SJean-Jacques Hiblot 	}
2076272cc70bSAndy Fleming 
2077272cc70bSAndy Fleming 	if (err)
2078272cc70bSAndy Fleming 		return err;
2079272cc70bSAndy Fleming 
208001298da3SJean-Jacques Hiblot 	mmc->best_mode = mmc->selected_mode;
2081272cc70bSAndy Fleming 
20825af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
20835af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
20845af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
20855af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
20865af8f45cSAndrew Gabbasov 	}
20875af8f45cSAndrew Gabbasov 
2088272cc70bSAndy Fleming 	/* fill in device description */
2089c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
2090c40fdca6SSimon Glass 	bdesc->lun = 0;
2091c40fdca6SSimon Glass 	bdesc->hwpart = 0;
2092c40fdca6SSimon Glass 	bdesc->type = 0;
2093c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
2094c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
2095c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
2096fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
2097fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
2098fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
2099c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
2100babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
2101babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
2102c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
21030b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
2104babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
2105babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
2106c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
2107babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
210856196826SPaul Burton #else
2109c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
2110c40fdca6SSimon Glass 	bdesc->product[0] = 0;
2111c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
211256196826SPaul Burton #endif
2113122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
2114c40fdca6SSimon Glass 	part_init(bdesc);
2115122efd43SMikhail Kshevetskiy #endif
2116272cc70bSAndy Fleming 
2117272cc70bSAndy Fleming 	return 0;
2118272cc70bSAndy Fleming }
2119272cc70bSAndy Fleming 
2120fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
2121272cc70bSAndy Fleming {
2122272cc70bSAndy Fleming 	struct mmc_cmd cmd;
2123272cc70bSAndy Fleming 	int err;
2124272cc70bSAndy Fleming 
2125272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
2126272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
212793bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
2128272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
2129272cc70bSAndy Fleming 
2130272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2131272cc70bSAndy Fleming 
2132272cc70bSAndy Fleming 	if (err)
2133272cc70bSAndy Fleming 		return err;
2134272cc70bSAndy Fleming 
2135998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
2136915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
2137272cc70bSAndy Fleming 	else
2138272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
2139272cc70bSAndy Fleming 
2140272cc70bSAndy Fleming 	return 0;
2141272cc70bSAndy Fleming }
2142272cc70bSAndy Fleming 
2143c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
214495de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
214595de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
214695de9ab2SPaul Kocialkowski {
214795de9ab2SPaul Kocialkowski }
214805cbeb7cSSimon Glass #endif
214995de9ab2SPaul Kocialkowski 
21502051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
21512051aefeSPeng Fan {
2152c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
215306ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
21542051aefeSPeng Fan 	int ret;
21552051aefeSPeng Fan 
21562051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
215706ec045fSJean-Jacques Hiblot 					  &mmc->vmmc_supply);
215806ec045fSJean-Jacques Hiblot 	if (ret)
2159288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
21602051aefeSPeng Fan 
216106ec045fSJean-Jacques Hiblot 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
216206ec045fSJean-Jacques Hiblot 					  &mmc->vqmmc_supply);
216306ec045fSJean-Jacques Hiblot 	if (ret)
216406ec045fSJean-Jacques Hiblot 		debug("%s: No vqmmc supply\n", mmc->dev->name);
21652051aefeSPeng Fan #endif
216605cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
216705cbeb7cSSimon Glass 	/*
216805cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
216905cbeb7cSSimon Glass 	 * out to board code.
217005cbeb7cSSimon Glass 	 */
217105cbeb7cSSimon Glass 	board_mmc_power_init();
217205cbeb7cSSimon Glass #endif
21732051aefeSPeng Fan 	return 0;
21742051aefeSPeng Fan }
21752051aefeSPeng Fan 
2176fb7c3bebSKishon Vijay Abraham I /*
2177fb7c3bebSKishon Vijay Abraham I  * put the host in the initial state:
2178fb7c3bebSKishon Vijay Abraham I  * - turn on Vdd (card power supply)
2179fb7c3bebSKishon Vijay Abraham I  * - configure the bus width and clock to minimal values
2180fb7c3bebSKishon Vijay Abraham I  */
2181fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc)
2182fb7c3bebSKishon Vijay Abraham I {
2183fb7c3bebSKishon Vijay Abraham I 	int err;
2184fb7c3bebSKishon Vijay Abraham I 
2185fb7c3bebSKishon Vijay Abraham I 	/* First try to set 3.3V. If it fails set to 1.8V */
2186fb7c3bebSKishon Vijay Abraham I 	err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330);
2187fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2188fb7c3bebSKishon Vijay Abraham I 		err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
2189fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2190fb7c3bebSKishon Vijay Abraham I 		printf("mmc: failed to set signal voltage\n");
2191fb7c3bebSKishon Vijay Abraham I 
2192fb7c3bebSKishon Vijay Abraham I 	mmc_select_mode(mmc, MMC_LEGACY);
2193fb7c3bebSKishon Vijay Abraham I 	mmc_set_bus_width(mmc, 1);
219435f67820SKishon Vijay Abraham I 	mmc_set_clock(mmc, 0, false);
2195fb7c3bebSKishon Vijay Abraham I }
2196fb7c3bebSKishon Vijay Abraham I 
2197fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc)
2198fb7c3bebSKishon Vijay Abraham I {
2199fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2200fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2201fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, true);
2202fb7c3bebSKishon Vijay Abraham I 
2203fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2204fb7c3bebSKishon Vijay Abraham I 			puts("Error enabling VMMC supply\n");
2205fb7c3bebSKishon Vijay Abraham I 			return ret;
2206fb7c3bebSKishon Vijay Abraham I 		}
2207fb7c3bebSKishon Vijay Abraham I 	}
2208fb7c3bebSKishon Vijay Abraham I #endif
2209fb7c3bebSKishon Vijay Abraham I 	return 0;
2210fb7c3bebSKishon Vijay Abraham I }
2211fb7c3bebSKishon Vijay Abraham I 
2212fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc)
2213fb7c3bebSKishon Vijay Abraham I {
22142e7410d7SKishon Vijay Abraham I 	mmc_set_clock(mmc, 1, true);
2215fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2216fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2217fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, false);
2218fb7c3bebSKishon Vijay Abraham I 
2219fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2220c10b85d6SJean-Jacques Hiblot 			debug("Error disabling VMMC supply\n");
2221fb7c3bebSKishon Vijay Abraham I 			return ret;
2222fb7c3bebSKishon Vijay Abraham I 		}
2223fb7c3bebSKishon Vijay Abraham I 	}
2224fb7c3bebSKishon Vijay Abraham I #endif
2225fb7c3bebSKishon Vijay Abraham I 	return 0;
2226fb7c3bebSKishon Vijay Abraham I }
2227fb7c3bebSKishon Vijay Abraham I 
2228fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc)
2229fb7c3bebSKishon Vijay Abraham I {
2230fb7c3bebSKishon Vijay Abraham I 	int ret;
2231fb7c3bebSKishon Vijay Abraham I 
2232fb7c3bebSKishon Vijay Abraham I 	ret = mmc_power_off(mmc);
2233fb7c3bebSKishon Vijay Abraham I 	if (ret)
2234fb7c3bebSKishon Vijay Abraham I 		return ret;
2235fb7c3bebSKishon Vijay Abraham I 	/*
2236fb7c3bebSKishon Vijay Abraham I 	 * SD spec recommends at least 1ms of delay. Let's wait for 2ms
2237fb7c3bebSKishon Vijay Abraham I 	 * to be on the safer side.
2238fb7c3bebSKishon Vijay Abraham I 	 */
2239fb7c3bebSKishon Vijay Abraham I 	udelay(2000);
2240fb7c3bebSKishon Vijay Abraham I 	return mmc_power_on(mmc);
2241fb7c3bebSKishon Vijay Abraham I }
2242fb7c3bebSKishon Vijay Abraham I 
2243e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
2244272cc70bSAndy Fleming {
22458ca51e51SSimon Glass 	bool no_card;
2246c10b85d6SJean-Jacques Hiblot 	bool uhs_en = supports_uhs(mmc->cfg->host_caps);
2247afd5932bSMacpaul Lin 	int err;
2248272cc70bSAndy Fleming 
224904a2ea24SJean-Jacques Hiblot 	mmc->host_caps = mmc->cfg->host_caps;
225004a2ea24SJean-Jacques Hiblot 
2251ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
22528ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
2253e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
22548ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
22558ca51e51SSimon Glass #endif
22568ca51e51SSimon Glass 	if (no_card) {
225748972d90SThierry Reding 		mmc->has_init = 0;
225856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
225948972d90SThierry Reding 		printf("MMC: no card present\n");
226056196826SPaul Burton #endif
2261915ffa52SJaehoon Chung 		return -ENOMEDIUM;
226248972d90SThierry Reding 	}
226348972d90SThierry Reding 
2264bc897b1dSLei Wen 	if (mmc->has_init)
2265bc897b1dSLei Wen 		return 0;
2266bc897b1dSLei Wen 
22675a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
22685a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
22695a8dbdc6SYangbo Lu #endif
22702051aefeSPeng Fan 	err = mmc_power_init(mmc);
22712051aefeSPeng Fan 	if (err)
22722051aefeSPeng Fan 		return err;
227395de9ab2SPaul Kocialkowski 
2274*83dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
2275*83dc4227SKishon Vijay Abraham I 	mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN |
2276*83dc4227SKishon Vijay Abraham I 		      MMC_QUIRK_RETRY_SEND_CID;
2277*83dc4227SKishon Vijay Abraham I #endif
2278*83dc4227SKishon Vijay Abraham I 
227904a2ea24SJean-Jacques Hiblot 	err = mmc_power_cycle(mmc);
228004a2ea24SJean-Jacques Hiblot 	if (err) {
228104a2ea24SJean-Jacques Hiblot 		/*
228204a2ea24SJean-Jacques Hiblot 		 * if power cycling is not supported, we should not try
228304a2ea24SJean-Jacques Hiblot 		 * to use the UHS modes, because we wouldn't be able to
228404a2ea24SJean-Jacques Hiblot 		 * recover from an error during the UHS initialization.
228504a2ea24SJean-Jacques Hiblot 		 */
228604a2ea24SJean-Jacques Hiblot 		debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n");
228704a2ea24SJean-Jacques Hiblot 		uhs_en = false;
228804a2ea24SJean-Jacques Hiblot 		mmc->host_caps &= ~UHS_CAPS;
2289fb7c3bebSKishon Vijay Abraham I 		err = mmc_power_on(mmc);
229004a2ea24SJean-Jacques Hiblot 	}
2291fb7c3bebSKishon Vijay Abraham I 	if (err)
2292fb7c3bebSKishon Vijay Abraham I 		return err;
2293fb7c3bebSKishon Vijay Abraham I 
2294e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
22958ca51e51SSimon Glass 	/* The device has already been probed ready for use */
22968ca51e51SSimon Glass #else
2297ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
229893bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
2299272cc70bSAndy Fleming 	if (err)
2300272cc70bSAndy Fleming 		return err;
23018ca51e51SSimon Glass #endif
2302786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
2303aff5d3c8SKishon Vijay Abraham I 
2304c10b85d6SJean-Jacques Hiblot retry:
2305fb7c3bebSKishon Vijay Abraham I 	mmc_set_initial_state(mmc);
2306318a7a57SJean-Jacques Hiblot 	mmc_send_init_stream(mmc);
2307318a7a57SJean-Jacques Hiblot 
2308272cc70bSAndy Fleming 	/* Reset the Card */
2309272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
2310272cc70bSAndy Fleming 
2311272cc70bSAndy Fleming 	if (err)
2312272cc70bSAndy Fleming 		return err;
2313272cc70bSAndy Fleming 
2314bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
2315c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
2316bc897b1dSLei Wen 
2317272cc70bSAndy Fleming 	/* Test for SD version 2 */
2318272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
2319272cc70bSAndy Fleming 
2320272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
2321c10b85d6SJean-Jacques Hiblot 	err = sd_send_op_cond(mmc, uhs_en);
2322c10b85d6SJean-Jacques Hiblot 	if (err && uhs_en) {
2323c10b85d6SJean-Jacques Hiblot 		uhs_en = false;
2324c10b85d6SJean-Jacques Hiblot 		mmc_power_cycle(mmc);
2325c10b85d6SJean-Jacques Hiblot 		goto retry;
2326c10b85d6SJean-Jacques Hiblot 	}
2327272cc70bSAndy Fleming 
2328272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
2329915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
2330272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
2331272cc70bSAndy Fleming 
2332bd47c135SAndrew Gabbasov 		if (err) {
233356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2334272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
233556196826SPaul Burton #endif
2336915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
2337272cc70bSAndy Fleming 		}
2338272cc70bSAndy Fleming 	}
2339272cc70bSAndy Fleming 
2340bd47c135SAndrew Gabbasov 	if (!err)
2341e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
2342e9550449SChe-Liang Chiou 
2343e9550449SChe-Liang Chiou 	return err;
2344e9550449SChe-Liang Chiou }
2345e9550449SChe-Liang Chiou 
2346e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2347e9550449SChe-Liang Chiou {
2348e9550449SChe-Liang Chiou 	int err = 0;
2349e9550449SChe-Liang Chiou 
2350bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
2351e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
2352e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
2353e9550449SChe-Liang Chiou 
2354e9550449SChe-Liang Chiou 	if (!err)
2355bc897b1dSLei Wen 		err = mmc_startup(mmc);
2356bc897b1dSLei Wen 	if (err)
2357bc897b1dSLei Wen 		mmc->has_init = 0;
2358bc897b1dSLei Wen 	else
2359bc897b1dSLei Wen 		mmc->has_init = 1;
2360e9550449SChe-Liang Chiou 	return err;
2361e9550449SChe-Liang Chiou }
2362e9550449SChe-Liang Chiou 
2363e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2364e9550449SChe-Liang Chiou {
2365bd47c135SAndrew Gabbasov 	int err = 0;
2366ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
2367c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
236833fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2369e9550449SChe-Liang Chiou 
237033fb211dSSimon Glass 	upriv->mmc = mmc;
237133fb211dSSimon Glass #endif
2372e9550449SChe-Liang Chiou 	if (mmc->has_init)
2373e9550449SChe-Liang Chiou 		return 0;
2374d803fea5SMateusz Zalega 
2375d803fea5SMateusz Zalega 	start = get_timer(0);
2376d803fea5SMateusz Zalega 
2377e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2378e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2379e9550449SChe-Liang Chiou 
2380bd47c135SAndrew Gabbasov 	if (!err)
2381e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2382919b4858SJagan Teki 	if (err)
2383919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
2384919b4858SJagan Teki 
2385bc897b1dSLei Wen 	return err;
2386272cc70bSAndy Fleming }
2387272cc70bSAndy Fleming 
2388ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2389ab71188cSMarkus Niebel {
2390ab71188cSMarkus Niebel 	mmc->dsr = val;
2391ab71188cSMarkus Niebel 	return 0;
2392ab71188cSMarkus Niebel }
2393ab71188cSMarkus Niebel 
2394cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2395cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2396272cc70bSAndy Fleming {
2397272cc70bSAndy Fleming 	return -1;
2398272cc70bSAndy Fleming }
2399272cc70bSAndy Fleming 
2400cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2401cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2402cee9ab7cSJeroen Hofstee {
2403cee9ab7cSJeroen Hofstee 	return -1;
2404cee9ab7cSJeroen Hofstee }
2405272cc70bSAndy Fleming 
2406e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2407e9550449SChe-Liang Chiou {
2408e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2409e9550449SChe-Liang Chiou }
2410e9550449SChe-Liang Chiou 
2411c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
24128e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
24138e3332e2SSjoerd Simons {
24148e3332e2SSjoerd Simons 	return 0;
24158e3332e2SSjoerd Simons }
2416c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
24178e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
24188e3332e2SSjoerd Simons {
24194a1db6d8SSimon Glass 	int ret, i;
24208e3332e2SSjoerd Simons 	struct uclass *uc;
24214a1db6d8SSimon Glass 	struct udevice *dev;
24228e3332e2SSjoerd Simons 
24238e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
24248e3332e2SSjoerd Simons 	if (ret)
24258e3332e2SSjoerd Simons 		return ret;
24268e3332e2SSjoerd Simons 
24274a1db6d8SSimon Glass 	/*
24284a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
24294a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
24304a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
24314a1db6d8SSimon Glass 	 */
24324a1db6d8SSimon Glass 	for (i = 0; ; i++) {
24334a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
24344a1db6d8SSimon Glass 		if (ret == -ENODEV)
24354a1db6d8SSimon Glass 			break;
24364a1db6d8SSimon Glass 	}
24374a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
24384a1db6d8SSimon Glass 		ret = device_probe(dev);
24398e3332e2SSjoerd Simons 		if (ret)
24404a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
24418e3332e2SSjoerd Simons 	}
24428e3332e2SSjoerd Simons 
24438e3332e2SSjoerd Simons 	return 0;
24448e3332e2SSjoerd Simons }
24458e3332e2SSjoerd Simons #else
24468e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
24478e3332e2SSjoerd Simons {
24488e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
24498e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
24508e3332e2SSjoerd Simons 
24518e3332e2SSjoerd Simons 	return 0;
24528e3332e2SSjoerd Simons }
24538e3332e2SSjoerd Simons #endif
2454e9550449SChe-Liang Chiou 
2455272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2456272cc70bSAndy Fleming {
24571b26bab1SDaniel Kochmański 	static int initialized = 0;
24588e3332e2SSjoerd Simons 	int ret;
24591b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
24601b26bab1SDaniel Kochmański 		return 0;
24611b26bab1SDaniel Kochmański 	initialized = 1;
24621b26bab1SDaniel Kochmański 
2463c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2464b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2465c40fdca6SSimon Glass 	mmc_list_init();
2466c40fdca6SSimon Glass #endif
2467b5b838f1SMarek Vasut #endif
24688e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
24698e3332e2SSjoerd Simons 	if (ret)
24708e3332e2SSjoerd Simons 		return ret;
2471272cc70bSAndy Fleming 
2472bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2473272cc70bSAndy Fleming 	print_mmc_devices(',');
2474bb0dc108SYing Zhang #endif
2475272cc70bSAndy Fleming 
2476c40fdca6SSimon Glass 	mmc_do_preinit();
2477272cc70bSAndy Fleming 	return 0;
2478272cc70bSAndy Fleming }
2479cd3d4880STomas Melin 
2480cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2481cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2482cd3d4880STomas Melin {
2483cd3d4880STomas Melin 	int err;
2484cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2485cd3d4880STomas Melin 
2486cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2487cd3d4880STomas Melin 	if (err) {
2488cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2489cd3d4880STomas Melin 		return err;
2490cd3d4880STomas Melin 	}
2491cd3d4880STomas Melin 
2492cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2493cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2494cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2495cd3d4880STomas Melin 	}
2496cd3d4880STomas Melin 
2497cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2498cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2499cd3d4880STomas Melin 		return 0;
2500cd3d4880STomas Melin 	}
2501cd3d4880STomas Melin 
2502cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2503cd3d4880STomas Melin 	if (err) {
2504cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2505cd3d4880STomas Melin 		return err;
2506cd3d4880STomas Melin 	}
2507cd3d4880STomas Melin 
2508cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2509cd3d4880STomas Melin 
2510cd3d4880STomas Melin 	return 0;
2511cd3d4880STomas Melin }
2512cd3d4880STomas Melin #endif
2513