xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision baef2070a407f14fbab10312b509732e6d104590)
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 
62f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
63c10b85d6SJean-Jacques Hiblot static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout)
64c10b85d6SJean-Jacques Hiblot {
65c10b85d6SJean-Jacques Hiblot 	return -ENOSYS;
66c10b85d6SJean-Jacques Hiblot }
67f99c2efeSJean-Jacques Hiblot #endif
68c10b85d6SJean-Jacques Hiblot 
69750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
70d23d8d7eSNikita Kiryanov {
71d23d8d7eSNikita Kiryanov 	return -1;
72d23d8d7eSNikita Kiryanov }
73d23d8d7eSNikita Kiryanov 
74d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
75d23d8d7eSNikita Kiryanov {
76d23d8d7eSNikita Kiryanov 	int wp;
77d23d8d7eSNikita Kiryanov 
78d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
79d23d8d7eSNikita Kiryanov 
80d4e1da4eSPeter Korsgaard 	if (wp < 0) {
8193bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
8293bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
83d4e1da4eSPeter Korsgaard 		else
84d4e1da4eSPeter Korsgaard 			wp = 0;
85d4e1da4eSPeter Korsgaard 	}
86d23d8d7eSNikita Kiryanov 
87d23d8d7eSNikita Kiryanov 	return wp;
88d23d8d7eSNikita Kiryanov }
89d23d8d7eSNikita Kiryanov 
90cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc)
91cee9ab7cSJeroen Hofstee {
9211fdade2SStefano Babic 	return -1;
9311fdade2SStefano Babic }
948ca51e51SSimon Glass #endif
9511fdade2SStefano Babic 
968635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
97c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd)
98c0c76ebaSSimon Glass {
99c0c76ebaSSimon Glass 	printf("CMD_SEND:%d\n", cmd->cmdidx);
100c0c76ebaSSimon Glass 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
101c0c76ebaSSimon Glass }
102c0c76ebaSSimon Glass 
103c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
104c0c76ebaSSimon Glass {
1055db2fe3aSRaffaele Recalcati 	int i;
1065db2fe3aSRaffaele Recalcati 	u8 *ptr;
1075db2fe3aSRaffaele Recalcati 
1087863ce58SBin Meng 	if (ret) {
1097863ce58SBin Meng 		printf("\t\tRET\t\t\t %d\n", ret);
1107863ce58SBin Meng 	} else {
1115db2fe3aSRaffaele Recalcati 		switch (cmd->resp_type) {
1125db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
1135db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
1145db2fe3aSRaffaele Recalcati 			break;
1155db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
1165db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
1175db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1185db2fe3aSRaffaele Recalcati 			break;
1195db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
1205db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
1215db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1225db2fe3aSRaffaele Recalcati 			break;
1235db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
1245db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
1255db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1265db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1275db2fe3aSRaffaele Recalcati 				cmd->response[1]);
1285db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1295db2fe3aSRaffaele Recalcati 				cmd->response[2]);
1305db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1315db2fe3aSRaffaele Recalcati 				cmd->response[3]);
1325db2fe3aSRaffaele Recalcati 			printf("\n");
1335db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
1345db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
1355db2fe3aSRaffaele Recalcati 				int j;
1365db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
137146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
1385db2fe3aSRaffaele Recalcati 				ptr += 3;
1395db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
1405db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
1415db2fe3aSRaffaele Recalcati 				printf("\n");
1425db2fe3aSRaffaele Recalcati 			}
1435db2fe3aSRaffaele Recalcati 			break;
1445db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1455db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1465db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1475db2fe3aSRaffaele Recalcati 			break;
1485db2fe3aSRaffaele Recalcati 		default:
1495db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1505db2fe3aSRaffaele Recalcati 			break;
1515db2fe3aSRaffaele Recalcati 		}
1527863ce58SBin Meng 	}
153c0c76ebaSSimon Glass }
154c0c76ebaSSimon Glass 
155c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd)
156c0c76ebaSSimon Glass {
157c0c76ebaSSimon Glass 	int status;
158c0c76ebaSSimon Glass 
159c0c76ebaSSimon Glass 	status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9;
160c0c76ebaSSimon Glass 	printf("CURR STATE:%d\n", status);
161c0c76ebaSSimon Glass }
1625db2fe3aSRaffaele Recalcati #endif
163c0c76ebaSSimon Glass 
16435f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
16535f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode)
16635f9e196SJean-Jacques Hiblot {
16735f9e196SJean-Jacques Hiblot 	static const char *const names[] = {
16835f9e196SJean-Jacques Hiblot 	      [MMC_LEGACY]	= "MMC legacy",
16935f9e196SJean-Jacques Hiblot 	      [SD_LEGACY]	= "SD Legacy",
17035f9e196SJean-Jacques Hiblot 	      [MMC_HS]		= "MMC High Speed (26MHz)",
17135f9e196SJean-Jacques Hiblot 	      [SD_HS]		= "SD High Speed (50MHz)",
17235f9e196SJean-Jacques Hiblot 	      [UHS_SDR12]	= "UHS SDR12 (25MHz)",
17335f9e196SJean-Jacques Hiblot 	      [UHS_SDR25]	= "UHS SDR25 (50MHz)",
17435f9e196SJean-Jacques Hiblot 	      [UHS_SDR50]	= "UHS SDR50 (100MHz)",
17535f9e196SJean-Jacques Hiblot 	      [UHS_SDR104]	= "UHS SDR104 (208MHz)",
17635f9e196SJean-Jacques Hiblot 	      [UHS_DDR50]	= "UHS DDR50 (50MHz)",
17735f9e196SJean-Jacques Hiblot 	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
17835f9e196SJean-Jacques Hiblot 	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
17935f9e196SJean-Jacques Hiblot 	      [MMC_HS_200]	= "HS200 (200MHz)",
18035f9e196SJean-Jacques Hiblot 	};
18135f9e196SJean-Jacques Hiblot 
18235f9e196SJean-Jacques Hiblot 	if (mode >= MMC_MODES_END)
18335f9e196SJean-Jacques Hiblot 		return "Unknown mode";
18435f9e196SJean-Jacques Hiblot 	else
18535f9e196SJean-Jacques Hiblot 		return names[mode];
18635f9e196SJean-Jacques Hiblot }
18735f9e196SJean-Jacques Hiblot #endif
18835f9e196SJean-Jacques Hiblot 
18905038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
19005038576SJean-Jacques Hiblot {
19105038576SJean-Jacques Hiblot 	static const int freqs[] = {
19205038576SJean-Jacques Hiblot 	      [SD_LEGACY]	= 25000000,
19305038576SJean-Jacques Hiblot 	      [MMC_HS]		= 26000000,
19405038576SJean-Jacques Hiblot 	      [SD_HS]		= 50000000,
195f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
19605038576SJean-Jacques Hiblot 	      [UHS_SDR12]	= 25000000,
19705038576SJean-Jacques Hiblot 	      [UHS_SDR25]	= 50000000,
19805038576SJean-Jacques Hiblot 	      [UHS_SDR50]	= 100000000,
19905038576SJean-Jacques Hiblot 	      [UHS_DDR50]	= 50000000,
200f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
201f99c2efeSJean-Jacques Hiblot 	      [UHS_SDR104]	= 208000000,
202f99c2efeSJean-Jacques Hiblot #endif
203f99c2efeSJean-Jacques Hiblot #endif
20405038576SJean-Jacques Hiblot 	      [MMC_HS_52]	= 52000000,
20505038576SJean-Jacques Hiblot 	      [MMC_DDR_52]	= 52000000,
206f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
20705038576SJean-Jacques Hiblot 	      [MMC_HS_200]	= 200000000,
208f99c2efeSJean-Jacques Hiblot #endif
20905038576SJean-Jacques Hiblot 	};
21005038576SJean-Jacques Hiblot 
21105038576SJean-Jacques Hiblot 	if (mode == MMC_LEGACY)
21205038576SJean-Jacques Hiblot 		return mmc->legacy_speed;
21305038576SJean-Jacques Hiblot 	else if (mode >= MMC_MODES_END)
21405038576SJean-Jacques Hiblot 		return 0;
21505038576SJean-Jacques Hiblot 	else
21605038576SJean-Jacques Hiblot 		return freqs[mode];
21705038576SJean-Jacques Hiblot }
21805038576SJean-Jacques Hiblot 
21935f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode)
22035f9e196SJean-Jacques Hiblot {
22135f9e196SJean-Jacques Hiblot 	mmc->selected_mode = mode;
22205038576SJean-Jacques Hiblot 	mmc->tran_speed = mmc_mode2freq(mmc, mode);
2233862b854SJean-Jacques Hiblot 	mmc->ddr_mode = mmc_is_mode_ddr(mode);
22435f9e196SJean-Jacques Hiblot 	debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
22535f9e196SJean-Jacques Hiblot 	      mmc->tran_speed / 1000000);
22635f9e196SJean-Jacques Hiblot 	return 0;
22735f9e196SJean-Jacques Hiblot }
22835f9e196SJean-Jacques Hiblot 
229e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
230c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
231c0c76ebaSSimon Glass {
232c0c76ebaSSimon Glass 	int ret;
233c0c76ebaSSimon Glass 
234c0c76ebaSSimon Glass 	mmmc_trace_before_send(mmc, cmd);
235c0c76ebaSSimon Glass 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
236c0c76ebaSSimon Glass 	mmmc_trace_after_send(mmc, cmd, ret);
237c0c76ebaSSimon Glass 
2388635ff9eSMarek Vasut 	return ret;
239272cc70bSAndy Fleming }
2408ca51e51SSimon Glass #endif
241272cc70bSAndy Fleming 
242da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
2435d4fc8d9SRaffaele Recalcati {
2445d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
245d617c426SJan Kloetzke 	int err, retries = 5;
2465d4fc8d9SRaffaele Recalcati 
2475d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
2485d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
249aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
250aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
2515d4fc8d9SRaffaele Recalcati 
2521677eef4SAndrew Gabbasov 	while (1) {
2535d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
254d617c426SJan Kloetzke 		if (!err) {
255d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
256d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
257d617c426SJan Kloetzke 			     MMC_STATE_PRG)
2585d4fc8d9SRaffaele Recalcati 				break;
259d0c221feSJean-Jacques Hiblot 
260d0c221feSJean-Jacques Hiblot 			if (cmd.response[0] & MMC_STATUS_MASK) {
26156196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
262d8e3d420SJean-Jacques Hiblot 				pr_err("Status Error: 0x%08X\n",
263d617c426SJan Kloetzke 				       cmd.response[0]);
26456196826SPaul Burton #endif
265915ffa52SJaehoon Chung 				return -ECOMM;
266d617c426SJan Kloetzke 			}
267d617c426SJan Kloetzke 		} else if (--retries < 0)
268d617c426SJan Kloetzke 			return err;
2695d4fc8d9SRaffaele Recalcati 
2701677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
2711677eef4SAndrew Gabbasov 			break;
2725d4fc8d9SRaffaele Recalcati 
2731677eef4SAndrew Gabbasov 		udelay(1000);
2741677eef4SAndrew Gabbasov 	}
2755d4fc8d9SRaffaele Recalcati 
276c0c76ebaSSimon Glass 	mmc_trace_state(mmc, &cmd);
2775b0c942fSJongman Heo 	if (timeout <= 0) {
27856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
279d8e3d420SJean-Jacques Hiblot 		pr_err("Timeout waiting card ready\n");
28056196826SPaul Burton #endif
281915ffa52SJaehoon Chung 		return -ETIMEDOUT;
2825d4fc8d9SRaffaele Recalcati 	}
2835d4fc8d9SRaffaele Recalcati 
2845d4fc8d9SRaffaele Recalcati 	return 0;
2855d4fc8d9SRaffaele Recalcati }
2865d4fc8d9SRaffaele Recalcati 
287da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
288272cc70bSAndy Fleming {
289272cc70bSAndy Fleming 	struct mmc_cmd cmd;
29083dc4227SKishon Vijay Abraham I 	int err;
291272cc70bSAndy Fleming 
292786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
293d22e3d46SJaehoon Chung 		return 0;
294d22e3d46SJaehoon Chung 
295272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
296272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
297272cc70bSAndy Fleming 	cmd.cmdarg = len;
298272cc70bSAndy Fleming 
29983dc4227SKishon Vijay Abraham I 	err = mmc_send_cmd(mmc, &cmd, NULL);
30083dc4227SKishon Vijay Abraham I 
30183dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
30283dc4227SKishon Vijay Abraham I 	if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) {
30383dc4227SKishon Vijay Abraham I 		int retries = 4;
30483dc4227SKishon Vijay Abraham I 		/*
30583dc4227SKishon Vijay Abraham I 		 * It has been seen that SET_BLOCKLEN may fail on the first
30683dc4227SKishon Vijay Abraham I 		 * attempt, let's try a few more time
30783dc4227SKishon Vijay Abraham I 		 */
30883dc4227SKishon Vijay Abraham I 		do {
30983dc4227SKishon Vijay Abraham I 			err = mmc_send_cmd(mmc, &cmd, NULL);
31083dc4227SKishon Vijay Abraham I 			if (!err)
31183dc4227SKishon Vijay Abraham I 				break;
31283dc4227SKishon Vijay Abraham I 		} while (retries--);
31383dc4227SKishon Vijay Abraham I 	}
31483dc4227SKishon Vijay Abraham I #endif
31583dc4227SKishon Vijay Abraham I 
31683dc4227SKishon Vijay Abraham I 	return err;
317272cc70bSAndy Fleming }
318272cc70bSAndy Fleming 
319f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
3209815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_4bit[] = {
3219815e3baSJean-Jacques Hiblot 	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
3229815e3baSJean-Jacques Hiblot 	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
3239815e3baSJean-Jacques Hiblot 	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
3249815e3baSJean-Jacques Hiblot 	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
3259815e3baSJean-Jacques Hiblot 	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
3269815e3baSJean-Jacques Hiblot 	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
3279815e3baSJean-Jacques Hiblot 	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
3289815e3baSJean-Jacques Hiblot 	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
3299815e3baSJean-Jacques Hiblot };
3309815e3baSJean-Jacques Hiblot 
3319815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_8bit[] = {
3329815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
3339815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
3349815e3baSJean-Jacques Hiblot 	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
3359815e3baSJean-Jacques Hiblot 	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
3369815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
3379815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
3389815e3baSJean-Jacques Hiblot 	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
3399815e3baSJean-Jacques Hiblot 	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
3409815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
3419815e3baSJean-Jacques Hiblot 	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
3429815e3baSJean-Jacques Hiblot 	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
3439815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
3449815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
3459815e3baSJean-Jacques Hiblot 	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
3469815e3baSJean-Jacques Hiblot 	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
3479815e3baSJean-Jacques Hiblot 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
3489815e3baSJean-Jacques Hiblot };
3499815e3baSJean-Jacques Hiblot 
3509815e3baSJean-Jacques Hiblot int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error)
3519815e3baSJean-Jacques Hiblot {
3529815e3baSJean-Jacques Hiblot 	struct mmc_cmd cmd;
3539815e3baSJean-Jacques Hiblot 	struct mmc_data data;
3549815e3baSJean-Jacques Hiblot 	const u8 *tuning_block_pattern;
3559815e3baSJean-Jacques Hiblot 	int size, err;
3569815e3baSJean-Jacques Hiblot 
3579815e3baSJean-Jacques Hiblot 	if (mmc->bus_width == 8) {
3589815e3baSJean-Jacques Hiblot 		tuning_block_pattern = tuning_blk_pattern_8bit;
3599815e3baSJean-Jacques Hiblot 		size = sizeof(tuning_blk_pattern_8bit);
3609815e3baSJean-Jacques Hiblot 	} else if (mmc->bus_width == 4) {
3619815e3baSJean-Jacques Hiblot 		tuning_block_pattern = tuning_blk_pattern_4bit;
3629815e3baSJean-Jacques Hiblot 		size = sizeof(tuning_blk_pattern_4bit);
3639815e3baSJean-Jacques Hiblot 	} else {
3649815e3baSJean-Jacques Hiblot 		return -EINVAL;
3659815e3baSJean-Jacques Hiblot 	}
3669815e3baSJean-Jacques Hiblot 
3679815e3baSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, data_buf, size);
3689815e3baSJean-Jacques Hiblot 
3699815e3baSJean-Jacques Hiblot 	cmd.cmdidx = opcode;
3709815e3baSJean-Jacques Hiblot 	cmd.cmdarg = 0;
3719815e3baSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
3729815e3baSJean-Jacques Hiblot 
3739815e3baSJean-Jacques Hiblot 	data.dest = (void *)data_buf;
3749815e3baSJean-Jacques Hiblot 	data.blocks = 1;
3759815e3baSJean-Jacques Hiblot 	data.blocksize = size;
3769815e3baSJean-Jacques Hiblot 	data.flags = MMC_DATA_READ;
3779815e3baSJean-Jacques Hiblot 
3789815e3baSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, &data);
3799815e3baSJean-Jacques Hiblot 	if (err)
3809815e3baSJean-Jacques Hiblot 		return err;
3819815e3baSJean-Jacques Hiblot 
3829815e3baSJean-Jacques Hiblot 	if (memcmp(data_buf, tuning_block_pattern, size))
3839815e3baSJean-Jacques Hiblot 		return -EIO;
3849815e3baSJean-Jacques Hiblot 
3859815e3baSJean-Jacques Hiblot 	return 0;
3869815e3baSJean-Jacques Hiblot }
387f99c2efeSJean-Jacques Hiblot #endif
3889815e3baSJean-Jacques Hiblot 
389ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
390fdbb873eSKim Phillips 			   lbaint_t blkcnt)
391272cc70bSAndy Fleming {
392272cc70bSAndy Fleming 	struct mmc_cmd cmd;
393272cc70bSAndy Fleming 	struct mmc_data data;
394272cc70bSAndy Fleming 
3954a1a06bcSAlagu Sankar 	if (blkcnt > 1)
3964a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
3974a1a06bcSAlagu Sankar 	else
398272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
399272cc70bSAndy Fleming 
400272cc70bSAndy Fleming 	if (mmc->high_capacity)
4014a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
402272cc70bSAndy Fleming 	else
4034a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
404272cc70bSAndy Fleming 
405272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
406272cc70bSAndy Fleming 
407272cc70bSAndy Fleming 	data.dest = dst;
4084a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
409272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
410272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
411272cc70bSAndy Fleming 
4124a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
4134a1a06bcSAlagu Sankar 		return 0;
4144a1a06bcSAlagu Sankar 
4154a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
4164a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
4174a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
4184a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
4194a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
42056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
421d8e3d420SJean-Jacques Hiblot 			pr_err("mmc fail to send stop cmd\n");
42256196826SPaul Burton #endif
4234a1a06bcSAlagu Sankar 			return 0;
4244a1a06bcSAlagu Sankar 		}
425272cc70bSAndy Fleming 	}
426272cc70bSAndy Fleming 
4274a1a06bcSAlagu Sankar 	return blkcnt;
428272cc70bSAndy Fleming }
429272cc70bSAndy Fleming 
430c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
4317dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
43233fb211dSSimon Glass #else
4337dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
4347dba0b93SSimon Glass 		void *dst)
43533fb211dSSimon Glass #endif
436272cc70bSAndy Fleming {
437c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
43833fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
43933fb211dSSimon Glass #endif
440bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
441873cc1d7SStephen Warren 	int err;
4424a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
443272cc70bSAndy Fleming 
4444a1a06bcSAlagu Sankar 	if (blkcnt == 0)
4454a1a06bcSAlagu Sankar 		return 0;
4464a1a06bcSAlagu Sankar 
4474a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
448272cc70bSAndy Fleming 	if (!mmc)
449272cc70bSAndy Fleming 		return 0;
450272cc70bSAndy Fleming 
451b5b838f1SMarek Vasut 	if (CONFIG_IS_ENABLED(MMC_TINY))
452b5b838f1SMarek Vasut 		err = mmc_switch_part(mmc, block_dev->hwpart);
453b5b838f1SMarek Vasut 	else
45469f45cd5SSimon Glass 		err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
455b5b838f1SMarek Vasut 
456873cc1d7SStephen Warren 	if (err < 0)
457873cc1d7SStephen Warren 		return 0;
458873cc1d7SStephen Warren 
459c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
46056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
461d8e3d420SJean-Jacques Hiblot 		pr_err("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
462c40fdca6SSimon Glass 		       start + blkcnt, block_dev->lba);
46356196826SPaul Burton #endif
464d2bf29e3SLei Wen 		return 0;
465d2bf29e3SLei Wen 	}
466272cc70bSAndy Fleming 
46711692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
46811692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
469272cc70bSAndy Fleming 		return 0;
47011692991SSimon Glass 	}
471272cc70bSAndy Fleming 
4724a1a06bcSAlagu Sankar 	do {
47393bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
47493bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
47511692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
47611692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
4774a1a06bcSAlagu Sankar 			return 0;
47811692991SSimon Glass 		}
4794a1a06bcSAlagu Sankar 		blocks_todo -= cur;
4804a1a06bcSAlagu Sankar 		start += cur;
4814a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
4824a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
483272cc70bSAndy Fleming 
484272cc70bSAndy Fleming 	return blkcnt;
485272cc70bSAndy Fleming }
486272cc70bSAndy Fleming 
487fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
488272cc70bSAndy Fleming {
489272cc70bSAndy Fleming 	struct mmc_cmd cmd;
490272cc70bSAndy Fleming 	int err;
491272cc70bSAndy Fleming 
492272cc70bSAndy Fleming 	udelay(1000);
493272cc70bSAndy Fleming 
494272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
495272cc70bSAndy Fleming 	cmd.cmdarg = 0;
496272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
497272cc70bSAndy Fleming 
498272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
499272cc70bSAndy Fleming 
500272cc70bSAndy Fleming 	if (err)
501272cc70bSAndy Fleming 		return err;
502272cc70bSAndy Fleming 
503272cc70bSAndy Fleming 	udelay(2000);
504272cc70bSAndy Fleming 
505272cc70bSAndy Fleming 	return 0;
506272cc70bSAndy Fleming }
507272cc70bSAndy Fleming 
508f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
509c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage)
510c10b85d6SJean-Jacques Hiblot {
511c10b85d6SJean-Jacques Hiblot 	struct mmc_cmd cmd;
512c10b85d6SJean-Jacques Hiblot 	int err = 0;
513c10b85d6SJean-Jacques Hiblot 
514c10b85d6SJean-Jacques Hiblot 	/*
515c10b85d6SJean-Jacques Hiblot 	 * Send CMD11 only if the request is to switch the card to
516c10b85d6SJean-Jacques Hiblot 	 * 1.8V signalling.
517c10b85d6SJean-Jacques Hiblot 	 */
518c10b85d6SJean-Jacques Hiblot 	if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
519c10b85d6SJean-Jacques Hiblot 		return mmc_set_signal_voltage(mmc, signal_voltage);
520c10b85d6SJean-Jacques Hiblot 
521c10b85d6SJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_SWITCH_UHS18V;
522c10b85d6SJean-Jacques Hiblot 	cmd.cmdarg = 0;
523c10b85d6SJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
524c10b85d6SJean-Jacques Hiblot 
525c10b85d6SJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
526c10b85d6SJean-Jacques Hiblot 	if (err)
527c10b85d6SJean-Jacques Hiblot 		return err;
528c10b85d6SJean-Jacques Hiblot 
529c10b85d6SJean-Jacques Hiblot 	if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR))
530c10b85d6SJean-Jacques Hiblot 		return -EIO;
531c10b85d6SJean-Jacques Hiblot 
532c10b85d6SJean-Jacques Hiblot 	/*
533c10b85d6SJean-Jacques Hiblot 	 * The card should drive cmd and dat[0:3] low immediately
534c10b85d6SJean-Jacques Hiblot 	 * after the response of cmd11, but wait 100 us to be sure
535c10b85d6SJean-Jacques Hiblot 	 */
536c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 0, 100);
537c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
538c10b85d6SJean-Jacques Hiblot 		udelay(100);
539c10b85d6SJean-Jacques Hiblot 	else if (err)
540c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
541c10b85d6SJean-Jacques Hiblot 
542c10b85d6SJean-Jacques Hiblot 	/*
543c10b85d6SJean-Jacques Hiblot 	 * During a signal voltage level switch, the clock must be gated
544c10b85d6SJean-Jacques Hiblot 	 * for 5 ms according to the SD spec
545c10b85d6SJean-Jacques Hiblot 	 */
546c10b85d6SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->clock, true);
547c10b85d6SJean-Jacques Hiblot 
548c10b85d6SJean-Jacques Hiblot 	err = mmc_set_signal_voltage(mmc, signal_voltage);
549c10b85d6SJean-Jacques Hiblot 	if (err)
550c10b85d6SJean-Jacques Hiblot 		return err;
551c10b85d6SJean-Jacques Hiblot 
552c10b85d6SJean-Jacques Hiblot 	/* Keep clock gated for at least 10 ms, though spec only says 5 ms */
553c10b85d6SJean-Jacques Hiblot 	mdelay(10);
554c10b85d6SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->clock, false);
555c10b85d6SJean-Jacques Hiblot 
556c10b85d6SJean-Jacques Hiblot 	/*
557c10b85d6SJean-Jacques Hiblot 	 * Failure to switch is indicated by the card holding
558c10b85d6SJean-Jacques Hiblot 	 * dat[0:3] low. Wait for at least 1 ms according to spec
559c10b85d6SJean-Jacques Hiblot 	 */
560c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 1, 1000);
561c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
562c10b85d6SJean-Jacques Hiblot 		udelay(1000);
563c10b85d6SJean-Jacques Hiblot 	else if (err)
564c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
565c10b85d6SJean-Jacques Hiblot 
566c10b85d6SJean-Jacques Hiblot 	return 0;
567c10b85d6SJean-Jacques Hiblot }
568f99c2efeSJean-Jacques Hiblot #endif
569c10b85d6SJean-Jacques Hiblot 
570c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en)
571272cc70bSAndy Fleming {
572272cc70bSAndy Fleming 	int timeout = 1000;
573272cc70bSAndy Fleming 	int err;
574272cc70bSAndy Fleming 	struct mmc_cmd cmd;
575272cc70bSAndy Fleming 
5761677eef4SAndrew Gabbasov 	while (1) {
577272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
578272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
579272cc70bSAndy Fleming 		cmd.cmdarg = 0;
580272cc70bSAndy Fleming 
581272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
582272cc70bSAndy Fleming 
583272cc70bSAndy Fleming 		if (err)
584272cc70bSAndy Fleming 			return err;
585272cc70bSAndy Fleming 
586272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
587272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
588250de12bSStefano Babic 
589250de12bSStefano Babic 		/*
590250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
591250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
592250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
593250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
594250de12bSStefano Babic 		 * specified.
595250de12bSStefano Babic 		 */
596d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
59793bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
598272cc70bSAndy Fleming 
599272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
600272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
601272cc70bSAndy Fleming 
602c10b85d6SJean-Jacques Hiblot 		if (uhs_en)
603c10b85d6SJean-Jacques Hiblot 			cmd.cmdarg |= OCR_S18R;
604c10b85d6SJean-Jacques Hiblot 
605272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
606272cc70bSAndy Fleming 
607272cc70bSAndy Fleming 		if (err)
608272cc70bSAndy Fleming 			return err;
609272cc70bSAndy Fleming 
6101677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
6111677eef4SAndrew Gabbasov 			break;
612272cc70bSAndy Fleming 
6131677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
614915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
615272cc70bSAndy Fleming 
6161677eef4SAndrew Gabbasov 		udelay(1000);
6171677eef4SAndrew Gabbasov 	}
6181677eef4SAndrew Gabbasov 
619272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
620272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
621272cc70bSAndy Fleming 
622d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
623d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
624d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
625d52ebf10SThomas Chou 		cmd.cmdarg = 0;
626d52ebf10SThomas Chou 
627d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
628d52ebf10SThomas Chou 
629d52ebf10SThomas Chou 		if (err)
630d52ebf10SThomas Chou 			return err;
631d52ebf10SThomas Chou 	}
632d52ebf10SThomas Chou 
633998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
634272cc70bSAndy Fleming 
635f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
636c10b85d6SJean-Jacques Hiblot 	if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000)
637c10b85d6SJean-Jacques Hiblot 	    == 0x41000000) {
638c10b85d6SJean-Jacques Hiblot 		err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
639c10b85d6SJean-Jacques Hiblot 		if (err)
640c10b85d6SJean-Jacques Hiblot 			return err;
641c10b85d6SJean-Jacques Hiblot 	}
642f99c2efeSJean-Jacques Hiblot #endif
643c10b85d6SJean-Jacques Hiblot 
644272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
645272cc70bSAndy Fleming 	mmc->rca = 0;
646272cc70bSAndy Fleming 
647272cc70bSAndy Fleming 	return 0;
648272cc70bSAndy Fleming }
649272cc70bSAndy Fleming 
6505289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
651272cc70bSAndy Fleming {
6525289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
653272cc70bSAndy Fleming 	int err;
654272cc70bSAndy Fleming 
6555289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
6565289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
6575289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
6585a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
6595a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
66093bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
661a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
662a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
663e9550449SChe-Liang Chiou 
6645289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
665e9550449SChe-Liang Chiou 	if (err)
666e9550449SChe-Liang Chiou 		return err;
6675289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
668e9550449SChe-Liang Chiou 	return 0;
669e9550449SChe-Liang Chiou }
670e9550449SChe-Liang Chiou 
671750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
672e9550449SChe-Liang Chiou {
673e9550449SChe-Liang Chiou 	int err, i;
674e9550449SChe-Liang Chiou 
675272cc70bSAndy Fleming 	/* Some cards seem to need this */
676272cc70bSAndy Fleming 	mmc_go_idle(mmc);
677272cc70bSAndy Fleming 
67831cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
679e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
6805289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
68131cacbabSRaffaele Recalcati 		if (err)
68231cacbabSRaffaele Recalcati 			return err;
68331cacbabSRaffaele Recalcati 
684e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
685a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
686bd47c135SAndrew Gabbasov 			break;
687e9550449SChe-Liang Chiou 	}
688bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
689bd47c135SAndrew Gabbasov 	return 0;
690e9550449SChe-Liang Chiou }
69131cacbabSRaffaele Recalcati 
692750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
693e9550449SChe-Liang Chiou {
694e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
695e9550449SChe-Liang Chiou 	int timeout = 1000;
696e9550449SChe-Liang Chiou 	uint start;
697e9550449SChe-Liang Chiou 	int err;
698e9550449SChe-Liang Chiou 
699e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
700cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
701d188b113SYangbo Lu 		/* Some cards seem to need this */
702d188b113SYangbo Lu 		mmc_go_idle(mmc);
703d188b113SYangbo Lu 
704e9550449SChe-Liang Chiou 		start = get_timer(0);
7051677eef4SAndrew Gabbasov 		while (1) {
7065289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
707272cc70bSAndy Fleming 			if (err)
708272cc70bSAndy Fleming 				return err;
7091677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
7101677eef4SAndrew Gabbasov 				break;
711e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
712915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
713e9550449SChe-Liang Chiou 			udelay(100);
7141677eef4SAndrew Gabbasov 		}
715cc17c01fSAndrew Gabbasov 	}
716272cc70bSAndy Fleming 
717d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
718d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
719d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
720d52ebf10SThomas Chou 		cmd.cmdarg = 0;
721d52ebf10SThomas Chou 
722d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
723d52ebf10SThomas Chou 
724d52ebf10SThomas Chou 		if (err)
725d52ebf10SThomas Chou 			return err;
726a626c8d4SAndrew Gabbasov 
727a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
728d52ebf10SThomas Chou 	}
729d52ebf10SThomas Chou 
730272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
731272cc70bSAndy Fleming 
732272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
733def816a2SStephen Warren 	mmc->rca = 1;
734272cc70bSAndy Fleming 
735272cc70bSAndy Fleming 	return 0;
736272cc70bSAndy Fleming }
737272cc70bSAndy Fleming 
738272cc70bSAndy Fleming 
739fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
740272cc70bSAndy Fleming {
741272cc70bSAndy Fleming 	struct mmc_cmd cmd;
742272cc70bSAndy Fleming 	struct mmc_data data;
743272cc70bSAndy Fleming 	int err;
744272cc70bSAndy Fleming 
745272cc70bSAndy Fleming 	/* Get the Card Status Register */
746272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
747272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
748272cc70bSAndy Fleming 	cmd.cmdarg = 0;
749272cc70bSAndy Fleming 
750cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
751272cc70bSAndy Fleming 	data.blocks = 1;
7528bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
753272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
754272cc70bSAndy Fleming 
755272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
756272cc70bSAndy Fleming 
757272cc70bSAndy Fleming 	return err;
758272cc70bSAndy Fleming }
759272cc70bSAndy Fleming 
760c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
761272cc70bSAndy Fleming {
762272cc70bSAndy Fleming 	struct mmc_cmd cmd;
7635d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
764a9003dc6SMaxime Ripard 	int retries = 3;
7655d4fc8d9SRaffaele Recalcati 	int ret;
766272cc70bSAndy Fleming 
767272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
768272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
769272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
770272cc70bSAndy Fleming 				 (index << 16) |
771272cc70bSAndy Fleming 				 (value << 8);
772272cc70bSAndy Fleming 
773a9003dc6SMaxime Ripard 	while (retries > 0) {
7745d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
7755d4fc8d9SRaffaele Recalcati 
7765d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
777a9003dc6SMaxime Ripard 		if (!ret) {
77893ad0d18SJan Kloetzke 			ret = mmc_send_status(mmc, timeout);
779a9003dc6SMaxime Ripard 			return ret;
780a9003dc6SMaxime Ripard 		}
781a9003dc6SMaxime Ripard 
782a9003dc6SMaxime Ripard 		retries--;
783a9003dc6SMaxime Ripard 	}
7845d4fc8d9SRaffaele Recalcati 
7855d4fc8d9SRaffaele Recalcati 	return ret;
7865d4fc8d9SRaffaele Recalcati 
787272cc70bSAndy Fleming }
788272cc70bSAndy Fleming 
7893862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
790272cc70bSAndy Fleming {
791272cc70bSAndy Fleming 	int err;
7923862b854SJean-Jacques Hiblot 	int speed_bits;
7933862b854SJean-Jacques Hiblot 
7943862b854SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
7953862b854SJean-Jacques Hiblot 
7963862b854SJean-Jacques Hiblot 	switch (mode) {
7973862b854SJean-Jacques Hiblot 	case MMC_HS:
7983862b854SJean-Jacques Hiblot 	case MMC_HS_52:
7993862b854SJean-Jacques Hiblot 	case MMC_DDR_52:
8003862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_HS;
801634d4849SKishon Vijay Abraham I 		break;
802*baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
803634d4849SKishon Vijay Abraham I 	case MMC_HS_200:
804634d4849SKishon Vijay Abraham I 		speed_bits = EXT_CSD_TIMING_HS200;
805634d4849SKishon Vijay Abraham I 		break;
806*baef2070SJean-Jacques Hiblot #endif
8073862b854SJean-Jacques Hiblot 	case MMC_LEGACY:
8083862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_LEGACY;
8093862b854SJean-Jacques Hiblot 		break;
8103862b854SJean-Jacques Hiblot 	default:
8113862b854SJean-Jacques Hiblot 		return -EINVAL;
8123862b854SJean-Jacques Hiblot 	}
8133862b854SJean-Jacques Hiblot 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
8143862b854SJean-Jacques Hiblot 			 speed_bits);
8153862b854SJean-Jacques Hiblot 	if (err)
8163862b854SJean-Jacques Hiblot 		return err;
8173862b854SJean-Jacques Hiblot 
8183862b854SJean-Jacques Hiblot 	if ((mode == MMC_HS) || (mode == MMC_HS_52)) {
8193862b854SJean-Jacques Hiblot 		/* Now check to see that it worked */
8203862b854SJean-Jacques Hiblot 		err = mmc_send_ext_csd(mmc, test_csd);
8213862b854SJean-Jacques Hiblot 		if (err)
8223862b854SJean-Jacques Hiblot 			return err;
8233862b854SJean-Jacques Hiblot 
8243862b854SJean-Jacques Hiblot 		/* No high-speed support */
8253862b854SJean-Jacques Hiblot 		if (!test_csd[EXT_CSD_HS_TIMING])
8263862b854SJean-Jacques Hiblot 			return -ENOTSUPP;
8273862b854SJean-Jacques Hiblot 	}
8283862b854SJean-Jacques Hiblot 
8293862b854SJean-Jacques Hiblot 	return 0;
8303862b854SJean-Jacques Hiblot }
8313862b854SJean-Jacques Hiblot 
8323862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc)
8333862b854SJean-Jacques Hiblot {
8343862b854SJean-Jacques Hiblot 	u8 *ext_csd = mmc->ext_csd;
8353862b854SJean-Jacques Hiblot 	char cardtype;
836272cc70bSAndy Fleming 
83700e446faSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY);
838272cc70bSAndy Fleming 
839d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
840d52ebf10SThomas Chou 		return 0;
841d52ebf10SThomas Chou 
842272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
843272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
844272cc70bSAndy Fleming 		return 0;
845272cc70bSAndy Fleming 
8463862b854SJean-Jacques Hiblot 	if (!ext_csd) {
847d8e3d420SJean-Jacques Hiblot 		pr_err("No ext_csd found!\n"); /* this should enver happen */
8483862b854SJean-Jacques Hiblot 		return -ENOTSUPP;
8493862b854SJean-Jacques Hiblot 	}
8503862b854SJean-Jacques Hiblot 
851fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
852fc5b32fbSAndrew Gabbasov 
853634d4849SKishon Vijay Abraham I 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
854bc1e3272SJean-Jacques Hiblot 	mmc->cardtype = cardtype;
855272cc70bSAndy Fleming 
856*baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
857634d4849SKishon Vijay Abraham I 	if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
858634d4849SKishon Vijay Abraham I 			EXT_CSD_CARD_TYPE_HS200_1_8V)) {
859634d4849SKishon Vijay Abraham I 		mmc->card_caps |= MMC_MODE_HS200;
860634d4849SKishon Vijay Abraham I 	}
861*baef2070SJean-Jacques Hiblot #endif
862d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
8633862b854SJean-Jacques Hiblot 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
864d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
8653862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS_52MHz;
866d22e3d46SJaehoon Chung 	}
8673862b854SJean-Jacques Hiblot 	if (cardtype & EXT_CSD_CARD_TYPE_26)
8683862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS;
869272cc70bSAndy Fleming 
870272cc70bSAndy Fleming 	return 0;
871272cc70bSAndy Fleming }
872272cc70bSAndy Fleming 
873f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
874f866a46dSStephen Warren {
875f866a46dSStephen Warren 	switch (part_num) {
876f866a46dSStephen Warren 	case 0:
877f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
878f866a46dSStephen Warren 		break;
879f866a46dSStephen Warren 	case 1:
880f866a46dSStephen Warren 	case 2:
881f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
882f866a46dSStephen Warren 		break;
883f866a46dSStephen Warren 	case 3:
884f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
885f866a46dSStephen Warren 		break;
886f866a46dSStephen Warren 	case 4:
887f866a46dSStephen Warren 	case 5:
888f866a46dSStephen Warren 	case 6:
889f866a46dSStephen Warren 	case 7:
890f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
891f866a46dSStephen Warren 		break;
892f866a46dSStephen Warren 	default:
893f866a46dSStephen Warren 		return -1;
894f866a46dSStephen Warren 	}
895f866a46dSStephen Warren 
896c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
897f866a46dSStephen Warren 
898f866a46dSStephen Warren 	return 0;
899f866a46dSStephen Warren }
900f866a46dSStephen Warren 
901f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
90201298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num)
90301298da3SJean-Jacques Hiblot {
90401298da3SJean-Jacques Hiblot 	int forbidden = 0;
90501298da3SJean-Jacques Hiblot 	bool change = false;
90601298da3SJean-Jacques Hiblot 
90701298da3SJean-Jacques Hiblot 	if (part_num & PART_ACCESS_MASK)
90801298da3SJean-Jacques Hiblot 		forbidden = MMC_CAP(MMC_HS_200);
90901298da3SJean-Jacques Hiblot 
91001298da3SJean-Jacques Hiblot 	if (MMC_CAP(mmc->selected_mode) & forbidden) {
91101298da3SJean-Jacques Hiblot 		debug("selected mode (%s) is forbidden for part %d\n",
91201298da3SJean-Jacques Hiblot 		      mmc_mode_name(mmc->selected_mode), part_num);
91301298da3SJean-Jacques Hiblot 		change = true;
91401298da3SJean-Jacques Hiblot 	} else if (mmc->selected_mode != mmc->best_mode) {
91501298da3SJean-Jacques Hiblot 		debug("selected mode is not optimal\n");
91601298da3SJean-Jacques Hiblot 		change = true;
91701298da3SJean-Jacques Hiblot 	}
91801298da3SJean-Jacques Hiblot 
91901298da3SJean-Jacques Hiblot 	if (change)
92001298da3SJean-Jacques Hiblot 		return mmc_select_mode_and_width(mmc,
92101298da3SJean-Jacques Hiblot 						 mmc->card_caps & ~forbidden);
92201298da3SJean-Jacques Hiblot 
92301298da3SJean-Jacques Hiblot 	return 0;
92401298da3SJean-Jacques Hiblot }
925f99c2efeSJean-Jacques Hiblot #else
926f99c2efeSJean-Jacques Hiblot static inline int mmc_boot_part_access_chk(struct mmc *mmc,
927f99c2efeSJean-Jacques Hiblot 					   unsigned int part_num)
928f99c2efeSJean-Jacques Hiblot {
929f99c2efeSJean-Jacques Hiblot 	return 0;
930f99c2efeSJean-Jacques Hiblot }
931f99c2efeSJean-Jacques Hiblot #endif
93201298da3SJean-Jacques Hiblot 
9337dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
934bc897b1dSLei Wen {
935f866a46dSStephen Warren 	int ret;
936bc897b1dSLei Wen 
93701298da3SJean-Jacques Hiblot 	ret = mmc_boot_part_access_chk(mmc, part_num);
93801298da3SJean-Jacques Hiblot 	if (ret)
93901298da3SJean-Jacques Hiblot 		return ret;
94001298da3SJean-Jacques Hiblot 
941f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
942bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
943bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
944f866a46dSStephen Warren 
9456dc93e70SPeter Bigot 	/*
9466dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
9476dc93e70SPeter Bigot 	 * to return to representing the raw device.
9486dc93e70SPeter Bigot 	 */
949873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
9506dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
951fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
952873cc1d7SStephen Warren 	}
9536dc93e70SPeter Bigot 
9546dc93e70SPeter Bigot 	return ret;
955bc897b1dSLei Wen }
956bc897b1dSLei Wen 
957cf17789eSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
958ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
959ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
960ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
961ac9da0e0SDiego Santa Cruz {
962ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
963ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
964ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
965ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
966ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
967ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
9688dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
969ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
970ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
971ac9da0e0SDiego Santa Cruz 
972ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
973ac9da0e0SDiego Santa Cruz 		return -EINVAL;
974ac9da0e0SDiego Santa Cruz 
975ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
976d8e3d420SJean-Jacques Hiblot 		pr_err("eMMC >= 4.4 required for enhanced user data area\n");
977ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
978ac9da0e0SDiego Santa Cruz 	}
979ac9da0e0SDiego Santa Cruz 
980ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
981d8e3d420SJean-Jacques Hiblot 		pr_err("Card does not support partitioning\n");
982ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
983ac9da0e0SDiego Santa Cruz 	}
984ac9da0e0SDiego Santa Cruz 
985ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
986d8e3d420SJean-Jacques Hiblot 		pr_err("Card does not define HC WP group size\n");
987ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
988ac9da0e0SDiego Santa Cruz 	}
989ac9da0e0SDiego Santa Cruz 
990ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
991ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
992ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
993ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
994d8e3d420SJean-Jacques Hiblot 			pr_err("User data enhanced area not HC WP group "
995ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
996ac9da0e0SDiego Santa Cruz 			return -EINVAL;
997ac9da0e0SDiego Santa Cruz 		}
998ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
999ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
1000ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
1001ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
1002ac9da0e0SDiego Santa Cruz 		} else {
1003ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
1004ac9da0e0SDiego Santa Cruz 		}
1005ac9da0e0SDiego Santa Cruz 	} else {
1006ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
1007ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
1008ac9da0e0SDiego Santa Cruz 	}
1009ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
1010ac9da0e0SDiego Santa Cruz 
1011ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1012ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
1013d8e3d420SJean-Jacques Hiblot 			pr_err("GP%i partition not HC WP group size "
1014ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
1015ac9da0e0SDiego Santa Cruz 			return -EINVAL;
1016ac9da0e0SDiego Santa Cruz 		}
1017ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
1018ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
1019ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
1020ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
1021ac9da0e0SDiego Santa Cruz 		}
1022ac9da0e0SDiego Santa Cruz 	}
1023ac9da0e0SDiego Santa Cruz 
1024ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
1025d8e3d420SJean-Jacques Hiblot 		pr_err("Card does not support enhanced attribute\n");
1026ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1027ac9da0e0SDiego Santa Cruz 	}
1028ac9da0e0SDiego Santa Cruz 
1029ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
1030ac9da0e0SDiego Santa Cruz 	if (err)
1031ac9da0e0SDiego Santa Cruz 		return err;
1032ac9da0e0SDiego Santa Cruz 
1033ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
1034ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
1035ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
1036ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
1037ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
1038d8e3d420SJean-Jacques Hiblot 		pr_err("Total enhanced size exceeds maximum (%u > %u)\n",
1039ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
1040ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1041ac9da0e0SDiego Santa Cruz 	}
1042ac9da0e0SDiego Santa Cruz 
10438dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
10448dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
10458dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
10468dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
10478dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
10488dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
10498dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
10508dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
10518dda5b0eSDiego Santa Cruz 		else
10528dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
10538dda5b0eSDiego Santa Cruz 	}
10548dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
10558dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
10568dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
10578dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
10588dda5b0eSDiego Santa Cruz 			else
10598dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
10608dda5b0eSDiego Santa Cruz 		}
10618dda5b0eSDiego Santa Cruz 	}
10628dda5b0eSDiego Santa Cruz 
10638dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
10648dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
10658dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
10668dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
10678dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
10688dda5b0eSDiego Santa Cruz 	}
10698dda5b0eSDiego Santa Cruz 
1070ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
1071ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
1072d8e3d420SJean-Jacques Hiblot 		pr_err("Card already partitioned\n");
1073ac9da0e0SDiego Santa Cruz 		return -EPERM;
1074ac9da0e0SDiego Santa Cruz 	}
1075ac9da0e0SDiego Santa Cruz 
1076ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
1077ac9da0e0SDiego Santa Cruz 		return 0;
1078ac9da0e0SDiego Santa Cruz 
1079ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
1080ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
1081ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1082ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1083ac9da0e0SDiego Santa Cruz 
1084ac9da0e0SDiego Santa Cruz 		if (err)
1085ac9da0e0SDiego Santa Cruz 			return err;
1086ac9da0e0SDiego Santa Cruz 
1087ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1088ac9da0e0SDiego Santa Cruz 
1089ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
1090ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
1091ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1092ac9da0e0SDiego Santa Cruz 
1093ac9da0e0SDiego Santa Cruz 	}
1094ac9da0e0SDiego Santa Cruz 
1095ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
1096ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
1097ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1098ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
1099ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
1100ac9da0e0SDiego Santa Cruz 		if (err)
1101ac9da0e0SDiego Santa Cruz 			return err;
1102ac9da0e0SDiego Santa Cruz 	}
1103ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
1104ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1105ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
1106ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
1107ac9da0e0SDiego Santa Cruz 		if (err)
1108ac9da0e0SDiego Santa Cruz 			return err;
1109ac9da0e0SDiego Santa Cruz 	}
1110ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1111ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
1112ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1113ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
1114ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
1115ac9da0e0SDiego Santa Cruz 			if (err)
1116ac9da0e0SDiego Santa Cruz 				return err;
1117ac9da0e0SDiego Santa Cruz 		}
1118ac9da0e0SDiego Santa Cruz 	}
1119ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1120ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
1121ac9da0e0SDiego Santa Cruz 	if (err)
1122ac9da0e0SDiego Santa Cruz 		return err;
1123ac9da0e0SDiego Santa Cruz 
1124ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
1125ac9da0e0SDiego Santa Cruz 		return 0;
1126ac9da0e0SDiego Santa Cruz 
11278dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
11288dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
11298dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
11308dda5b0eSDiego Santa Cruz 	 * partitioning. */
11318dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
11328dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
11338dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
11348dda5b0eSDiego Santa Cruz 		if (err)
11358dda5b0eSDiego Santa Cruz 			return err;
11368dda5b0eSDiego Santa Cruz 	}
11378dda5b0eSDiego Santa Cruz 
1138ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
1139ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
1140ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
1141ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
1142ac9da0e0SDiego Santa Cruz 
1143ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1144ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
1145ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
1146ac9da0e0SDiego Santa Cruz 	if (err)
1147ac9da0e0SDiego Santa Cruz 		return err;
1148ac9da0e0SDiego Santa Cruz 
1149ac9da0e0SDiego Santa Cruz 	return 0;
1150ac9da0e0SDiego Santa Cruz }
1151cf17789eSJean-Jacques Hiblot #endif
1152ac9da0e0SDiego Santa Cruz 
1153e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
115448972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
115548972d90SThierry Reding {
115648972d90SThierry Reding 	int cd;
115748972d90SThierry Reding 
115848972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
115948972d90SThierry Reding 
1160d4e1da4eSPeter Korsgaard 	if (cd < 0) {
116193bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
116293bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
1163d4e1da4eSPeter Korsgaard 		else
1164d4e1da4eSPeter Korsgaard 			cd = 1;
1165d4e1da4eSPeter Korsgaard 	}
116648972d90SThierry Reding 
116748972d90SThierry Reding 	return cd;
116848972d90SThierry Reding }
11698ca51e51SSimon Glass #endif
117048972d90SThierry Reding 
1171fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
1172272cc70bSAndy Fleming {
1173272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1174272cc70bSAndy Fleming 	struct mmc_data data;
1175272cc70bSAndy Fleming 
1176272cc70bSAndy Fleming 	/* Switch the frequency */
1177272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
1178272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1179272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
1180272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
1181272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
1182272cc70bSAndy Fleming 
1183272cc70bSAndy Fleming 	data.dest = (char *)resp;
1184272cc70bSAndy Fleming 	data.blocksize = 64;
1185272cc70bSAndy Fleming 	data.blocks = 1;
1186272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1187272cc70bSAndy Fleming 
1188272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
1189272cc70bSAndy Fleming }
1190272cc70bSAndy Fleming 
1191272cc70bSAndy Fleming 
1192d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc)
1193272cc70bSAndy Fleming {
1194272cc70bSAndy Fleming 	int err;
1195272cc70bSAndy Fleming 	struct mmc_cmd cmd;
119618e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
119718e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
1198272cc70bSAndy Fleming 	struct mmc_data data;
1199272cc70bSAndy Fleming 	int timeout;
1200f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1201c10b85d6SJean-Jacques Hiblot 	u32 sd3_bus_mode;
1202f99c2efeSJean-Jacques Hiblot #endif
1203272cc70bSAndy Fleming 
120400e446faSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY);
1205272cc70bSAndy Fleming 
1206d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
1207d52ebf10SThomas Chou 		return 0;
1208d52ebf10SThomas Chou 
1209272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
1210272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
1211272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1212272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1213272cc70bSAndy Fleming 
1214272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1215272cc70bSAndy Fleming 
1216272cc70bSAndy Fleming 	if (err)
1217272cc70bSAndy Fleming 		return err;
1218272cc70bSAndy Fleming 
1219272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
1220272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1221272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1222272cc70bSAndy Fleming 
1223272cc70bSAndy Fleming 	timeout = 3;
1224272cc70bSAndy Fleming 
1225272cc70bSAndy Fleming retry_scr:
1226f781dd38SAnton staaf 	data.dest = (char *)scr;
1227272cc70bSAndy Fleming 	data.blocksize = 8;
1228272cc70bSAndy Fleming 	data.blocks = 1;
1229272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1230272cc70bSAndy Fleming 
1231272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
1232272cc70bSAndy Fleming 
1233272cc70bSAndy Fleming 	if (err) {
1234272cc70bSAndy Fleming 		if (timeout--)
1235272cc70bSAndy Fleming 			goto retry_scr;
1236272cc70bSAndy Fleming 
1237272cc70bSAndy Fleming 		return err;
1238272cc70bSAndy Fleming 	}
1239272cc70bSAndy Fleming 
12404e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
12414e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
1242272cc70bSAndy Fleming 
1243272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
1244272cc70bSAndy Fleming 	case 0:
1245272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1246272cc70bSAndy Fleming 		break;
1247272cc70bSAndy Fleming 	case 1:
1248272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
1249272cc70bSAndy Fleming 		break;
1250272cc70bSAndy Fleming 	case 2:
1251272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
12521741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
12531741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
1254272cc70bSAndy Fleming 		break;
1255272cc70bSAndy Fleming 	default:
1256272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1257272cc70bSAndy Fleming 		break;
1258272cc70bSAndy Fleming 	}
1259272cc70bSAndy Fleming 
1260b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1261b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1262b44c7083SAlagu Sankar 
1263272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1264272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1265272cc70bSAndy Fleming 		return 0;
1266272cc70bSAndy Fleming 
1267272cc70bSAndy Fleming 	timeout = 4;
1268272cc70bSAndy Fleming 	while (timeout--) {
1269272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1270f781dd38SAnton staaf 				(u8 *)switch_status);
1271272cc70bSAndy Fleming 
1272272cc70bSAndy Fleming 		if (err)
1273272cc70bSAndy Fleming 			return err;
1274272cc70bSAndy Fleming 
1275272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
12764e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1277272cc70bSAndy Fleming 			break;
1278272cc70bSAndy Fleming 	}
1279272cc70bSAndy Fleming 
1280272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
1281d0c221feSJean-Jacques Hiblot 	if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
1282d0c221feSJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(SD_HS);
1283272cc70bSAndy Fleming 
1284f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1285c10b85d6SJean-Jacques Hiblot 	/* Version before 3.0 don't support UHS modes */
1286c10b85d6SJean-Jacques Hiblot 	if (mmc->version < SD_VERSION_3)
1287c10b85d6SJean-Jacques Hiblot 		return 0;
1288c10b85d6SJean-Jacques Hiblot 
1289c10b85d6SJean-Jacques Hiblot 	sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f;
1290c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR104)
1291c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR104);
1292c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR50)
1293c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR50);
1294c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR25)
1295c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR25);
1296c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR12)
1297c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR12);
1298c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_DDR50)
1299c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_DDR50);
1300f99c2efeSJean-Jacques Hiblot #endif
1301c10b85d6SJean-Jacques Hiblot 
13022c3fbf4cSMacpaul Lin 	return 0;
1303d0c221feSJean-Jacques Hiblot }
1304d0c221feSJean-Jacques Hiblot 
1305d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
1306d0c221feSJean-Jacques Hiblot {
1307d0c221feSJean-Jacques Hiblot 	int err;
1308d0c221feSJean-Jacques Hiblot 
1309d0c221feSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
1310c10b85d6SJean-Jacques Hiblot 	int speed;
13112c3fbf4cSMacpaul Lin 
1312c10b85d6SJean-Jacques Hiblot 	switch (mode) {
1313c10b85d6SJean-Jacques Hiblot 	case SD_LEGACY:
1314c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR12_BUS_SPEED;
1315c10b85d6SJean-Jacques Hiblot 		break;
1316c10b85d6SJean-Jacques Hiblot 	case SD_HS:
1317*baef2070SJean-Jacques Hiblot 		speed = HIGH_SPEED_BUS_SPEED;
1318*baef2070SJean-Jacques Hiblot 		break;
1319*baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1320*baef2070SJean-Jacques Hiblot 	case UHS_SDR12:
1321*baef2070SJean-Jacques Hiblot 		speed = UHS_SDR12_BUS_SPEED;
1322*baef2070SJean-Jacques Hiblot 		break;
1323c10b85d6SJean-Jacques Hiblot 	case UHS_SDR25:
1324c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR25_BUS_SPEED;
1325c10b85d6SJean-Jacques Hiblot 		break;
1326c10b85d6SJean-Jacques Hiblot 	case UHS_SDR50:
1327c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR50_BUS_SPEED;
1328c10b85d6SJean-Jacques Hiblot 		break;
1329c10b85d6SJean-Jacques Hiblot 	case UHS_DDR50:
1330c10b85d6SJean-Jacques Hiblot 		speed = UHS_DDR50_BUS_SPEED;
1331c10b85d6SJean-Jacques Hiblot 		break;
1332c10b85d6SJean-Jacques Hiblot 	case UHS_SDR104:
1333c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR104_BUS_SPEED;
1334c10b85d6SJean-Jacques Hiblot 		break;
1335*baef2070SJean-Jacques Hiblot #endif
1336c10b85d6SJean-Jacques Hiblot 	default:
1337c10b85d6SJean-Jacques Hiblot 		return -EINVAL;
1338c10b85d6SJean-Jacques Hiblot 	}
1339c10b85d6SJean-Jacques Hiblot 
1340c10b85d6SJean-Jacques Hiblot 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status);
1341272cc70bSAndy Fleming 	if (err)
1342272cc70bSAndy Fleming 		return err;
1343272cc70bSAndy Fleming 
1344c10b85d6SJean-Jacques Hiblot 	if ((__be32_to_cpu(switch_status[4]) >> 24) != speed)
1345d0c221feSJean-Jacques Hiblot 		return -ENOTSUPP;
1346d0c221feSJean-Jacques Hiblot 
1347d0c221feSJean-Jacques Hiblot 	return 0;
1348d0c221feSJean-Jacques Hiblot }
1349d0c221feSJean-Jacques Hiblot 
1350d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w)
1351d0c221feSJean-Jacques Hiblot {
1352d0c221feSJean-Jacques Hiblot 	int err;
1353d0c221feSJean-Jacques Hiblot 	struct mmc_cmd cmd;
1354d0c221feSJean-Jacques Hiblot 
1355d0c221feSJean-Jacques Hiblot 	if ((w != 4) && (w != 1))
1356d0c221feSJean-Jacques Hiblot 		return -EINVAL;
1357d0c221feSJean-Jacques Hiblot 
1358d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = MMC_CMD_APP_CMD;
1359d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1360d0c221feSJean-Jacques Hiblot 	cmd.cmdarg = mmc->rca << 16;
1361d0c221feSJean-Jacques Hiblot 
1362d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1363d0c221feSJean-Jacques Hiblot 	if (err)
1364d0c221feSJean-Jacques Hiblot 		return err;
1365d0c221feSJean-Jacques Hiblot 
1366d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1367d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1368d0c221feSJean-Jacques Hiblot 	if (w == 4)
1369d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 2;
1370d0c221feSJean-Jacques Hiblot 	else if (w == 1)
1371d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 0;
1372d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1373d0c221feSJean-Jacques Hiblot 	if (err)
1374d0c221feSJean-Jacques Hiblot 		return err;
1375272cc70bSAndy Fleming 
1376272cc70bSAndy Fleming 	return 0;
1377272cc70bSAndy Fleming }
1378272cc70bSAndy Fleming 
13793697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
13803697e599SPeng Fan {
13813697e599SPeng Fan 	int err, i;
13823697e599SPeng Fan 	struct mmc_cmd cmd;
13833697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
13843697e599SPeng Fan 	struct mmc_data data;
13853697e599SPeng Fan 	int timeout = 3;
13863697e599SPeng Fan 	unsigned int au, eo, et, es;
13873697e599SPeng Fan 
13883697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
13893697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
13903697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
13913697e599SPeng Fan 
13923697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
13933697e599SPeng Fan 	if (err)
13943697e599SPeng Fan 		return err;
13953697e599SPeng Fan 
13963697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
13973697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
13983697e599SPeng Fan 	cmd.cmdarg = 0;
13993697e599SPeng Fan 
14003697e599SPeng Fan retry_ssr:
14013697e599SPeng Fan 	data.dest = (char *)ssr;
14023697e599SPeng Fan 	data.blocksize = 64;
14033697e599SPeng Fan 	data.blocks = 1;
14043697e599SPeng Fan 	data.flags = MMC_DATA_READ;
14053697e599SPeng Fan 
14063697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
14073697e599SPeng Fan 	if (err) {
14083697e599SPeng Fan 		if (timeout--)
14093697e599SPeng Fan 			goto retry_ssr;
14103697e599SPeng Fan 
14113697e599SPeng Fan 		return err;
14123697e599SPeng Fan 	}
14133697e599SPeng Fan 
14143697e599SPeng Fan 	for (i = 0; i < 16; i++)
14153697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
14163697e599SPeng Fan 
14173697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
14183697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
14193697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
14203697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
14213697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
14223697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
14233697e599SPeng Fan 		if (es && et) {
14243697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
14253697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
14263697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
14273697e599SPeng Fan 		}
14283697e599SPeng Fan 	} else {
14293697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
14303697e599SPeng Fan 	}
14313697e599SPeng Fan 
14323697e599SPeng Fan 	return 0;
14333697e599SPeng Fan }
14343697e599SPeng Fan 
1435272cc70bSAndy Fleming /* frequency bases */
1436272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
14375f837c2cSMike Frysinger static const int fbase[] = {
1438272cc70bSAndy Fleming 	10000,
1439272cc70bSAndy Fleming 	100000,
1440272cc70bSAndy Fleming 	1000000,
1441272cc70bSAndy Fleming 	10000000,
1442272cc70bSAndy Fleming };
1443272cc70bSAndy Fleming 
1444272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1445272cc70bSAndy Fleming  * to platforms without floating point.
1446272cc70bSAndy Fleming  */
144761fe076fSSimon Glass static const u8 multipliers[] = {
1448272cc70bSAndy Fleming 	0,	/* reserved */
1449272cc70bSAndy Fleming 	10,
1450272cc70bSAndy Fleming 	12,
1451272cc70bSAndy Fleming 	13,
1452272cc70bSAndy Fleming 	15,
1453272cc70bSAndy Fleming 	20,
1454272cc70bSAndy Fleming 	25,
1455272cc70bSAndy Fleming 	30,
1456272cc70bSAndy Fleming 	35,
1457272cc70bSAndy Fleming 	40,
1458272cc70bSAndy Fleming 	45,
1459272cc70bSAndy Fleming 	50,
1460272cc70bSAndy Fleming 	55,
1461272cc70bSAndy Fleming 	60,
1462272cc70bSAndy Fleming 	70,
1463272cc70bSAndy Fleming 	80,
1464272cc70bSAndy Fleming };
1465272cc70bSAndy Fleming 
1466d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap)
1467d0c221feSJean-Jacques Hiblot {
1468d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_8BIT)
1469d0c221feSJean-Jacques Hiblot 		return 8;
1470d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_4BIT)
1471d0c221feSJean-Jacques Hiblot 		return 4;
1472d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_1BIT)
1473d0c221feSJean-Jacques Hiblot 		return 1;
1474d8e3d420SJean-Jacques Hiblot 	pr_warn("invalid bus witdh capability 0x%x\n", cap);
1475d0c221feSJean-Jacques Hiblot 	return 0;
1476d0c221feSJean-Jacques Hiblot }
1477d0c221feSJean-Jacques Hiblot 
1478e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1479f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1480ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode)
1481ec841209SKishon Vijay Abraham I {
1482ec841209SKishon Vijay Abraham I 	return -ENOTSUPP;
1483ec841209SKishon Vijay Abraham I }
1484f99c2efeSJean-Jacques Hiblot #endif
1485ec841209SKishon Vijay Abraham I 
1486318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc)
1487318a7a57SJean-Jacques Hiblot {
1488318a7a57SJean-Jacques Hiblot }
1489318a7a57SJean-Jacques Hiblot 
14902a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc)
1491272cc70bSAndy Fleming {
14922a4d212fSKishon Vijay Abraham I 	int ret = 0;
14932a4d212fSKishon Vijay Abraham I 
149493bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
14952a4d212fSKishon Vijay Abraham I 		ret = mmc->cfg->ops->set_ios(mmc);
14962a4d212fSKishon Vijay Abraham I 
14972a4d212fSKishon Vijay Abraham I 	return ret;
1498272cc70bSAndy Fleming }
14998ca51e51SSimon Glass #endif
1500272cc70bSAndy Fleming 
150135f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable)
1502272cc70bSAndy Fleming {
150393bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
150493bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1505272cc70bSAndy Fleming 
150693bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
150793bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1508272cc70bSAndy Fleming 
1509272cc70bSAndy Fleming 	mmc->clock = clock;
151035f67820SKishon Vijay Abraham I 	mmc->clk_disable = disable;
1511272cc70bSAndy Fleming 
15122a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1513272cc70bSAndy Fleming }
1514272cc70bSAndy Fleming 
15152a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width)
1516272cc70bSAndy Fleming {
1517272cc70bSAndy Fleming 	mmc->bus_width = width;
1518272cc70bSAndy Fleming 
15192a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1520272cc70bSAndy Fleming }
1521272cc70bSAndy Fleming 
15224c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
15234c9d2aaaSJean-Jacques Hiblot /*
15244c9d2aaaSJean-Jacques Hiblot  * helper function to display the capabilities in a human
15254c9d2aaaSJean-Jacques Hiblot  * friendly manner. The capabilities include bus width and
15264c9d2aaaSJean-Jacques Hiblot  * supported modes.
15274c9d2aaaSJean-Jacques Hiblot  */
15284c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps)
15294c9d2aaaSJean-Jacques Hiblot {
15304c9d2aaaSJean-Jacques Hiblot 	enum bus_mode mode;
15314c9d2aaaSJean-Jacques Hiblot 
15324c9d2aaaSJean-Jacques Hiblot 	printf("%s: widths [", text);
15334c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_8BIT)
15344c9d2aaaSJean-Jacques Hiblot 		printf("8, ");
15354c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_4BIT)
15364c9d2aaaSJean-Jacques Hiblot 		printf("4, ");
1537d0c221feSJean-Jacques Hiblot 	if (caps & MMC_MODE_1BIT)
1538d0c221feSJean-Jacques Hiblot 		printf("1, ");
1539d0c221feSJean-Jacques Hiblot 	printf("\b\b] modes [");
15404c9d2aaaSJean-Jacques Hiblot 	for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
15414c9d2aaaSJean-Jacques Hiblot 		if (MMC_CAP(mode) & caps)
15424c9d2aaaSJean-Jacques Hiblot 			printf("%s, ", mmc_mode_name(mode));
15434c9d2aaaSJean-Jacques Hiblot 	printf("\b\b]\n");
15444c9d2aaaSJean-Jacques Hiblot }
15454c9d2aaaSJean-Jacques Hiblot #endif
15464c9d2aaaSJean-Jacques Hiblot 
1547d0c221feSJean-Jacques Hiblot struct mode_width_tuning {
1548d0c221feSJean-Jacques Hiblot 	enum bus_mode mode;
1549d0c221feSJean-Jacques Hiblot 	uint widths;
1550f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1551634d4849SKishon Vijay Abraham I 	uint tuning;
1552f99c2efeSJean-Jacques Hiblot #endif
1553d0c221feSJean-Jacques Hiblot };
1554d0c221feSJean-Jacques Hiblot 
1555f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
1556bc1e3272SJean-Jacques Hiblot int mmc_voltage_to_mv(enum mmc_voltage voltage)
1557bc1e3272SJean-Jacques Hiblot {
1558bc1e3272SJean-Jacques Hiblot 	switch (voltage) {
1559bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_000: return 0;
1560bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_330: return 3300;
1561bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_180: return 1800;
1562bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_120: return 1200;
1563bc1e3272SJean-Jacques Hiblot 	}
1564bc1e3272SJean-Jacques Hiblot 	return -EINVAL;
1565bc1e3272SJean-Jacques Hiblot }
1566bc1e3272SJean-Jacques Hiblot 
1567aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1568aff5d3c8SKishon Vijay Abraham I {
1569bc1e3272SJean-Jacques Hiblot 	int err;
1570bc1e3272SJean-Jacques Hiblot 
1571bc1e3272SJean-Jacques Hiblot 	if (mmc->signal_voltage == signal_voltage)
1572bc1e3272SJean-Jacques Hiblot 		return 0;
1573bc1e3272SJean-Jacques Hiblot 
1574aff5d3c8SKishon Vijay Abraham I 	mmc->signal_voltage = signal_voltage;
1575bc1e3272SJean-Jacques Hiblot 	err = mmc_set_ios(mmc);
1576bc1e3272SJean-Jacques Hiblot 	if (err)
1577bc1e3272SJean-Jacques Hiblot 		debug("unable to set voltage (err %d)\n", err);
1578bc1e3272SJean-Jacques Hiblot 
1579bc1e3272SJean-Jacques Hiblot 	return err;
1580aff5d3c8SKishon Vijay Abraham I }
1581f99c2efeSJean-Jacques Hiblot #else
1582f99c2efeSJean-Jacques Hiblot static inline int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1583f99c2efeSJean-Jacques Hiblot {
1584f99c2efeSJean-Jacques Hiblot 	return 0;
1585f99c2efeSJean-Jacques Hiblot }
1586f99c2efeSJean-Jacques Hiblot #endif
1587aff5d3c8SKishon Vijay Abraham I 
1588d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = {
1589f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1590f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1591d0c221feSJean-Jacques Hiblot 	{
1592c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR104,
1593c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1594c10b85d6SJean-Jacques Hiblot 		.tuning = MMC_CMD_SEND_TUNING_BLOCK
1595c10b85d6SJean-Jacques Hiblot 	},
1596f99c2efeSJean-Jacques Hiblot #endif
1597c10b85d6SJean-Jacques Hiblot 	{
1598c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR50,
1599c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1600c10b85d6SJean-Jacques Hiblot 	},
1601c10b85d6SJean-Jacques Hiblot 	{
1602c10b85d6SJean-Jacques Hiblot 		.mode = UHS_DDR50,
1603c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1604c10b85d6SJean-Jacques Hiblot 	},
1605c10b85d6SJean-Jacques Hiblot 	{
1606c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR25,
1607c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1608c10b85d6SJean-Jacques Hiblot 	},
1609f99c2efeSJean-Jacques Hiblot #endif
1610c10b85d6SJean-Jacques Hiblot 	{
1611d0c221feSJean-Jacques Hiblot 		.mode = SD_HS,
1612d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1613d0c221feSJean-Jacques Hiblot 	},
1614f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1615d0c221feSJean-Jacques Hiblot 	{
1616c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR12,
1617c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1618c10b85d6SJean-Jacques Hiblot 	},
1619f99c2efeSJean-Jacques Hiblot #endif
1620c10b85d6SJean-Jacques Hiblot 	{
1621d0c221feSJean-Jacques Hiblot 		.mode = SD_LEGACY,
1622d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1623d0c221feSJean-Jacques Hiblot 	}
1624d0c221feSJean-Jacques Hiblot };
1625d0c221feSJean-Jacques Hiblot 
1626d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \
1627d0c221feSJean-Jacques Hiblot 	for (mwt = sd_modes_by_pref;\
1628d0c221feSJean-Jacques Hiblot 	     mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\
1629d0c221feSJean-Jacques Hiblot 	     mwt++) \
1630d0c221feSJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
1631d0c221feSJean-Jacques Hiblot 
163201298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
16338ac8a263SJean-Jacques Hiblot {
16348ac8a263SJean-Jacques Hiblot 	int err;
1635d0c221feSJean-Jacques Hiblot 	uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
1636d0c221feSJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
1637f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1638c10b85d6SJean-Jacques Hiblot 	bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false;
1639f99c2efeSJean-Jacques Hiblot #else
1640f99c2efeSJean-Jacques Hiblot 	bool uhs_en = false;
1641f99c2efeSJean-Jacques Hiblot #endif
1642c10b85d6SJean-Jacques Hiblot 	uint caps;
1643c10b85d6SJean-Jacques Hiblot 
164452d241dfSJean-Jacques Hiblot #ifdef DEBUG
164552d241dfSJean-Jacques Hiblot 	mmc_dump_capabilities("sd card", card_caps);
16461da8eb59SJean-Jacques Hiblot 	mmc_dump_capabilities("host", mmc->host_caps);
164752d241dfSJean-Jacques Hiblot #endif
16488ac8a263SJean-Jacques Hiblot 
16498ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
16501da8eb59SJean-Jacques Hiblot 	caps = card_caps & mmc->host_caps;
16518ac8a263SJean-Jacques Hiblot 
1652c10b85d6SJean-Jacques Hiblot 	if (!uhs_en)
1653c10b85d6SJean-Jacques Hiblot 		caps &= ~UHS_CAPS;
1654c10b85d6SJean-Jacques Hiblot 
1655c10b85d6SJean-Jacques Hiblot 	for_each_sd_mode_by_pref(caps, mwt) {
1656d0c221feSJean-Jacques Hiblot 		uint *w;
16578ac8a263SJean-Jacques Hiblot 
1658d0c221feSJean-Jacques Hiblot 		for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
1659c10b85d6SJean-Jacques Hiblot 			if (*w & caps & mwt->widths) {
1660d0c221feSJean-Jacques Hiblot 				debug("trying mode %s width %d (at %d MHz)\n",
1661d0c221feSJean-Jacques Hiblot 				      mmc_mode_name(mwt->mode),
1662d0c221feSJean-Jacques Hiblot 				      bus_width(*w),
1663d0c221feSJean-Jacques Hiblot 				      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1664d0c221feSJean-Jacques Hiblot 
1665d0c221feSJean-Jacques Hiblot 				/* configure the bus width (card + host) */
1666d0c221feSJean-Jacques Hiblot 				err = sd_select_bus_width(mmc, bus_width(*w));
16678ac8a263SJean-Jacques Hiblot 				if (err)
1668d0c221feSJean-Jacques Hiblot 					goto error;
1669d0c221feSJean-Jacques Hiblot 				mmc_set_bus_width(mmc, bus_width(*w));
16708ac8a263SJean-Jacques Hiblot 
1671d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (card) */
1672d0c221feSJean-Jacques Hiblot 				err = sd_set_card_speed(mmc, mwt->mode);
16738ac8a263SJean-Jacques Hiblot 				if (err)
1674d0c221feSJean-Jacques Hiblot 					goto error;
16758ac8a263SJean-Jacques Hiblot 
1676d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (host) */
1677d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, mwt->mode);
167835f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
16798ac8a263SJean-Jacques Hiblot 
1680f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1681c10b85d6SJean-Jacques Hiblot 				/* execute tuning if needed */
1682c10b85d6SJean-Jacques Hiblot 				if (mwt->tuning && !mmc_host_is_spi(mmc)) {
1683c10b85d6SJean-Jacques Hiblot 					err = mmc_execute_tuning(mmc,
1684c10b85d6SJean-Jacques Hiblot 								 mwt->tuning);
1685c10b85d6SJean-Jacques Hiblot 					if (err) {
1686c10b85d6SJean-Jacques Hiblot 						debug("tuning failed\n");
1687c10b85d6SJean-Jacques Hiblot 						goto error;
1688c10b85d6SJean-Jacques Hiblot 					}
1689c10b85d6SJean-Jacques Hiblot 				}
1690f99c2efeSJean-Jacques Hiblot #endif
1691c10b85d6SJean-Jacques Hiblot 
16928ac8a263SJean-Jacques Hiblot 				err = sd_read_ssr(mmc);
1693d0c221feSJean-Jacques Hiblot 				if (!err)
16948ac8a263SJean-Jacques Hiblot 					return 0;
1695d0c221feSJean-Jacques Hiblot 
1696d8e3d420SJean-Jacques Hiblot 				pr_warn("bad ssr\n");
1697d0c221feSJean-Jacques Hiblot 
1698d0c221feSJean-Jacques Hiblot error:
1699d0c221feSJean-Jacques Hiblot 				/* revert to a safer bus speed */
1700d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, SD_LEGACY);
170135f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
1702d0c221feSJean-Jacques Hiblot 			}
1703d0c221feSJean-Jacques Hiblot 		}
1704d0c221feSJean-Jacques Hiblot 	}
1705d0c221feSJean-Jacques Hiblot 
1706d0c221feSJean-Jacques Hiblot 	printf("unable to select a mode\n");
1707d0c221feSJean-Jacques Hiblot 	return -ENOTSUPP;
17088ac8a263SJean-Jacques Hiblot }
17098ac8a263SJean-Jacques Hiblot 
17107382e691SJean-Jacques Hiblot /*
17117382e691SJean-Jacques Hiblot  * read the compare the part of ext csd that is constant.
17127382e691SJean-Jacques Hiblot  * This can be used to check that the transfer is working
17137382e691SJean-Jacques Hiblot  * as expected.
17147382e691SJean-Jacques Hiblot  */
17157382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
17167382e691SJean-Jacques Hiblot {
17177382e691SJean-Jacques Hiblot 	int err;
17187382e691SJean-Jacques Hiblot 	const u8 *ext_csd = mmc->ext_csd;
17197382e691SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
17207382e691SJean-Jacques Hiblot 
17211de06b9fSJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
17221de06b9fSJean-Jacques Hiblot 		return 0;
17231de06b9fSJean-Jacques Hiblot 
17247382e691SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, test_csd);
17257382e691SJean-Jacques Hiblot 	if (err)
17267382e691SJean-Jacques Hiblot 		return err;
17277382e691SJean-Jacques Hiblot 
17287382e691SJean-Jacques Hiblot 	/* Only compare read only fields */
17297382e691SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
17307382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
17317382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
17327382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
17337382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_REV]
17347382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_REV] &&
17357382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
17367382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
17377382e691SJean-Jacques Hiblot 	    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
17387382e691SJean-Jacques Hiblot 		   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
17397382e691SJean-Jacques Hiblot 		return 0;
17407382e691SJean-Jacques Hiblot 
17417382e691SJean-Jacques Hiblot 	return -EBADMSG;
17427382e691SJean-Jacques Hiblot }
17437382e691SJean-Jacques Hiblot 
1744f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
1745bc1e3272SJean-Jacques Hiblot static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
1746bc1e3272SJean-Jacques Hiblot 				  uint32_t allowed_mask)
1747bc1e3272SJean-Jacques Hiblot {
1748bc1e3272SJean-Jacques Hiblot 	u32 card_mask = 0;
1749bc1e3272SJean-Jacques Hiblot 
1750bc1e3272SJean-Jacques Hiblot 	switch (mode) {
1751bc1e3272SJean-Jacques Hiblot 	case MMC_HS_200:
1752bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
1753bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_180;
1754bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V)
1755bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_120;
1756bc1e3272SJean-Jacques Hiblot 		break;
1757bc1e3272SJean-Jacques Hiblot 	case MMC_DDR_52:
1758bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
1759bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_330 |
1760bc1e3272SJean-Jacques Hiblot 				     MMC_SIGNAL_VOLTAGE_180;
1761bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V)
1762bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_120;
1763bc1e3272SJean-Jacques Hiblot 		break;
1764bc1e3272SJean-Jacques Hiblot 	default:
1765bc1e3272SJean-Jacques Hiblot 		card_mask |= MMC_SIGNAL_VOLTAGE_330;
1766bc1e3272SJean-Jacques Hiblot 		break;
1767bc1e3272SJean-Jacques Hiblot 	}
1768bc1e3272SJean-Jacques Hiblot 
1769bc1e3272SJean-Jacques Hiblot 	while (card_mask & allowed_mask) {
1770bc1e3272SJean-Jacques Hiblot 		enum mmc_voltage best_match;
1771bc1e3272SJean-Jacques Hiblot 
1772bc1e3272SJean-Jacques Hiblot 		best_match = 1 << (ffs(card_mask & allowed_mask) - 1);
1773bc1e3272SJean-Jacques Hiblot 		if (!mmc_set_signal_voltage(mmc,  best_match))
1774bc1e3272SJean-Jacques Hiblot 			return 0;
1775bc1e3272SJean-Jacques Hiblot 
1776bc1e3272SJean-Jacques Hiblot 		allowed_mask &= ~best_match;
1777bc1e3272SJean-Jacques Hiblot 	}
1778bc1e3272SJean-Jacques Hiblot 
1779bc1e3272SJean-Jacques Hiblot 	return -ENOTSUPP;
1780bc1e3272SJean-Jacques Hiblot }
1781f99c2efeSJean-Jacques Hiblot #else
1782f99c2efeSJean-Jacques Hiblot static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
1783f99c2efeSJean-Jacques Hiblot 					 uint32_t allowed_mask)
1784f99c2efeSJean-Jacques Hiblot {
1785f99c2efeSJean-Jacques Hiblot 	return 0;
1786f99c2efeSJean-Jacques Hiblot }
1787f99c2efeSJean-Jacques Hiblot #endif
1788bc1e3272SJean-Jacques Hiblot 
17893862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = {
1790f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
17918ac8a263SJean-Jacques Hiblot 	{
17923862b854SJean-Jacques Hiblot 		.mode = MMC_HS_200,
17933862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
1794634d4849SKishon Vijay Abraham I 		.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
17953862b854SJean-Jacques Hiblot 	},
1796f99c2efeSJean-Jacques Hiblot #endif
17973862b854SJean-Jacques Hiblot 	{
17983862b854SJean-Jacques Hiblot 		.mode = MMC_DDR_52,
17993862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
18003862b854SJean-Jacques Hiblot 	},
18013862b854SJean-Jacques Hiblot 	{
18023862b854SJean-Jacques Hiblot 		.mode = MMC_HS_52,
18033862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
18043862b854SJean-Jacques Hiblot 	},
18053862b854SJean-Jacques Hiblot 	{
18063862b854SJean-Jacques Hiblot 		.mode = MMC_HS,
18073862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
18083862b854SJean-Jacques Hiblot 	},
18093862b854SJean-Jacques Hiblot 	{
18103862b854SJean-Jacques Hiblot 		.mode = MMC_LEGACY,
18113862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
18123862b854SJean-Jacques Hiblot 	}
18138ac8a263SJean-Jacques Hiblot };
18148ac8a263SJean-Jacques Hiblot 
18153862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \
18163862b854SJean-Jacques Hiblot 	for (mwt = mmc_modes_by_pref;\
18173862b854SJean-Jacques Hiblot 	    mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\
18183862b854SJean-Jacques Hiblot 	    mwt++) \
18193862b854SJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
18203862b854SJean-Jacques Hiblot 
18213862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width {
18223862b854SJean-Jacques Hiblot 	uint cap;
18233862b854SJean-Jacques Hiblot 	bool is_ddr;
18243862b854SJean-Jacques Hiblot 	uint ext_csd_bits;
18253862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = {
18263862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8},
18273862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4},
18283862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8},
18293862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4},
18303862b854SJean-Jacques Hiblot 	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
18313862b854SJean-Jacques Hiblot };
18323862b854SJean-Jacques Hiblot 
18333862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \
18343862b854SJean-Jacques Hiblot 	for (ecbv = ext_csd_bus_width;\
18353862b854SJean-Jacques Hiblot 	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
18363862b854SJean-Jacques Hiblot 	    ecbv++) \
18373862b854SJean-Jacques Hiblot 		if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
18383862b854SJean-Jacques Hiblot 
183901298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
18403862b854SJean-Jacques Hiblot {
18413862b854SJean-Jacques Hiblot 	int err;
18423862b854SJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
18433862b854SJean-Jacques Hiblot 	const struct ext_csd_bus_width *ecbw;
18443862b854SJean-Jacques Hiblot 
184552d241dfSJean-Jacques Hiblot #ifdef DEBUG
184652d241dfSJean-Jacques Hiblot 	mmc_dump_capabilities("mmc", card_caps);
18471da8eb59SJean-Jacques Hiblot 	mmc_dump_capabilities("host", mmc->host_caps);
184852d241dfSJean-Jacques Hiblot #endif
184952d241dfSJean-Jacques Hiblot 
18508ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
18511da8eb59SJean-Jacques Hiblot 	card_caps &= mmc->host_caps;
18528ac8a263SJean-Jacques Hiblot 
18538ac8a263SJean-Jacques Hiblot 	/* Only version 4 of MMC supports wider bus widths */
18548ac8a263SJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
18558ac8a263SJean-Jacques Hiblot 		return 0;
18568ac8a263SJean-Jacques Hiblot 
1857dfda9d88SJean-Jacques Hiblot 	if (!mmc->ext_csd) {
1858dfda9d88SJean-Jacques Hiblot 		debug("No ext_csd found!\n"); /* this should enver happen */
1859dfda9d88SJean-Jacques Hiblot 		return -ENOTSUPP;
1860dfda9d88SJean-Jacques Hiblot 	}
1861dfda9d88SJean-Jacques Hiblot 
186201298da3SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->legacy_speed, false);
186301298da3SJean-Jacques Hiblot 
186401298da3SJean-Jacques Hiblot 	for_each_mmc_mode_by_pref(card_caps, mwt) {
186501298da3SJean-Jacques Hiblot 		for_each_supported_width(card_caps & mwt->widths,
18663862b854SJean-Jacques Hiblot 					 mmc_is_mode_ddr(mwt->mode), ecbw) {
1867bc1e3272SJean-Jacques Hiblot 			enum mmc_voltage old_voltage;
18683862b854SJean-Jacques Hiblot 			debug("trying mode %s width %d (at %d MHz)\n",
18693862b854SJean-Jacques Hiblot 			      mmc_mode_name(mwt->mode),
18703862b854SJean-Jacques Hiblot 			      bus_width(ecbw->cap),
18713862b854SJean-Jacques Hiblot 			      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1872bc1e3272SJean-Jacques Hiblot 			old_voltage = mmc->signal_voltage;
1873bc1e3272SJean-Jacques Hiblot 			err = mmc_set_lowest_voltage(mmc, mwt->mode,
1874bc1e3272SJean-Jacques Hiblot 						     MMC_ALL_SIGNAL_VOLTAGE);
1875bc1e3272SJean-Jacques Hiblot 			if (err)
1876bc1e3272SJean-Jacques Hiblot 				continue;
1877bc1e3272SJean-Jacques Hiblot 
18783862b854SJean-Jacques Hiblot 			/* configure the bus width (card + host) */
18793862b854SJean-Jacques Hiblot 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
18803862b854SJean-Jacques Hiblot 				    EXT_CSD_BUS_WIDTH,
18813862b854SJean-Jacques Hiblot 				    ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG);
18823862b854SJean-Jacques Hiblot 			if (err)
18833862b854SJean-Jacques Hiblot 				goto error;
18843862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
18853862b854SJean-Jacques Hiblot 
18863862b854SJean-Jacques Hiblot 			/* configure the bus speed (card) */
18873862b854SJean-Jacques Hiblot 			err = mmc_set_card_speed(mmc, mwt->mode);
18883862b854SJean-Jacques Hiblot 			if (err)
18893862b854SJean-Jacques Hiblot 				goto error;
18903862b854SJean-Jacques Hiblot 
18918ac8a263SJean-Jacques Hiblot 			/*
18923862b854SJean-Jacques Hiblot 			 * configure the bus width AND the ddr mode (card)
18933862b854SJean-Jacques Hiblot 			 * The host side will be taken care of in the next step
18948ac8a263SJean-Jacques Hiblot 			 */
18953862b854SJean-Jacques Hiblot 			if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
18963862b854SJean-Jacques Hiblot 				err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
18973862b854SJean-Jacques Hiblot 						 EXT_CSD_BUS_WIDTH,
18983862b854SJean-Jacques Hiblot 						 ecbw->ext_csd_bits);
18993862b854SJean-Jacques Hiblot 				if (err)
19003862b854SJean-Jacques Hiblot 					goto error;
19018ac8a263SJean-Jacques Hiblot 			}
19028ac8a263SJean-Jacques Hiblot 
19033862b854SJean-Jacques Hiblot 			/* configure the bus mode (host) */
19043862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, mwt->mode);
190535f67820SKishon Vijay Abraham I 			mmc_set_clock(mmc, mmc->tran_speed, false);
1906f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
19078ac8a263SJean-Jacques Hiblot 
1908634d4849SKishon Vijay Abraham I 			/* execute tuning if needed */
1909634d4849SKishon Vijay Abraham I 			if (mwt->tuning) {
1910634d4849SKishon Vijay Abraham I 				err = mmc_execute_tuning(mmc, mwt->tuning);
1911634d4849SKishon Vijay Abraham I 				if (err) {
1912634d4849SKishon Vijay Abraham I 					debug("tuning failed\n");
1913634d4849SKishon Vijay Abraham I 					goto error;
1914634d4849SKishon Vijay Abraham I 				}
1915634d4849SKishon Vijay Abraham I 			}
1916f99c2efeSJean-Jacques Hiblot #endif
1917634d4849SKishon Vijay Abraham I 
19183862b854SJean-Jacques Hiblot 			/* do a transfer to check the configuration */
19197382e691SJean-Jacques Hiblot 			err = mmc_read_and_compare_ext_csd(mmc);
19207382e691SJean-Jacques Hiblot 			if (!err)
19213862b854SJean-Jacques Hiblot 				return 0;
19223862b854SJean-Jacques Hiblot error:
1923bc1e3272SJean-Jacques Hiblot 			mmc_set_signal_voltage(mmc, old_voltage);
19243862b854SJean-Jacques Hiblot 			/* if an error occured, revert to a safer bus mode */
19253862b854SJean-Jacques Hiblot 			mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
19263862b854SJean-Jacques Hiblot 				   EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
19273862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_LEGACY);
19283862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, 1);
19293862b854SJean-Jacques Hiblot 		}
19308ac8a263SJean-Jacques Hiblot 	}
19318ac8a263SJean-Jacques Hiblot 
1932d8e3d420SJean-Jacques Hiblot 	pr_err("unable to select a mode\n");
19338ac8a263SJean-Jacques Hiblot 
19343862b854SJean-Jacques Hiblot 	return -ENOTSUPP;
19358ac8a263SJean-Jacques Hiblot }
19368ac8a263SJean-Jacques Hiblot 
1937dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
1938c744b6f6SJean-Jacques Hiblot {
1939c744b6f6SJean-Jacques Hiblot 	int err, i;
1940c744b6f6SJean-Jacques Hiblot 	u64 capacity;
1941c744b6f6SJean-Jacques Hiblot 	bool has_parts = false;
1942c744b6f6SJean-Jacques Hiblot 	bool part_completed;
1943f7d5dffcSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
1944c744b6f6SJean-Jacques Hiblot 
1945c744b6f6SJean-Jacques Hiblot 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
1946c744b6f6SJean-Jacques Hiblot 		return 0;
1947c744b6f6SJean-Jacques Hiblot 
1948c744b6f6SJean-Jacques Hiblot 	/* check  ext_csd version and capacity */
1949c744b6f6SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, ext_csd);
1950c744b6f6SJean-Jacques Hiblot 	if (err)
1951f7d5dffcSJean-Jacques Hiblot 		goto error;
1952f7d5dffcSJean-Jacques Hiblot 
1953f7d5dffcSJean-Jacques Hiblot 	/* store the ext csd for future reference */
1954f7d5dffcSJean-Jacques Hiblot 	if (!mmc->ext_csd)
1955f7d5dffcSJean-Jacques Hiblot 		mmc->ext_csd = malloc(MMC_MAX_BLOCK_LEN);
1956f7d5dffcSJean-Jacques Hiblot 	if (!mmc->ext_csd)
1957f7d5dffcSJean-Jacques Hiblot 		return -ENOMEM;
1958f7d5dffcSJean-Jacques Hiblot 	memcpy(mmc->ext_csd, ext_csd, MMC_MAX_BLOCK_LEN);
1959f7d5dffcSJean-Jacques Hiblot 
1960c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_REV] >= 2) {
1961c744b6f6SJean-Jacques Hiblot 		/*
1962c744b6f6SJean-Jacques Hiblot 		 * According to the JEDEC Standard, the value of
1963c744b6f6SJean-Jacques Hiblot 		 * ext_csd's capacity is valid if the value is more
1964c744b6f6SJean-Jacques Hiblot 		 * than 2GB
1965c744b6f6SJean-Jacques Hiblot 		 */
1966c744b6f6SJean-Jacques Hiblot 		capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
1967c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
1968c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
1969c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1970c744b6f6SJean-Jacques Hiblot 		capacity *= MMC_MAX_BLOCK_LEN;
1971c744b6f6SJean-Jacques Hiblot 		if ((capacity >> 20) > 2 * 1024)
1972c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1973c744b6f6SJean-Jacques Hiblot 	}
1974c744b6f6SJean-Jacques Hiblot 
1975c744b6f6SJean-Jacques Hiblot 	switch (ext_csd[EXT_CSD_REV]) {
1976c744b6f6SJean-Jacques Hiblot 	case 1:
1977c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_1;
1978c744b6f6SJean-Jacques Hiblot 		break;
1979c744b6f6SJean-Jacques Hiblot 	case 2:
1980c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_2;
1981c744b6f6SJean-Jacques Hiblot 		break;
1982c744b6f6SJean-Jacques Hiblot 	case 3:
1983c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_3;
1984c744b6f6SJean-Jacques Hiblot 		break;
1985c744b6f6SJean-Jacques Hiblot 	case 5:
1986c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_41;
1987c744b6f6SJean-Jacques Hiblot 		break;
1988c744b6f6SJean-Jacques Hiblot 	case 6:
1989c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_5;
1990c744b6f6SJean-Jacques Hiblot 		break;
1991c744b6f6SJean-Jacques Hiblot 	case 7:
1992c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_0;
1993c744b6f6SJean-Jacques Hiblot 		break;
1994c744b6f6SJean-Jacques Hiblot 	case 8:
1995c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_1;
1996c744b6f6SJean-Jacques Hiblot 		break;
1997c744b6f6SJean-Jacques Hiblot 	}
1998c744b6f6SJean-Jacques Hiblot 
1999c744b6f6SJean-Jacques Hiblot 	/* The partition data may be non-zero but it is only
2000c744b6f6SJean-Jacques Hiblot 	 * effective if PARTITION_SETTING_COMPLETED is set in
2001c744b6f6SJean-Jacques Hiblot 	 * EXT_CSD, so ignore any data if this bit is not set,
2002c744b6f6SJean-Jacques Hiblot 	 * except for enabling the high-capacity group size
2003c744b6f6SJean-Jacques Hiblot 	 * definition (see below).
2004c744b6f6SJean-Jacques Hiblot 	 */
2005c744b6f6SJean-Jacques Hiblot 	part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
2006c744b6f6SJean-Jacques Hiblot 			    EXT_CSD_PARTITION_SETTING_COMPLETED);
2007c744b6f6SJean-Jacques Hiblot 
2008c744b6f6SJean-Jacques Hiblot 	/* store the partition info of emmc */
2009c744b6f6SJean-Jacques Hiblot 	mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
2010c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
2011c744b6f6SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_BOOT_MULT])
2012c744b6f6SJean-Jacques Hiblot 		mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
2013c744b6f6SJean-Jacques Hiblot 	if (part_completed &&
2014c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
2015c744b6f6SJean-Jacques Hiblot 		mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
2016c744b6f6SJean-Jacques Hiblot 
2017c744b6f6SJean-Jacques Hiblot 	mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
2018c744b6f6SJean-Jacques Hiblot 
2019c744b6f6SJean-Jacques Hiblot 	mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
2020c744b6f6SJean-Jacques Hiblot 
2021c744b6f6SJean-Jacques Hiblot 	for (i = 0; i < 4; i++) {
2022c744b6f6SJean-Jacques Hiblot 		int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
2023c744b6f6SJean-Jacques Hiblot 		uint mult = (ext_csd[idx + 2] << 16) +
2024c744b6f6SJean-Jacques Hiblot 			(ext_csd[idx + 1] << 8) + ext_csd[idx];
2025c744b6f6SJean-Jacques Hiblot 		if (mult)
2026c744b6f6SJean-Jacques Hiblot 			has_parts = true;
2027c744b6f6SJean-Jacques Hiblot 		if (!part_completed)
2028c744b6f6SJean-Jacques Hiblot 			continue;
2029c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] = mult;
2030c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *=
2031c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
2032c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2033c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] <<= 19;
2034c744b6f6SJean-Jacques Hiblot 	}
2035c744b6f6SJean-Jacques Hiblot 
2036c744b6f6SJean-Jacques Hiblot 	if (part_completed) {
2037c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size =
2038c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
2039c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
2040c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_SIZE_MULT];
2041c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
2042c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2043c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size <<= 19;
2044c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_start =
2045c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
2046c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
2047c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
2048c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_START_ADDR];
2049c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity)
2050c744b6f6SJean-Jacques Hiblot 			mmc->enh_user_start <<= 9;
2051c744b6f6SJean-Jacques Hiblot 	}
2052c744b6f6SJean-Jacques Hiblot 
2053c744b6f6SJean-Jacques Hiblot 	/*
2054c744b6f6SJean-Jacques Hiblot 	 * Host needs to enable ERASE_GRP_DEF bit if device is
2055c744b6f6SJean-Jacques Hiblot 	 * partitioned. This bit will be lost every time after a reset
2056c744b6f6SJean-Jacques Hiblot 	 * or power off. This will affect erase size.
2057c744b6f6SJean-Jacques Hiblot 	 */
2058c744b6f6SJean-Jacques Hiblot 	if (part_completed)
2059c744b6f6SJean-Jacques Hiblot 		has_parts = true;
2060c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
2061c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
2062c744b6f6SJean-Jacques Hiblot 		has_parts = true;
2063c744b6f6SJean-Jacques Hiblot 	if (has_parts) {
2064c744b6f6SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
2065c744b6f6SJean-Jacques Hiblot 				 EXT_CSD_ERASE_GROUP_DEF, 1);
2066c744b6f6SJean-Jacques Hiblot 
2067c744b6f6SJean-Jacques Hiblot 		if (err)
2068f7d5dffcSJean-Jacques Hiblot 			goto error;
2069c744b6f6SJean-Jacques Hiblot 
2070c744b6f6SJean-Jacques Hiblot 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
2071c744b6f6SJean-Jacques Hiblot 	}
2072c744b6f6SJean-Jacques Hiblot 
2073c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
2074c744b6f6SJean-Jacques Hiblot 		/* Read out group size from ext_csd */
2075c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size =
2076c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
2077c744b6f6SJean-Jacques Hiblot 		/*
2078c744b6f6SJean-Jacques Hiblot 		 * if high capacity and partition setting completed
2079c744b6f6SJean-Jacques Hiblot 		 * SEC_COUNT is valid even if it is smaller than 2 GiB
2080c744b6f6SJean-Jacques Hiblot 		 * JEDEC Standard JESD84-B45, 6.2.4
2081c744b6f6SJean-Jacques Hiblot 		 */
2082c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity && part_completed) {
2083c744b6f6SJean-Jacques Hiblot 			capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
2084c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
2085c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
2086c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
2087c744b6f6SJean-Jacques Hiblot 			capacity *= MMC_MAX_BLOCK_LEN;
2088c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
2089c744b6f6SJean-Jacques Hiblot 		}
2090c744b6f6SJean-Jacques Hiblot 	} else {
2091c744b6f6SJean-Jacques Hiblot 		/* Calculate the group size from the csd value. */
2092c744b6f6SJean-Jacques Hiblot 		int erase_gsz, erase_gmul;
2093c744b6f6SJean-Jacques Hiblot 
2094c744b6f6SJean-Jacques Hiblot 		erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
2095c744b6f6SJean-Jacques Hiblot 		erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
2096c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size = (erase_gsz + 1)
2097c744b6f6SJean-Jacques Hiblot 			* (erase_gmul + 1);
2098c744b6f6SJean-Jacques Hiblot 	}
2099c744b6f6SJean-Jacques Hiblot 
2100c744b6f6SJean-Jacques Hiblot 	mmc->hc_wp_grp_size = 1024
2101c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
2102c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2103c744b6f6SJean-Jacques Hiblot 
2104c744b6f6SJean-Jacques Hiblot 	mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
2105c744b6f6SJean-Jacques Hiblot 
2106c744b6f6SJean-Jacques Hiblot 	return 0;
2107f7d5dffcSJean-Jacques Hiblot error:
2108f7d5dffcSJean-Jacques Hiblot 	if (mmc->ext_csd) {
2109f7d5dffcSJean-Jacques Hiblot 		free(mmc->ext_csd);
2110f7d5dffcSJean-Jacques Hiblot 		mmc->ext_csd = NULL;
2111f7d5dffcSJean-Jacques Hiblot 	}
2112f7d5dffcSJean-Jacques Hiblot 	return err;
2113c744b6f6SJean-Jacques Hiblot }
2114c744b6f6SJean-Jacques Hiblot 
2115fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
2116272cc70bSAndy Fleming {
2117f866a46dSStephen Warren 	int err, i;
2118272cc70bSAndy Fleming 	uint mult, freq;
2119c744b6f6SJean-Jacques Hiblot 	u64 cmult, csize;
2120272cc70bSAndy Fleming 	struct mmc_cmd cmd;
2121c40fdca6SSimon Glass 	struct blk_desc *bdesc;
2122272cc70bSAndy Fleming 
2123d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
2124d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
2125d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
2126d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
2127d52ebf10SThomas Chou 		cmd.cmdarg = 1;
2128d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
2129d52ebf10SThomas Chou 		if (err)
2130d52ebf10SThomas Chou 			return err;
2131d52ebf10SThomas Chou 	}
2132d52ebf10SThomas Chou #endif
2133d52ebf10SThomas Chou 
2134272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
2135d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
2136d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
2137272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
2138272cc70bSAndy Fleming 	cmd.cmdarg = 0;
2139272cc70bSAndy Fleming 
2140272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2141272cc70bSAndy Fleming 
214283dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
214383dc4227SKishon Vijay Abraham I 	if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) {
214483dc4227SKishon Vijay Abraham I 		int retries = 4;
214583dc4227SKishon Vijay Abraham I 		/*
214683dc4227SKishon Vijay Abraham I 		 * It has been seen that SEND_CID may fail on the first
214783dc4227SKishon Vijay Abraham I 		 * attempt, let's try a few more time
214883dc4227SKishon Vijay Abraham I 		 */
214983dc4227SKishon Vijay Abraham I 		do {
215083dc4227SKishon Vijay Abraham I 			err = mmc_send_cmd(mmc, &cmd, NULL);
215183dc4227SKishon Vijay Abraham I 			if (!err)
215283dc4227SKishon Vijay Abraham I 				break;
215383dc4227SKishon Vijay Abraham I 		} while (retries--);
215483dc4227SKishon Vijay Abraham I 	}
215583dc4227SKishon Vijay Abraham I #endif
215683dc4227SKishon Vijay Abraham I 
2157272cc70bSAndy Fleming 	if (err)
2158272cc70bSAndy Fleming 		return err;
2159272cc70bSAndy Fleming 
2160272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
2161272cc70bSAndy Fleming 
2162272cc70bSAndy Fleming 	/*
2163272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
2164272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
2165272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
2166272cc70bSAndy Fleming 	 */
2167d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2168272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
2169272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
2170272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
2171272cc70bSAndy Fleming 
2172272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
2173272cc70bSAndy Fleming 
2174272cc70bSAndy Fleming 		if (err)
2175272cc70bSAndy Fleming 			return err;
2176272cc70bSAndy Fleming 
2177272cc70bSAndy Fleming 		if (IS_SD(mmc))
2178998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
2179d52ebf10SThomas Chou 	}
2180272cc70bSAndy Fleming 
2181272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
2182272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
2183272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
2184272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
2185272cc70bSAndy Fleming 
2186272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2187272cc70bSAndy Fleming 
2188272cc70bSAndy Fleming 	if (err)
2189272cc70bSAndy Fleming 		return err;
2190272cc70bSAndy Fleming 
2191998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
2192998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
2193998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
2194998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
2195272cc70bSAndy Fleming 
2196272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
21970b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
2198272cc70bSAndy Fleming 
2199272cc70bSAndy Fleming 		switch (version) {
2200272cc70bSAndy Fleming 		case 0:
2201272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
2202272cc70bSAndy Fleming 			break;
2203272cc70bSAndy Fleming 		case 1:
2204272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
2205272cc70bSAndy Fleming 			break;
2206272cc70bSAndy Fleming 		case 2:
2207272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
2208272cc70bSAndy Fleming 			break;
2209272cc70bSAndy Fleming 		case 3:
2210272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
2211272cc70bSAndy Fleming 			break;
2212272cc70bSAndy Fleming 		case 4:
2213272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
2214272cc70bSAndy Fleming 			break;
2215272cc70bSAndy Fleming 		default:
2216272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
2217272cc70bSAndy Fleming 			break;
2218272cc70bSAndy Fleming 		}
2219272cc70bSAndy Fleming 	}
2220272cc70bSAndy Fleming 
2221272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
22220b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
22230b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
2224272cc70bSAndy Fleming 
222535f9e196SJean-Jacques Hiblot 	mmc->legacy_speed = freq * mult;
222635f9e196SJean-Jacques Hiblot 	mmc_select_mode(mmc, MMC_LEGACY);
2227272cc70bSAndy Fleming 
2228ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
2229998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
2230272cc70bSAndy Fleming 
2231272cc70bSAndy Fleming 	if (IS_SD(mmc))
2232272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
2233272cc70bSAndy Fleming 	else
2234998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
2235272cc70bSAndy Fleming 
2236272cc70bSAndy Fleming 	if (mmc->high_capacity) {
2237272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
2238272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
2239272cc70bSAndy Fleming 		cmult = 8;
2240272cc70bSAndy Fleming 	} else {
2241272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
2242272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
2243272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
2244272cc70bSAndy Fleming 	}
2245272cc70bSAndy Fleming 
2246f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
2247f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
2248f866a46dSStephen Warren 	mmc->capacity_boot = 0;
2249f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
2250f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
2251f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
2252272cc70bSAndy Fleming 
22538bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
22548bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
2255272cc70bSAndy Fleming 
22568bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
22578bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
2258272cc70bSAndy Fleming 
2259ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
2260ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
2261ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
2262ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
2263ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
2264d8e3d420SJean-Jacques Hiblot 			pr_warn("MMC: SET_DSR failed\n");
2265ab71188cSMarkus Niebel 	}
2266ab71188cSMarkus Niebel 
2267272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
2268d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2269272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
2270fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
2271272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
2272272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
2273272cc70bSAndy Fleming 
2274272cc70bSAndy Fleming 		if (err)
2275272cc70bSAndy Fleming 			return err;
2276d52ebf10SThomas Chou 	}
2277272cc70bSAndy Fleming 
2278e6f99a56SLei Wen 	/*
2279e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
2280e6f99a56SLei Wen 	 */
2281e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
2282bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
2283c744b6f6SJean-Jacques Hiblot 
2284dfda9d88SJean-Jacques Hiblot 	err = mmc_startup_v4(mmc);
22859cf199ebSDiego Santa Cruz 	if (err)
22869cf199ebSDiego Santa Cruz 		return err;
2287f866a46dSStephen Warren 
2288c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
2289f866a46dSStephen Warren 	if (err)
2290f866a46dSStephen Warren 		return err;
2291d23e2c09SSukumar Ghorai 
229201298da3SJean-Jacques Hiblot 	if (IS_SD(mmc)) {
229301298da3SJean-Jacques Hiblot 		err = sd_get_capabilities(mmc);
229401298da3SJean-Jacques Hiblot 		if (err)
229501298da3SJean-Jacques Hiblot 			return err;
229601298da3SJean-Jacques Hiblot 		err = sd_select_mode_and_width(mmc, mmc->card_caps);
229701298da3SJean-Jacques Hiblot 	} else {
229801298da3SJean-Jacques Hiblot 		err = mmc_get_capabilities(mmc);
229901298da3SJean-Jacques Hiblot 		if (err)
230001298da3SJean-Jacques Hiblot 			return err;
230101298da3SJean-Jacques Hiblot 		mmc_select_mode_and_width(mmc, mmc->card_caps);
230201298da3SJean-Jacques Hiblot 	}
2303272cc70bSAndy Fleming 
2304272cc70bSAndy Fleming 	if (err)
2305272cc70bSAndy Fleming 		return err;
2306272cc70bSAndy Fleming 
230701298da3SJean-Jacques Hiblot 	mmc->best_mode = mmc->selected_mode;
2308272cc70bSAndy Fleming 
23095af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
23105af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
23115af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
23125af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
23135af8f45cSAndrew Gabbasov 	}
23145af8f45cSAndrew Gabbasov 
2315272cc70bSAndy Fleming 	/* fill in device description */
2316c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
2317c40fdca6SSimon Glass 	bdesc->lun = 0;
2318c40fdca6SSimon Glass 	bdesc->hwpart = 0;
2319c40fdca6SSimon Glass 	bdesc->type = 0;
2320c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
2321c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
2322c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
2323fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
2324fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
2325fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
2326c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
2327babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
2328babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
2329c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
23300b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
2331babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
2332babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
2333c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
2334babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
233556196826SPaul Burton #else
2336c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
2337c40fdca6SSimon Glass 	bdesc->product[0] = 0;
2338c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
233956196826SPaul Burton #endif
2340122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
2341c40fdca6SSimon Glass 	part_init(bdesc);
2342122efd43SMikhail Kshevetskiy #endif
2343272cc70bSAndy Fleming 
2344272cc70bSAndy Fleming 	return 0;
2345272cc70bSAndy Fleming }
2346272cc70bSAndy Fleming 
2347fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
2348272cc70bSAndy Fleming {
2349272cc70bSAndy Fleming 	struct mmc_cmd cmd;
2350272cc70bSAndy Fleming 	int err;
2351272cc70bSAndy Fleming 
2352272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
2353272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
235493bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
2355272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
2356272cc70bSAndy Fleming 
2357272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2358272cc70bSAndy Fleming 
2359272cc70bSAndy Fleming 	if (err)
2360272cc70bSAndy Fleming 		return err;
2361272cc70bSAndy Fleming 
2362998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
2363915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
2364272cc70bSAndy Fleming 	else
2365272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
2366272cc70bSAndy Fleming 
2367272cc70bSAndy Fleming 	return 0;
2368272cc70bSAndy Fleming }
2369272cc70bSAndy Fleming 
2370c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
237195de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
237295de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
237395de9ab2SPaul Kocialkowski {
237495de9ab2SPaul Kocialkowski }
237505cbeb7cSSimon Glass #endif
237695de9ab2SPaul Kocialkowski 
23772051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
23782051aefeSPeng Fan {
2379c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
238006ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
23812051aefeSPeng Fan 	int ret;
23822051aefeSPeng Fan 
23832051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
238406ec045fSJean-Jacques Hiblot 					  &mmc->vmmc_supply);
238506ec045fSJean-Jacques Hiblot 	if (ret)
2386288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
23872051aefeSPeng Fan 
238806ec045fSJean-Jacques Hiblot 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
238906ec045fSJean-Jacques Hiblot 					  &mmc->vqmmc_supply);
239006ec045fSJean-Jacques Hiblot 	if (ret)
239106ec045fSJean-Jacques Hiblot 		debug("%s: No vqmmc supply\n", mmc->dev->name);
23922051aefeSPeng Fan #endif
239305cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
239405cbeb7cSSimon Glass 	/*
239505cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
239605cbeb7cSSimon Glass 	 * out to board code.
239705cbeb7cSSimon Glass 	 */
239805cbeb7cSSimon Glass 	board_mmc_power_init();
239905cbeb7cSSimon Glass #endif
24002051aefeSPeng Fan 	return 0;
24012051aefeSPeng Fan }
24022051aefeSPeng Fan 
2403fb7c3bebSKishon Vijay Abraham I /*
2404fb7c3bebSKishon Vijay Abraham I  * put the host in the initial state:
2405fb7c3bebSKishon Vijay Abraham I  * - turn on Vdd (card power supply)
2406fb7c3bebSKishon Vijay Abraham I  * - configure the bus width and clock to minimal values
2407fb7c3bebSKishon Vijay Abraham I  */
2408fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc)
2409fb7c3bebSKishon Vijay Abraham I {
2410fb7c3bebSKishon Vijay Abraham I 	int err;
2411fb7c3bebSKishon Vijay Abraham I 
2412fb7c3bebSKishon Vijay Abraham I 	/* First try to set 3.3V. If it fails set to 1.8V */
2413fb7c3bebSKishon Vijay Abraham I 	err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330);
2414fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2415fb7c3bebSKishon Vijay Abraham I 		err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
2416fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2417d8e3d420SJean-Jacques Hiblot 		pr_warn("mmc: failed to set signal voltage\n");
2418fb7c3bebSKishon Vijay Abraham I 
2419fb7c3bebSKishon Vijay Abraham I 	mmc_select_mode(mmc, MMC_LEGACY);
2420fb7c3bebSKishon Vijay Abraham I 	mmc_set_bus_width(mmc, 1);
242135f67820SKishon Vijay Abraham I 	mmc_set_clock(mmc, 0, false);
2422fb7c3bebSKishon Vijay Abraham I }
2423fb7c3bebSKishon Vijay Abraham I 
2424fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc)
2425fb7c3bebSKishon Vijay Abraham I {
2426fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2427fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2428fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, true);
2429fb7c3bebSKishon Vijay Abraham I 
2430fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2431fb7c3bebSKishon Vijay Abraham I 			puts("Error enabling VMMC supply\n");
2432fb7c3bebSKishon Vijay Abraham I 			return ret;
2433fb7c3bebSKishon Vijay Abraham I 		}
2434fb7c3bebSKishon Vijay Abraham I 	}
2435fb7c3bebSKishon Vijay Abraham I #endif
2436fb7c3bebSKishon Vijay Abraham I 	return 0;
2437fb7c3bebSKishon Vijay Abraham I }
2438fb7c3bebSKishon Vijay Abraham I 
2439fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc)
2440fb7c3bebSKishon Vijay Abraham I {
24412e7410d7SKishon Vijay Abraham I 	mmc_set_clock(mmc, 1, true);
2442fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2443fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2444fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, false);
2445fb7c3bebSKishon Vijay Abraham I 
2446fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2447c10b85d6SJean-Jacques Hiblot 			debug("Error disabling VMMC supply\n");
2448fb7c3bebSKishon Vijay Abraham I 			return ret;
2449fb7c3bebSKishon Vijay Abraham I 		}
2450fb7c3bebSKishon Vijay Abraham I 	}
2451fb7c3bebSKishon Vijay Abraham I #endif
2452fb7c3bebSKishon Vijay Abraham I 	return 0;
2453fb7c3bebSKishon Vijay Abraham I }
2454fb7c3bebSKishon Vijay Abraham I 
2455fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc)
2456fb7c3bebSKishon Vijay Abraham I {
2457fb7c3bebSKishon Vijay Abraham I 	int ret;
2458fb7c3bebSKishon Vijay Abraham I 
2459fb7c3bebSKishon Vijay Abraham I 	ret = mmc_power_off(mmc);
2460fb7c3bebSKishon Vijay Abraham I 	if (ret)
2461fb7c3bebSKishon Vijay Abraham I 		return ret;
2462fb7c3bebSKishon Vijay Abraham I 	/*
2463fb7c3bebSKishon Vijay Abraham I 	 * SD spec recommends at least 1ms of delay. Let's wait for 2ms
2464fb7c3bebSKishon Vijay Abraham I 	 * to be on the safer side.
2465fb7c3bebSKishon Vijay Abraham I 	 */
2466fb7c3bebSKishon Vijay Abraham I 	udelay(2000);
2467fb7c3bebSKishon Vijay Abraham I 	return mmc_power_on(mmc);
2468fb7c3bebSKishon Vijay Abraham I }
2469fb7c3bebSKishon Vijay Abraham I 
2470e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
2471272cc70bSAndy Fleming {
24728ca51e51SSimon Glass 	bool no_card;
2473c10b85d6SJean-Jacques Hiblot 	bool uhs_en = supports_uhs(mmc->cfg->host_caps);
2474afd5932bSMacpaul Lin 	int err;
2475272cc70bSAndy Fleming 
24761da8eb59SJean-Jacques Hiblot 	/*
24771da8eb59SJean-Jacques Hiblot 	 * all hosts are capable of 1 bit bus-width and able to use the legacy
24781da8eb59SJean-Jacques Hiblot 	 * timings.
24791da8eb59SJean-Jacques Hiblot 	 */
24801da8eb59SJean-Jacques Hiblot 	mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) |
24811da8eb59SJean-Jacques Hiblot 			 MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT;
248204a2ea24SJean-Jacques Hiblot 
2483ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
24848ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
2485e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
24868ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
24878ca51e51SSimon Glass #endif
24888ca51e51SSimon Glass 	if (no_card) {
248948972d90SThierry Reding 		mmc->has_init = 0;
249056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
249148972d90SThierry Reding 		printf("MMC: no card present\n");
249256196826SPaul Burton #endif
2493915ffa52SJaehoon Chung 		return -ENOMEDIUM;
249448972d90SThierry Reding 	}
249548972d90SThierry Reding 
2496bc897b1dSLei Wen 	if (mmc->has_init)
2497bc897b1dSLei Wen 		return 0;
2498bc897b1dSLei Wen 
24995a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
25005a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
25015a8dbdc6SYangbo Lu #endif
25022051aefeSPeng Fan 	err = mmc_power_init(mmc);
25032051aefeSPeng Fan 	if (err)
25042051aefeSPeng Fan 		return err;
250595de9ab2SPaul Kocialkowski 
250683dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
250783dc4227SKishon Vijay Abraham I 	mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN |
250883dc4227SKishon Vijay Abraham I 		      MMC_QUIRK_RETRY_SEND_CID;
250983dc4227SKishon Vijay Abraham I #endif
251083dc4227SKishon Vijay Abraham I 
251104a2ea24SJean-Jacques Hiblot 	err = mmc_power_cycle(mmc);
251204a2ea24SJean-Jacques Hiblot 	if (err) {
251304a2ea24SJean-Jacques Hiblot 		/*
251404a2ea24SJean-Jacques Hiblot 		 * if power cycling is not supported, we should not try
251504a2ea24SJean-Jacques Hiblot 		 * to use the UHS modes, because we wouldn't be able to
251604a2ea24SJean-Jacques Hiblot 		 * recover from an error during the UHS initialization.
251704a2ea24SJean-Jacques Hiblot 		 */
251804a2ea24SJean-Jacques Hiblot 		debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n");
251904a2ea24SJean-Jacques Hiblot 		uhs_en = false;
252004a2ea24SJean-Jacques Hiblot 		mmc->host_caps &= ~UHS_CAPS;
2521fb7c3bebSKishon Vijay Abraham I 		err = mmc_power_on(mmc);
252204a2ea24SJean-Jacques Hiblot 	}
2523fb7c3bebSKishon Vijay Abraham I 	if (err)
2524fb7c3bebSKishon Vijay Abraham I 		return err;
2525fb7c3bebSKishon Vijay Abraham I 
2526e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
25278ca51e51SSimon Glass 	/* The device has already been probed ready for use */
25288ca51e51SSimon Glass #else
2529ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
253093bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
2531272cc70bSAndy Fleming 	if (err)
2532272cc70bSAndy Fleming 		return err;
25338ca51e51SSimon Glass #endif
2534786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
2535aff5d3c8SKishon Vijay Abraham I 
2536c10b85d6SJean-Jacques Hiblot retry:
2537fb7c3bebSKishon Vijay Abraham I 	mmc_set_initial_state(mmc);
2538318a7a57SJean-Jacques Hiblot 	mmc_send_init_stream(mmc);
2539318a7a57SJean-Jacques Hiblot 
2540272cc70bSAndy Fleming 	/* Reset the Card */
2541272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
2542272cc70bSAndy Fleming 
2543272cc70bSAndy Fleming 	if (err)
2544272cc70bSAndy Fleming 		return err;
2545272cc70bSAndy Fleming 
2546bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
2547c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
2548bc897b1dSLei Wen 
2549272cc70bSAndy Fleming 	/* Test for SD version 2 */
2550272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
2551272cc70bSAndy Fleming 
2552272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
2553c10b85d6SJean-Jacques Hiblot 	err = sd_send_op_cond(mmc, uhs_en);
2554c10b85d6SJean-Jacques Hiblot 	if (err && uhs_en) {
2555c10b85d6SJean-Jacques Hiblot 		uhs_en = false;
2556c10b85d6SJean-Jacques Hiblot 		mmc_power_cycle(mmc);
2557c10b85d6SJean-Jacques Hiblot 		goto retry;
2558c10b85d6SJean-Jacques Hiblot 	}
2559272cc70bSAndy Fleming 
2560272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
2561915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
2562272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
2563272cc70bSAndy Fleming 
2564bd47c135SAndrew Gabbasov 		if (err) {
256556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2566d8e3d420SJean-Jacques Hiblot 			pr_err("Card did not respond to voltage select!\n");
256756196826SPaul Burton #endif
2568915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
2569272cc70bSAndy Fleming 		}
2570272cc70bSAndy Fleming 	}
2571272cc70bSAndy Fleming 
2572bd47c135SAndrew Gabbasov 	if (!err)
2573e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
2574e9550449SChe-Liang Chiou 
2575e9550449SChe-Liang Chiou 	return err;
2576e9550449SChe-Liang Chiou }
2577e9550449SChe-Liang Chiou 
2578e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2579e9550449SChe-Liang Chiou {
2580e9550449SChe-Liang Chiou 	int err = 0;
2581e9550449SChe-Liang Chiou 
2582bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
2583e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
2584e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
2585e9550449SChe-Liang Chiou 
2586e9550449SChe-Liang Chiou 	if (!err)
2587bc897b1dSLei Wen 		err = mmc_startup(mmc);
2588bc897b1dSLei Wen 	if (err)
2589bc897b1dSLei Wen 		mmc->has_init = 0;
2590bc897b1dSLei Wen 	else
2591bc897b1dSLei Wen 		mmc->has_init = 1;
2592e9550449SChe-Liang Chiou 	return err;
2593e9550449SChe-Liang Chiou }
2594e9550449SChe-Liang Chiou 
2595e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2596e9550449SChe-Liang Chiou {
2597bd47c135SAndrew Gabbasov 	int err = 0;
2598ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
2599c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
260033fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2601e9550449SChe-Liang Chiou 
260233fb211dSSimon Glass 	upriv->mmc = mmc;
260333fb211dSSimon Glass #endif
2604e9550449SChe-Liang Chiou 	if (mmc->has_init)
2605e9550449SChe-Liang Chiou 		return 0;
2606d803fea5SMateusz Zalega 
2607d803fea5SMateusz Zalega 	start = get_timer(0);
2608d803fea5SMateusz Zalega 
2609e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2610e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2611e9550449SChe-Liang Chiou 
2612bd47c135SAndrew Gabbasov 	if (!err)
2613e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2614919b4858SJagan Teki 	if (err)
2615919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
2616919b4858SJagan Teki 
2617bc897b1dSLei Wen 	return err;
2618272cc70bSAndy Fleming }
2619272cc70bSAndy Fleming 
2620ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2621ab71188cSMarkus Niebel {
2622ab71188cSMarkus Niebel 	mmc->dsr = val;
2623ab71188cSMarkus Niebel 	return 0;
2624ab71188cSMarkus Niebel }
2625ab71188cSMarkus Niebel 
2626cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2627cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2628272cc70bSAndy Fleming {
2629272cc70bSAndy Fleming 	return -1;
2630272cc70bSAndy Fleming }
2631272cc70bSAndy Fleming 
2632cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2633cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2634cee9ab7cSJeroen Hofstee {
2635cee9ab7cSJeroen Hofstee 	return -1;
2636cee9ab7cSJeroen Hofstee }
2637272cc70bSAndy Fleming 
2638e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2639e9550449SChe-Liang Chiou {
2640e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2641e9550449SChe-Liang Chiou }
2642e9550449SChe-Liang Chiou 
2643c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
26448e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
26458e3332e2SSjoerd Simons {
26468e3332e2SSjoerd Simons 	return 0;
26478e3332e2SSjoerd Simons }
2648c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
26498e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
26508e3332e2SSjoerd Simons {
26514a1db6d8SSimon Glass 	int ret, i;
26528e3332e2SSjoerd Simons 	struct uclass *uc;
26534a1db6d8SSimon Glass 	struct udevice *dev;
26548e3332e2SSjoerd Simons 
26558e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
26568e3332e2SSjoerd Simons 	if (ret)
26578e3332e2SSjoerd Simons 		return ret;
26588e3332e2SSjoerd Simons 
26594a1db6d8SSimon Glass 	/*
26604a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
26614a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
26624a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
26634a1db6d8SSimon Glass 	 */
26644a1db6d8SSimon Glass 	for (i = 0; ; i++) {
26654a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
26664a1db6d8SSimon Glass 		if (ret == -ENODEV)
26674a1db6d8SSimon Glass 			break;
26684a1db6d8SSimon Glass 	}
26694a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
26704a1db6d8SSimon Glass 		ret = device_probe(dev);
26718e3332e2SSjoerd Simons 		if (ret)
2672d8e3d420SJean-Jacques Hiblot 			pr_err("%s - probe failed: %d\n", dev->name, ret);
26738e3332e2SSjoerd Simons 	}
26748e3332e2SSjoerd Simons 
26758e3332e2SSjoerd Simons 	return 0;
26768e3332e2SSjoerd Simons }
26778e3332e2SSjoerd Simons #else
26788e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
26798e3332e2SSjoerd Simons {
26808e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
26818e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
26828e3332e2SSjoerd Simons 
26838e3332e2SSjoerd Simons 	return 0;
26848e3332e2SSjoerd Simons }
26858e3332e2SSjoerd Simons #endif
2686e9550449SChe-Liang Chiou 
2687272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2688272cc70bSAndy Fleming {
26891b26bab1SDaniel Kochmański 	static int initialized = 0;
26908e3332e2SSjoerd Simons 	int ret;
26911b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
26921b26bab1SDaniel Kochmański 		return 0;
26931b26bab1SDaniel Kochmański 	initialized = 1;
26941b26bab1SDaniel Kochmański 
2695c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2696b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2697c40fdca6SSimon Glass 	mmc_list_init();
2698c40fdca6SSimon Glass #endif
2699b5b838f1SMarek Vasut #endif
27008e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
27018e3332e2SSjoerd Simons 	if (ret)
27028e3332e2SSjoerd Simons 		return ret;
2703272cc70bSAndy Fleming 
2704bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2705272cc70bSAndy Fleming 	print_mmc_devices(',');
2706bb0dc108SYing Zhang #endif
2707272cc70bSAndy Fleming 
2708c40fdca6SSimon Glass 	mmc_do_preinit();
2709272cc70bSAndy Fleming 	return 0;
2710272cc70bSAndy Fleming }
2711cd3d4880STomas Melin 
2712cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2713cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2714cd3d4880STomas Melin {
2715cd3d4880STomas Melin 	int err;
2716cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2717cd3d4880STomas Melin 
2718cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2719cd3d4880STomas Melin 	if (err) {
2720cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2721cd3d4880STomas Melin 		return err;
2722cd3d4880STomas Melin 	}
2723cd3d4880STomas Melin 
2724cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2725cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2726cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2727cd3d4880STomas Melin 	}
2728cd3d4880STomas Melin 
2729cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2730cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2731cd3d4880STomas Melin 		return 0;
2732cd3d4880STomas Melin 	}
2733cd3d4880STomas Melin 
2734cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2735cd3d4880STomas Melin 	if (err) {
2736cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2737cd3d4880STomas Melin 		return err;
2738cd3d4880STomas Melin 	}
2739cd3d4880STomas Melin 
2740cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2741cd3d4880STomas Melin 
2742cd3d4880STomas Melin 	return 0;
2743cd3d4880STomas Melin }
2744cd3d4880STomas Melin #endif
2745