xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 00e446fa0453d435815b6f34b694d696a025f648)
1272cc70bSAndy Fleming /*
2272cc70bSAndy Fleming  * Copyright 2008, Freescale Semiconductor, Inc
3272cc70bSAndy Fleming  * Andy Fleming
4272cc70bSAndy Fleming  *
5272cc70bSAndy Fleming  * Based vaguely on the Linux code
6272cc70bSAndy Fleming  *
71a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
8272cc70bSAndy Fleming  */
9272cc70bSAndy Fleming 
10272cc70bSAndy Fleming #include <config.h>
11272cc70bSAndy Fleming #include <common.h>
12272cc70bSAndy Fleming #include <command.h>
138e3332e2SSjoerd Simons #include <dm.h>
148e3332e2SSjoerd Simons #include <dm/device-internal.h>
15d4622df3SStephen Warren #include <errno.h>
16272cc70bSAndy Fleming #include <mmc.h>
17272cc70bSAndy Fleming #include <part.h>
182051aefeSPeng Fan #include <power/regulator.h>
19272cc70bSAndy Fleming #include <malloc.h>
20cf92e05cSSimon Glass #include <memalign.h>
21272cc70bSAndy Fleming #include <linux/list.h>
229b1f942cSRabin Vincent #include <div64.h>
23da61fa5fSPaul Burton #include "mmc_private.h"
24272cc70bSAndy Fleming 
253697e599SPeng Fan static const unsigned int sd_au_size[] = {
263697e599SPeng Fan 	0,		SZ_16K / 512,		SZ_32K / 512,
273697e599SPeng Fan 	SZ_64K / 512,	SZ_128K / 512,		SZ_256K / 512,
283697e599SPeng Fan 	SZ_512K / 512,	SZ_1M / 512,		SZ_2M / 512,
293697e599SPeng Fan 	SZ_4M / 512,	SZ_8M / 512,		(SZ_8M + SZ_4M) / 512,
303697e599SPeng Fan 	SZ_16M / 512,	(SZ_16M + SZ_8M) / 512,	SZ_32M / 512,	SZ_64M / 512,
313697e599SPeng Fan };
323697e599SPeng Fan 
33aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage);
34fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc);
3501298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps);
36aff5d3c8SKishon Vijay Abraham I 
37b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
38b5b838f1SMarek Vasut static struct mmc mmc_static;
39b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num)
40b5b838f1SMarek Vasut {
41b5b838f1SMarek Vasut 	return &mmc_static;
42b5b838f1SMarek Vasut }
43b5b838f1SMarek Vasut 
44b5b838f1SMarek Vasut void mmc_do_preinit(void)
45b5b838f1SMarek Vasut {
46b5b838f1SMarek Vasut 	struct mmc *m = &mmc_static;
47b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
48b5b838f1SMarek Vasut 	mmc_set_preinit(m, 1);
49b5b838f1SMarek Vasut #endif
50b5b838f1SMarek Vasut 	if (m->preinit)
51b5b838f1SMarek Vasut 		mmc_start_init(m);
52b5b838f1SMarek Vasut }
53b5b838f1SMarek Vasut 
54b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
55b5b838f1SMarek Vasut {
56b5b838f1SMarek Vasut 	return &mmc->block_dev;
57b5b838f1SMarek Vasut }
58b5b838f1SMarek Vasut #endif
59b5b838f1SMarek Vasut 
60e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
61c10b85d6SJean-Jacques Hiblot 
62c10b85d6SJean-Jacques Hiblot static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout)
63c10b85d6SJean-Jacques Hiblot {
64c10b85d6SJean-Jacques Hiblot 	return -ENOSYS;
65c10b85d6SJean-Jacques Hiblot }
66c10b85d6SJean-Jacques Hiblot 
67750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
68d23d8d7eSNikita Kiryanov {
69d23d8d7eSNikita Kiryanov 	return -1;
70d23d8d7eSNikita Kiryanov }
71d23d8d7eSNikita Kiryanov 
72d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
73d23d8d7eSNikita Kiryanov {
74d23d8d7eSNikita Kiryanov 	int wp;
75d23d8d7eSNikita Kiryanov 
76d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
77d23d8d7eSNikita Kiryanov 
78d4e1da4eSPeter Korsgaard 	if (wp < 0) {
7993bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
8093bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
81d4e1da4eSPeter Korsgaard 		else
82d4e1da4eSPeter Korsgaard 			wp = 0;
83d4e1da4eSPeter Korsgaard 	}
84d23d8d7eSNikita Kiryanov 
85d23d8d7eSNikita Kiryanov 	return wp;
86d23d8d7eSNikita Kiryanov }
87d23d8d7eSNikita Kiryanov 
88cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc)
89cee9ab7cSJeroen Hofstee {
9011fdade2SStefano Babic 	return -1;
9111fdade2SStefano Babic }
928ca51e51SSimon Glass #endif
9311fdade2SStefano Babic 
948635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
95c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd)
96c0c76ebaSSimon Glass {
97c0c76ebaSSimon Glass 	printf("CMD_SEND:%d\n", cmd->cmdidx);
98c0c76ebaSSimon Glass 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
99c0c76ebaSSimon Glass }
100c0c76ebaSSimon Glass 
101c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
102c0c76ebaSSimon Glass {
1035db2fe3aSRaffaele Recalcati 	int i;
1045db2fe3aSRaffaele Recalcati 	u8 *ptr;
1055db2fe3aSRaffaele Recalcati 
1067863ce58SBin Meng 	if (ret) {
1077863ce58SBin Meng 		printf("\t\tRET\t\t\t %d\n", ret);
1087863ce58SBin Meng 	} else {
1095db2fe3aSRaffaele Recalcati 		switch (cmd->resp_type) {
1105db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
1115db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
1125db2fe3aSRaffaele Recalcati 			break;
1135db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
1145db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
1155db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1165db2fe3aSRaffaele Recalcati 			break;
1175db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
1185db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
1195db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1205db2fe3aSRaffaele Recalcati 			break;
1215db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
1225db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
1235db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1245db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1255db2fe3aSRaffaele Recalcati 				cmd->response[1]);
1265db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1275db2fe3aSRaffaele Recalcati 				cmd->response[2]);
1285db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1295db2fe3aSRaffaele Recalcati 				cmd->response[3]);
1305db2fe3aSRaffaele Recalcati 			printf("\n");
1315db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
1325db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
1335db2fe3aSRaffaele Recalcati 				int j;
1345db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
135146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
1365db2fe3aSRaffaele Recalcati 				ptr += 3;
1375db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
1385db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
1395db2fe3aSRaffaele Recalcati 				printf("\n");
1405db2fe3aSRaffaele Recalcati 			}
1415db2fe3aSRaffaele Recalcati 			break;
1425db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1435db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1445db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1455db2fe3aSRaffaele Recalcati 			break;
1465db2fe3aSRaffaele Recalcati 		default:
1475db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1485db2fe3aSRaffaele Recalcati 			break;
1495db2fe3aSRaffaele Recalcati 		}
1507863ce58SBin Meng 	}
151c0c76ebaSSimon Glass }
152c0c76ebaSSimon Glass 
153c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd)
154c0c76ebaSSimon Glass {
155c0c76ebaSSimon Glass 	int status;
156c0c76ebaSSimon Glass 
157c0c76ebaSSimon Glass 	status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9;
158c0c76ebaSSimon Glass 	printf("CURR STATE:%d\n", status);
159c0c76ebaSSimon Glass }
1605db2fe3aSRaffaele Recalcati #endif
161c0c76ebaSSimon Glass 
16235f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
16335f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode)
16435f9e196SJean-Jacques Hiblot {
16535f9e196SJean-Jacques Hiblot 	static const char *const names[] = {
16635f9e196SJean-Jacques Hiblot 	      [MMC_LEGACY]	= "MMC legacy",
16735f9e196SJean-Jacques Hiblot 	      [SD_LEGACY]	= "SD Legacy",
16835f9e196SJean-Jacques Hiblot 	      [MMC_HS]		= "MMC High Speed (26MHz)",
16935f9e196SJean-Jacques Hiblot 	      [SD_HS]		= "SD High Speed (50MHz)",
17035f9e196SJean-Jacques Hiblot 	      [UHS_SDR12]	= "UHS SDR12 (25MHz)",
17135f9e196SJean-Jacques Hiblot 	      [UHS_SDR25]	= "UHS SDR25 (50MHz)",
17235f9e196SJean-Jacques Hiblot 	      [UHS_SDR50]	= "UHS SDR50 (100MHz)",
17335f9e196SJean-Jacques Hiblot 	      [UHS_SDR104]	= "UHS SDR104 (208MHz)",
17435f9e196SJean-Jacques Hiblot 	      [UHS_DDR50]	= "UHS DDR50 (50MHz)",
17535f9e196SJean-Jacques Hiblot 	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
17635f9e196SJean-Jacques Hiblot 	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
17735f9e196SJean-Jacques Hiblot 	      [MMC_HS_200]	= "HS200 (200MHz)",
17835f9e196SJean-Jacques Hiblot 	};
17935f9e196SJean-Jacques Hiblot 
18035f9e196SJean-Jacques Hiblot 	if (mode >= MMC_MODES_END)
18135f9e196SJean-Jacques Hiblot 		return "Unknown mode";
18235f9e196SJean-Jacques Hiblot 	else
18335f9e196SJean-Jacques Hiblot 		return names[mode];
18435f9e196SJean-Jacques Hiblot }
18535f9e196SJean-Jacques Hiblot #endif
18635f9e196SJean-Jacques Hiblot 
18705038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
18805038576SJean-Jacques Hiblot {
18905038576SJean-Jacques Hiblot 	static const int freqs[] = {
19005038576SJean-Jacques Hiblot 	      [SD_LEGACY]	= 25000000,
19105038576SJean-Jacques Hiblot 	      [MMC_HS]		= 26000000,
19205038576SJean-Jacques Hiblot 	      [SD_HS]		= 50000000,
19305038576SJean-Jacques Hiblot 	      [UHS_SDR12]	= 25000000,
19405038576SJean-Jacques Hiblot 	      [UHS_SDR25]	= 50000000,
19505038576SJean-Jacques Hiblot 	      [UHS_SDR50]	= 100000000,
19605038576SJean-Jacques Hiblot 	      [UHS_SDR104]	= 208000000,
19705038576SJean-Jacques Hiblot 	      [UHS_DDR50]	= 50000000,
19805038576SJean-Jacques Hiblot 	      [MMC_HS_52]	= 52000000,
19905038576SJean-Jacques Hiblot 	      [MMC_DDR_52]	= 52000000,
20005038576SJean-Jacques Hiblot 	      [MMC_HS_200]	= 200000000,
20105038576SJean-Jacques Hiblot 	};
20205038576SJean-Jacques Hiblot 
20305038576SJean-Jacques Hiblot 	if (mode == MMC_LEGACY)
20405038576SJean-Jacques Hiblot 		return mmc->legacy_speed;
20505038576SJean-Jacques Hiblot 	else if (mode >= MMC_MODES_END)
20605038576SJean-Jacques Hiblot 		return 0;
20705038576SJean-Jacques Hiblot 	else
20805038576SJean-Jacques Hiblot 		return freqs[mode];
20905038576SJean-Jacques Hiblot }
21005038576SJean-Jacques Hiblot 
21135f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode)
21235f9e196SJean-Jacques Hiblot {
21335f9e196SJean-Jacques Hiblot 	mmc->selected_mode = mode;
21405038576SJean-Jacques Hiblot 	mmc->tran_speed = mmc_mode2freq(mmc, mode);
2153862b854SJean-Jacques Hiblot 	mmc->ddr_mode = mmc_is_mode_ddr(mode);
21635f9e196SJean-Jacques Hiblot 	debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
21735f9e196SJean-Jacques Hiblot 	      mmc->tran_speed / 1000000);
21835f9e196SJean-Jacques Hiblot 	return 0;
21935f9e196SJean-Jacques Hiblot }
22035f9e196SJean-Jacques Hiblot 
221e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
222c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
223c0c76ebaSSimon Glass {
224c0c76ebaSSimon Glass 	int ret;
225c0c76ebaSSimon Glass 
226c0c76ebaSSimon Glass 	mmmc_trace_before_send(mmc, cmd);
227c0c76ebaSSimon Glass 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
228c0c76ebaSSimon Glass 	mmmc_trace_after_send(mmc, cmd, ret);
229c0c76ebaSSimon Glass 
2308635ff9eSMarek Vasut 	return ret;
231272cc70bSAndy Fleming }
2328ca51e51SSimon Glass #endif
233272cc70bSAndy Fleming 
234da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
2355d4fc8d9SRaffaele Recalcati {
2365d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
237d617c426SJan Kloetzke 	int err, retries = 5;
2385d4fc8d9SRaffaele Recalcati 
2395d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
2405d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
241aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
242aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
2435d4fc8d9SRaffaele Recalcati 
2441677eef4SAndrew Gabbasov 	while (1) {
2455d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
246d617c426SJan Kloetzke 		if (!err) {
247d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
248d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
249d617c426SJan Kloetzke 			     MMC_STATE_PRG)
2505d4fc8d9SRaffaele Recalcati 				break;
251d0c221feSJean-Jacques Hiblot 
252d0c221feSJean-Jacques Hiblot 			if (cmd.response[0] & MMC_STATUS_MASK) {
25356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
254d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
255d617c426SJan Kloetzke 					cmd.response[0]);
25656196826SPaul Burton #endif
257915ffa52SJaehoon Chung 				return -ECOMM;
258d617c426SJan Kloetzke 			}
259d617c426SJan Kloetzke 		} else if (--retries < 0)
260d617c426SJan Kloetzke 			return err;
2615d4fc8d9SRaffaele Recalcati 
2621677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
2631677eef4SAndrew Gabbasov 			break;
2645d4fc8d9SRaffaele Recalcati 
2651677eef4SAndrew Gabbasov 		udelay(1000);
2661677eef4SAndrew Gabbasov 	}
2675d4fc8d9SRaffaele Recalcati 
268c0c76ebaSSimon Glass 	mmc_trace_state(mmc, &cmd);
2695b0c942fSJongman Heo 	if (timeout <= 0) {
27056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2715d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
27256196826SPaul Burton #endif
273915ffa52SJaehoon Chung 		return -ETIMEDOUT;
2745d4fc8d9SRaffaele Recalcati 	}
2755d4fc8d9SRaffaele Recalcati 
2765d4fc8d9SRaffaele Recalcati 	return 0;
2775d4fc8d9SRaffaele Recalcati }
2785d4fc8d9SRaffaele Recalcati 
279da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
280272cc70bSAndy Fleming {
281272cc70bSAndy Fleming 	struct mmc_cmd cmd;
28283dc4227SKishon Vijay Abraham I 	int err;
283272cc70bSAndy Fleming 
284786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
285d22e3d46SJaehoon Chung 		return 0;
286d22e3d46SJaehoon Chung 
287272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
288272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
289272cc70bSAndy Fleming 	cmd.cmdarg = len;
290272cc70bSAndy Fleming 
29183dc4227SKishon Vijay Abraham I 	err = mmc_send_cmd(mmc, &cmd, NULL);
29283dc4227SKishon Vijay Abraham I 
29383dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
29483dc4227SKishon Vijay Abraham I 	if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) {
29583dc4227SKishon Vijay Abraham I 		int retries = 4;
29683dc4227SKishon Vijay Abraham I 		/*
29783dc4227SKishon Vijay Abraham I 		 * It has been seen that SET_BLOCKLEN may fail on the first
29883dc4227SKishon Vijay Abraham I 		 * attempt, let's try a few more time
29983dc4227SKishon Vijay Abraham I 		 */
30083dc4227SKishon Vijay Abraham I 		do {
30183dc4227SKishon Vijay Abraham I 			err = mmc_send_cmd(mmc, &cmd, NULL);
30283dc4227SKishon Vijay Abraham I 			if (!err)
30383dc4227SKishon Vijay Abraham I 				break;
30483dc4227SKishon Vijay Abraham I 		} while (retries--);
30583dc4227SKishon Vijay Abraham I 	}
30683dc4227SKishon Vijay Abraham I #endif
30783dc4227SKishon Vijay Abraham I 
30883dc4227SKishon Vijay Abraham I 	return err;
309272cc70bSAndy Fleming }
310272cc70bSAndy Fleming 
3119815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_4bit[] = {
3129815e3baSJean-Jacques Hiblot 	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
3139815e3baSJean-Jacques Hiblot 	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
3149815e3baSJean-Jacques Hiblot 	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
3159815e3baSJean-Jacques Hiblot 	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
3169815e3baSJean-Jacques Hiblot 	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
3179815e3baSJean-Jacques Hiblot 	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
3189815e3baSJean-Jacques Hiblot 	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
3199815e3baSJean-Jacques Hiblot 	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
3209815e3baSJean-Jacques Hiblot };
3219815e3baSJean-Jacques Hiblot 
3229815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_8bit[] = {
3239815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
3249815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
3259815e3baSJean-Jacques Hiblot 	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
3269815e3baSJean-Jacques Hiblot 	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
3279815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
3289815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
3299815e3baSJean-Jacques Hiblot 	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
3309815e3baSJean-Jacques Hiblot 	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
3319815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
3329815e3baSJean-Jacques Hiblot 	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
3339815e3baSJean-Jacques Hiblot 	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
3349815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
3359815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
3369815e3baSJean-Jacques Hiblot 	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
3379815e3baSJean-Jacques Hiblot 	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
3389815e3baSJean-Jacques Hiblot 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
3399815e3baSJean-Jacques Hiblot };
3409815e3baSJean-Jacques Hiblot 
3419815e3baSJean-Jacques Hiblot int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error)
3429815e3baSJean-Jacques Hiblot {
3439815e3baSJean-Jacques Hiblot 	struct mmc_cmd cmd;
3449815e3baSJean-Jacques Hiblot 	struct mmc_data data;
3459815e3baSJean-Jacques Hiblot 	const u8 *tuning_block_pattern;
3469815e3baSJean-Jacques Hiblot 	int size, err;
3479815e3baSJean-Jacques Hiblot 
3489815e3baSJean-Jacques Hiblot 	if (mmc->bus_width == 8) {
3499815e3baSJean-Jacques Hiblot 		tuning_block_pattern = tuning_blk_pattern_8bit;
3509815e3baSJean-Jacques Hiblot 		size = sizeof(tuning_blk_pattern_8bit);
3519815e3baSJean-Jacques Hiblot 	} else if (mmc->bus_width == 4) {
3529815e3baSJean-Jacques Hiblot 		tuning_block_pattern = tuning_blk_pattern_4bit;
3539815e3baSJean-Jacques Hiblot 		size = sizeof(tuning_blk_pattern_4bit);
3549815e3baSJean-Jacques Hiblot 	} else {
3559815e3baSJean-Jacques Hiblot 		return -EINVAL;
3569815e3baSJean-Jacques Hiblot 	}
3579815e3baSJean-Jacques Hiblot 
3589815e3baSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, data_buf, size);
3599815e3baSJean-Jacques Hiblot 
3609815e3baSJean-Jacques Hiblot 	cmd.cmdidx = opcode;
3619815e3baSJean-Jacques Hiblot 	cmd.cmdarg = 0;
3629815e3baSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
3639815e3baSJean-Jacques Hiblot 
3649815e3baSJean-Jacques Hiblot 	data.dest = (void *)data_buf;
3659815e3baSJean-Jacques Hiblot 	data.blocks = 1;
3669815e3baSJean-Jacques Hiblot 	data.blocksize = size;
3679815e3baSJean-Jacques Hiblot 	data.flags = MMC_DATA_READ;
3689815e3baSJean-Jacques Hiblot 
3699815e3baSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, &data);
3709815e3baSJean-Jacques Hiblot 	if (err)
3719815e3baSJean-Jacques Hiblot 		return err;
3729815e3baSJean-Jacques Hiblot 
3739815e3baSJean-Jacques Hiblot 	if (memcmp(data_buf, tuning_block_pattern, size))
3749815e3baSJean-Jacques Hiblot 		return -EIO;
3759815e3baSJean-Jacques Hiblot 
3769815e3baSJean-Jacques Hiblot 	return 0;
3779815e3baSJean-Jacques Hiblot }
3789815e3baSJean-Jacques Hiblot 
379ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
380fdbb873eSKim Phillips 			   lbaint_t blkcnt)
381272cc70bSAndy Fleming {
382272cc70bSAndy Fleming 	struct mmc_cmd cmd;
383272cc70bSAndy Fleming 	struct mmc_data data;
384272cc70bSAndy Fleming 
3854a1a06bcSAlagu Sankar 	if (blkcnt > 1)
3864a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
3874a1a06bcSAlagu Sankar 	else
388272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
389272cc70bSAndy Fleming 
390272cc70bSAndy Fleming 	if (mmc->high_capacity)
3914a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
392272cc70bSAndy Fleming 	else
3934a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
394272cc70bSAndy Fleming 
395272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
396272cc70bSAndy Fleming 
397272cc70bSAndy Fleming 	data.dest = dst;
3984a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
399272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
400272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
401272cc70bSAndy Fleming 
4024a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
4034a1a06bcSAlagu Sankar 		return 0;
4044a1a06bcSAlagu Sankar 
4054a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
4064a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
4074a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
4084a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
4094a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
41056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
4114a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
41256196826SPaul Burton #endif
4134a1a06bcSAlagu Sankar 			return 0;
4144a1a06bcSAlagu Sankar 		}
415272cc70bSAndy Fleming 	}
416272cc70bSAndy Fleming 
4174a1a06bcSAlagu Sankar 	return blkcnt;
418272cc70bSAndy Fleming }
419272cc70bSAndy Fleming 
420c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
4217dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
42233fb211dSSimon Glass #else
4237dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
4247dba0b93SSimon Glass 		void *dst)
42533fb211dSSimon Glass #endif
426272cc70bSAndy Fleming {
427c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
42833fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
42933fb211dSSimon Glass #endif
430bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
431873cc1d7SStephen Warren 	int err;
4324a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
433272cc70bSAndy Fleming 
4344a1a06bcSAlagu Sankar 	if (blkcnt == 0)
4354a1a06bcSAlagu Sankar 		return 0;
4364a1a06bcSAlagu Sankar 
4374a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
438272cc70bSAndy Fleming 	if (!mmc)
439272cc70bSAndy Fleming 		return 0;
440272cc70bSAndy Fleming 
441b5b838f1SMarek Vasut 	if (CONFIG_IS_ENABLED(MMC_TINY))
442b5b838f1SMarek Vasut 		err = mmc_switch_part(mmc, block_dev->hwpart);
443b5b838f1SMarek Vasut 	else
44469f45cd5SSimon Glass 		err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
445b5b838f1SMarek Vasut 
446873cc1d7SStephen Warren 	if (err < 0)
447873cc1d7SStephen Warren 		return 0;
448873cc1d7SStephen Warren 
449c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
45056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
451ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
452c40fdca6SSimon Glass 			start + blkcnt, block_dev->lba);
45356196826SPaul Burton #endif
454d2bf29e3SLei Wen 		return 0;
455d2bf29e3SLei Wen 	}
456272cc70bSAndy Fleming 
45711692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
45811692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
459272cc70bSAndy Fleming 		return 0;
46011692991SSimon Glass 	}
461272cc70bSAndy Fleming 
4624a1a06bcSAlagu Sankar 	do {
46393bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
46493bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
46511692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
46611692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
4674a1a06bcSAlagu Sankar 			return 0;
46811692991SSimon Glass 		}
4694a1a06bcSAlagu Sankar 		blocks_todo -= cur;
4704a1a06bcSAlagu Sankar 		start += cur;
4714a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
4724a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
473272cc70bSAndy Fleming 
474272cc70bSAndy Fleming 	return blkcnt;
475272cc70bSAndy Fleming }
476272cc70bSAndy Fleming 
477fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
478272cc70bSAndy Fleming {
479272cc70bSAndy Fleming 	struct mmc_cmd cmd;
480272cc70bSAndy Fleming 	int err;
481272cc70bSAndy Fleming 
482272cc70bSAndy Fleming 	udelay(1000);
483272cc70bSAndy Fleming 
484272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
485272cc70bSAndy Fleming 	cmd.cmdarg = 0;
486272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
487272cc70bSAndy Fleming 
488272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
489272cc70bSAndy Fleming 
490272cc70bSAndy Fleming 	if (err)
491272cc70bSAndy Fleming 		return err;
492272cc70bSAndy Fleming 
493272cc70bSAndy Fleming 	udelay(2000);
494272cc70bSAndy Fleming 
495272cc70bSAndy Fleming 	return 0;
496272cc70bSAndy Fleming }
497272cc70bSAndy Fleming 
498c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage)
499c10b85d6SJean-Jacques Hiblot {
500c10b85d6SJean-Jacques Hiblot 	struct mmc_cmd cmd;
501c10b85d6SJean-Jacques Hiblot 	int err = 0;
502c10b85d6SJean-Jacques Hiblot 
503c10b85d6SJean-Jacques Hiblot 	/*
504c10b85d6SJean-Jacques Hiblot 	 * Send CMD11 only if the request is to switch the card to
505c10b85d6SJean-Jacques Hiblot 	 * 1.8V signalling.
506c10b85d6SJean-Jacques Hiblot 	 */
507c10b85d6SJean-Jacques Hiblot 	if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
508c10b85d6SJean-Jacques Hiblot 		return mmc_set_signal_voltage(mmc, signal_voltage);
509c10b85d6SJean-Jacques Hiblot 
510c10b85d6SJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_SWITCH_UHS18V;
511c10b85d6SJean-Jacques Hiblot 	cmd.cmdarg = 0;
512c10b85d6SJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
513c10b85d6SJean-Jacques Hiblot 
514c10b85d6SJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
515c10b85d6SJean-Jacques Hiblot 	if (err)
516c10b85d6SJean-Jacques Hiblot 		return err;
517c10b85d6SJean-Jacques Hiblot 
518c10b85d6SJean-Jacques Hiblot 	if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR))
519c10b85d6SJean-Jacques Hiblot 		return -EIO;
520c10b85d6SJean-Jacques Hiblot 
521c10b85d6SJean-Jacques Hiblot 	/*
522c10b85d6SJean-Jacques Hiblot 	 * The card should drive cmd and dat[0:3] low immediately
523c10b85d6SJean-Jacques Hiblot 	 * after the response of cmd11, but wait 100 us to be sure
524c10b85d6SJean-Jacques Hiblot 	 */
525c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 0, 100);
526c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
527c10b85d6SJean-Jacques Hiblot 		udelay(100);
528c10b85d6SJean-Jacques Hiblot 	else if (err)
529c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
530c10b85d6SJean-Jacques Hiblot 
531c10b85d6SJean-Jacques Hiblot 	/*
532c10b85d6SJean-Jacques Hiblot 	 * During a signal voltage level switch, the clock must be gated
533c10b85d6SJean-Jacques Hiblot 	 * for 5 ms according to the SD spec
534c10b85d6SJean-Jacques Hiblot 	 */
535c10b85d6SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->clock, true);
536c10b85d6SJean-Jacques Hiblot 
537c10b85d6SJean-Jacques Hiblot 	err = mmc_set_signal_voltage(mmc, signal_voltage);
538c10b85d6SJean-Jacques Hiblot 	if (err)
539c10b85d6SJean-Jacques Hiblot 		return err;
540c10b85d6SJean-Jacques Hiblot 
541c10b85d6SJean-Jacques Hiblot 	/* Keep clock gated for at least 10 ms, though spec only says 5 ms */
542c10b85d6SJean-Jacques Hiblot 	mdelay(10);
543c10b85d6SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->clock, false);
544c10b85d6SJean-Jacques Hiblot 
545c10b85d6SJean-Jacques Hiblot 	/*
546c10b85d6SJean-Jacques Hiblot 	 * Failure to switch is indicated by the card holding
547c10b85d6SJean-Jacques Hiblot 	 * dat[0:3] low. Wait for at least 1 ms according to spec
548c10b85d6SJean-Jacques Hiblot 	 */
549c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 1, 1000);
550c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
551c10b85d6SJean-Jacques Hiblot 		udelay(1000);
552c10b85d6SJean-Jacques Hiblot 	else if (err)
553c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
554c10b85d6SJean-Jacques Hiblot 
555c10b85d6SJean-Jacques Hiblot 	return 0;
556c10b85d6SJean-Jacques Hiblot }
557c10b85d6SJean-Jacques Hiblot 
558c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en)
559272cc70bSAndy Fleming {
560272cc70bSAndy Fleming 	int timeout = 1000;
561272cc70bSAndy Fleming 	int err;
562272cc70bSAndy Fleming 	struct mmc_cmd cmd;
563272cc70bSAndy Fleming 
5641677eef4SAndrew Gabbasov 	while (1) {
565272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
566272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
567272cc70bSAndy Fleming 		cmd.cmdarg = 0;
568272cc70bSAndy Fleming 
569272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
570272cc70bSAndy Fleming 
571272cc70bSAndy Fleming 		if (err)
572272cc70bSAndy Fleming 			return err;
573272cc70bSAndy Fleming 
574272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
575272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
576250de12bSStefano Babic 
577250de12bSStefano Babic 		/*
578250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
579250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
580250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
581250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
582250de12bSStefano Babic 		 * specified.
583250de12bSStefano Babic 		 */
584d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
58593bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
586272cc70bSAndy Fleming 
587272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
588272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
589272cc70bSAndy Fleming 
590c10b85d6SJean-Jacques Hiblot 		if (uhs_en)
591c10b85d6SJean-Jacques Hiblot 			cmd.cmdarg |= OCR_S18R;
592c10b85d6SJean-Jacques Hiblot 
593272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
594272cc70bSAndy Fleming 
595272cc70bSAndy Fleming 		if (err)
596272cc70bSAndy Fleming 			return err;
597272cc70bSAndy Fleming 
5981677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
5991677eef4SAndrew Gabbasov 			break;
600272cc70bSAndy Fleming 
6011677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
602915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
603272cc70bSAndy Fleming 
6041677eef4SAndrew Gabbasov 		udelay(1000);
6051677eef4SAndrew Gabbasov 	}
6061677eef4SAndrew Gabbasov 
607272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
608272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
609272cc70bSAndy Fleming 
610d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
611d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
612d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
613d52ebf10SThomas Chou 		cmd.cmdarg = 0;
614d52ebf10SThomas Chou 
615d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
616d52ebf10SThomas Chou 
617d52ebf10SThomas Chou 		if (err)
618d52ebf10SThomas Chou 			return err;
619d52ebf10SThomas Chou 	}
620d52ebf10SThomas Chou 
621998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
622272cc70bSAndy Fleming 
623c10b85d6SJean-Jacques Hiblot 	if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000)
624c10b85d6SJean-Jacques Hiblot 	    == 0x41000000) {
625c10b85d6SJean-Jacques Hiblot 		err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
626c10b85d6SJean-Jacques Hiblot 		if (err)
627c10b85d6SJean-Jacques Hiblot 			return err;
628c10b85d6SJean-Jacques Hiblot 	}
629c10b85d6SJean-Jacques Hiblot 
630272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
631272cc70bSAndy Fleming 	mmc->rca = 0;
632272cc70bSAndy Fleming 
633272cc70bSAndy Fleming 	return 0;
634272cc70bSAndy Fleming }
635272cc70bSAndy Fleming 
6365289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
637272cc70bSAndy Fleming {
6385289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
639272cc70bSAndy Fleming 	int err;
640272cc70bSAndy Fleming 
6415289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
6425289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
6435289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
6445a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
6455a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
64693bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
647a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
648a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
649e9550449SChe-Liang Chiou 
6505289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
651e9550449SChe-Liang Chiou 	if (err)
652e9550449SChe-Liang Chiou 		return err;
6535289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
654e9550449SChe-Liang Chiou 	return 0;
655e9550449SChe-Liang Chiou }
656e9550449SChe-Liang Chiou 
657750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
658e9550449SChe-Liang Chiou {
659e9550449SChe-Liang Chiou 	int err, i;
660e9550449SChe-Liang Chiou 
661272cc70bSAndy Fleming 	/* Some cards seem to need this */
662272cc70bSAndy Fleming 	mmc_go_idle(mmc);
663272cc70bSAndy Fleming 
66431cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
665e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
6665289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
66731cacbabSRaffaele Recalcati 		if (err)
66831cacbabSRaffaele Recalcati 			return err;
66931cacbabSRaffaele Recalcati 
670e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
671a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
672bd47c135SAndrew Gabbasov 			break;
673e9550449SChe-Liang Chiou 	}
674bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
675bd47c135SAndrew Gabbasov 	return 0;
676e9550449SChe-Liang Chiou }
67731cacbabSRaffaele Recalcati 
678750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
679e9550449SChe-Liang Chiou {
680e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
681e9550449SChe-Liang Chiou 	int timeout = 1000;
682e9550449SChe-Liang Chiou 	uint start;
683e9550449SChe-Liang Chiou 	int err;
684e9550449SChe-Liang Chiou 
685e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
686cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
687d188b113SYangbo Lu 		/* Some cards seem to need this */
688d188b113SYangbo Lu 		mmc_go_idle(mmc);
689d188b113SYangbo Lu 
690e9550449SChe-Liang Chiou 		start = get_timer(0);
6911677eef4SAndrew Gabbasov 		while (1) {
6925289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
693272cc70bSAndy Fleming 			if (err)
694272cc70bSAndy Fleming 				return err;
6951677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
6961677eef4SAndrew Gabbasov 				break;
697e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
698915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
699e9550449SChe-Liang Chiou 			udelay(100);
7001677eef4SAndrew Gabbasov 		}
701cc17c01fSAndrew Gabbasov 	}
702272cc70bSAndy Fleming 
703d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
704d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
705d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
706d52ebf10SThomas Chou 		cmd.cmdarg = 0;
707d52ebf10SThomas Chou 
708d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
709d52ebf10SThomas Chou 
710d52ebf10SThomas Chou 		if (err)
711d52ebf10SThomas Chou 			return err;
712a626c8d4SAndrew Gabbasov 
713a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
714d52ebf10SThomas Chou 	}
715d52ebf10SThomas Chou 
716272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
717272cc70bSAndy Fleming 
718272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
719def816a2SStephen Warren 	mmc->rca = 1;
720272cc70bSAndy Fleming 
721272cc70bSAndy Fleming 	return 0;
722272cc70bSAndy Fleming }
723272cc70bSAndy Fleming 
724272cc70bSAndy Fleming 
725fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
726272cc70bSAndy Fleming {
727272cc70bSAndy Fleming 	struct mmc_cmd cmd;
728272cc70bSAndy Fleming 	struct mmc_data data;
729272cc70bSAndy Fleming 	int err;
730272cc70bSAndy Fleming 
731272cc70bSAndy Fleming 	/* Get the Card Status Register */
732272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
733272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
734272cc70bSAndy Fleming 	cmd.cmdarg = 0;
735272cc70bSAndy Fleming 
736cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
737272cc70bSAndy Fleming 	data.blocks = 1;
7388bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
739272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
740272cc70bSAndy Fleming 
741272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
742272cc70bSAndy Fleming 
743272cc70bSAndy Fleming 	return err;
744272cc70bSAndy Fleming }
745272cc70bSAndy Fleming 
746c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
747272cc70bSAndy Fleming {
748272cc70bSAndy Fleming 	struct mmc_cmd cmd;
7495d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
750a9003dc6SMaxime Ripard 	int retries = 3;
7515d4fc8d9SRaffaele Recalcati 	int ret;
752272cc70bSAndy Fleming 
753272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
754272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
755272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
756272cc70bSAndy Fleming 				 (index << 16) |
757272cc70bSAndy Fleming 				 (value << 8);
758272cc70bSAndy Fleming 
759a9003dc6SMaxime Ripard 	while (retries > 0) {
7605d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
7615d4fc8d9SRaffaele Recalcati 
7625d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
763a9003dc6SMaxime Ripard 		if (!ret) {
76493ad0d18SJan Kloetzke 			ret = mmc_send_status(mmc, timeout);
765a9003dc6SMaxime Ripard 			return ret;
766a9003dc6SMaxime Ripard 		}
767a9003dc6SMaxime Ripard 
768a9003dc6SMaxime Ripard 		retries--;
769a9003dc6SMaxime Ripard 	}
7705d4fc8d9SRaffaele Recalcati 
7715d4fc8d9SRaffaele Recalcati 	return ret;
7725d4fc8d9SRaffaele Recalcati 
773272cc70bSAndy Fleming }
774272cc70bSAndy Fleming 
7753862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
776272cc70bSAndy Fleming {
777272cc70bSAndy Fleming 	int err;
7783862b854SJean-Jacques Hiblot 	int speed_bits;
7793862b854SJean-Jacques Hiblot 
7803862b854SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
7813862b854SJean-Jacques Hiblot 
7823862b854SJean-Jacques Hiblot 	switch (mode) {
7833862b854SJean-Jacques Hiblot 	case MMC_HS:
7843862b854SJean-Jacques Hiblot 	case MMC_HS_52:
7853862b854SJean-Jacques Hiblot 	case MMC_DDR_52:
7863862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_HS;
787634d4849SKishon Vijay Abraham I 		break;
788634d4849SKishon Vijay Abraham I 	case MMC_HS_200:
789634d4849SKishon Vijay Abraham I 		speed_bits = EXT_CSD_TIMING_HS200;
790634d4849SKishon Vijay Abraham I 		break;
7913862b854SJean-Jacques Hiblot 	case MMC_LEGACY:
7923862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_LEGACY;
7933862b854SJean-Jacques Hiblot 		break;
7943862b854SJean-Jacques Hiblot 	default:
7953862b854SJean-Jacques Hiblot 		return -EINVAL;
7963862b854SJean-Jacques Hiblot 	}
7973862b854SJean-Jacques Hiblot 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
7983862b854SJean-Jacques Hiblot 			 speed_bits);
7993862b854SJean-Jacques Hiblot 	if (err)
8003862b854SJean-Jacques Hiblot 		return err;
8013862b854SJean-Jacques Hiblot 
8023862b854SJean-Jacques Hiblot 	if ((mode == MMC_HS) || (mode == MMC_HS_52)) {
8033862b854SJean-Jacques Hiblot 		/* Now check to see that it worked */
8043862b854SJean-Jacques Hiblot 		err = mmc_send_ext_csd(mmc, test_csd);
8053862b854SJean-Jacques Hiblot 		if (err)
8063862b854SJean-Jacques Hiblot 			return err;
8073862b854SJean-Jacques Hiblot 
8083862b854SJean-Jacques Hiblot 		/* No high-speed support */
8093862b854SJean-Jacques Hiblot 		if (!test_csd[EXT_CSD_HS_TIMING])
8103862b854SJean-Jacques Hiblot 			return -ENOTSUPP;
8113862b854SJean-Jacques Hiblot 	}
8123862b854SJean-Jacques Hiblot 
8133862b854SJean-Jacques Hiblot 	return 0;
8143862b854SJean-Jacques Hiblot }
8153862b854SJean-Jacques Hiblot 
8163862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc)
8173862b854SJean-Jacques Hiblot {
8183862b854SJean-Jacques Hiblot 	u8 *ext_csd = mmc->ext_csd;
8193862b854SJean-Jacques Hiblot 	char cardtype;
820272cc70bSAndy Fleming 
821*00e446faSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY);
822272cc70bSAndy Fleming 
823d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
824d52ebf10SThomas Chou 		return 0;
825d52ebf10SThomas Chou 
826272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
827272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
828272cc70bSAndy Fleming 		return 0;
829272cc70bSAndy Fleming 
8303862b854SJean-Jacques Hiblot 	if (!ext_csd) {
8313862b854SJean-Jacques Hiblot 		printf("No ext_csd found!\n"); /* this should enver happen */
8323862b854SJean-Jacques Hiblot 		return -ENOTSUPP;
8333862b854SJean-Jacques Hiblot 	}
8343862b854SJean-Jacques Hiblot 
835fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
836fc5b32fbSAndrew Gabbasov 
837634d4849SKishon Vijay Abraham I 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
838bc1e3272SJean-Jacques Hiblot 	mmc->cardtype = cardtype;
839272cc70bSAndy Fleming 
840634d4849SKishon Vijay Abraham I 	if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
841634d4849SKishon Vijay Abraham I 			EXT_CSD_CARD_TYPE_HS200_1_8V)) {
842634d4849SKishon Vijay Abraham I 		mmc->card_caps |= MMC_MODE_HS200;
843634d4849SKishon Vijay Abraham I 	}
844d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
8453862b854SJean-Jacques Hiblot 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
846d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
8473862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS_52MHz;
848d22e3d46SJaehoon Chung 	}
8493862b854SJean-Jacques Hiblot 	if (cardtype & EXT_CSD_CARD_TYPE_26)
8503862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS;
851272cc70bSAndy Fleming 
852272cc70bSAndy Fleming 	return 0;
853272cc70bSAndy Fleming }
854272cc70bSAndy Fleming 
855f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
856f866a46dSStephen Warren {
857f866a46dSStephen Warren 	switch (part_num) {
858f866a46dSStephen Warren 	case 0:
859f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
860f866a46dSStephen Warren 		break;
861f866a46dSStephen Warren 	case 1:
862f866a46dSStephen Warren 	case 2:
863f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
864f866a46dSStephen Warren 		break;
865f866a46dSStephen Warren 	case 3:
866f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
867f866a46dSStephen Warren 		break;
868f866a46dSStephen Warren 	case 4:
869f866a46dSStephen Warren 	case 5:
870f866a46dSStephen Warren 	case 6:
871f866a46dSStephen Warren 	case 7:
872f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
873f866a46dSStephen Warren 		break;
874f866a46dSStephen Warren 	default:
875f866a46dSStephen Warren 		return -1;
876f866a46dSStephen Warren 	}
877f866a46dSStephen Warren 
878c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
879f866a46dSStephen Warren 
880f866a46dSStephen Warren 	return 0;
881f866a46dSStephen Warren }
882f866a46dSStephen Warren 
88301298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num)
88401298da3SJean-Jacques Hiblot {
88501298da3SJean-Jacques Hiblot 	int forbidden = 0;
88601298da3SJean-Jacques Hiblot 	bool change = false;
88701298da3SJean-Jacques Hiblot 
88801298da3SJean-Jacques Hiblot 	if (part_num & PART_ACCESS_MASK)
88901298da3SJean-Jacques Hiblot 		forbidden = MMC_CAP(MMC_HS_200);
89001298da3SJean-Jacques Hiblot 
89101298da3SJean-Jacques Hiblot 	if (MMC_CAP(mmc->selected_mode) & forbidden) {
89201298da3SJean-Jacques Hiblot 		debug("selected mode (%s) is forbidden for part %d\n",
89301298da3SJean-Jacques Hiblot 		      mmc_mode_name(mmc->selected_mode), part_num);
89401298da3SJean-Jacques Hiblot 		change = true;
89501298da3SJean-Jacques Hiblot 	} else if (mmc->selected_mode != mmc->best_mode) {
89601298da3SJean-Jacques Hiblot 		debug("selected mode is not optimal\n");
89701298da3SJean-Jacques Hiblot 		change = true;
89801298da3SJean-Jacques Hiblot 	}
89901298da3SJean-Jacques Hiblot 
90001298da3SJean-Jacques Hiblot 	if (change)
90101298da3SJean-Jacques Hiblot 		return mmc_select_mode_and_width(mmc,
90201298da3SJean-Jacques Hiblot 						 mmc->card_caps & ~forbidden);
90301298da3SJean-Jacques Hiblot 
90401298da3SJean-Jacques Hiblot 	return 0;
90501298da3SJean-Jacques Hiblot }
90601298da3SJean-Jacques Hiblot 
9077dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
908bc897b1dSLei Wen {
909f866a46dSStephen Warren 	int ret;
910bc897b1dSLei Wen 
91101298da3SJean-Jacques Hiblot 	ret = mmc_boot_part_access_chk(mmc, part_num);
91201298da3SJean-Jacques Hiblot 	if (ret)
91301298da3SJean-Jacques Hiblot 		return ret;
91401298da3SJean-Jacques Hiblot 
915f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
916bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
917bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
918f866a46dSStephen Warren 
9196dc93e70SPeter Bigot 	/*
9206dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
9216dc93e70SPeter Bigot 	 * to return to representing the raw device.
9226dc93e70SPeter Bigot 	 */
923873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
9246dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
925fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
926873cc1d7SStephen Warren 	}
9276dc93e70SPeter Bigot 
9286dc93e70SPeter Bigot 	return ret;
929bc897b1dSLei Wen }
930bc897b1dSLei Wen 
931ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
932ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
933ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
934ac9da0e0SDiego Santa Cruz {
935ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
936ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
937ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
938ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
939ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
940ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
9418dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
942ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
943ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
944ac9da0e0SDiego Santa Cruz 
945ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
946ac9da0e0SDiego Santa Cruz 		return -EINVAL;
947ac9da0e0SDiego Santa Cruz 
948ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
949ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
950ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
951ac9da0e0SDiego Santa Cruz 	}
952ac9da0e0SDiego Santa Cruz 
953ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
954ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
955ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
956ac9da0e0SDiego Santa Cruz 	}
957ac9da0e0SDiego Santa Cruz 
958ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
959ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
960ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
961ac9da0e0SDiego Santa Cruz 	}
962ac9da0e0SDiego Santa Cruz 
963ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
964ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
965ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
966ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
967ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
968ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
969ac9da0e0SDiego Santa Cruz 			return -EINVAL;
970ac9da0e0SDiego Santa Cruz 		}
971ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
972ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
973ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
974ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
975ac9da0e0SDiego Santa Cruz 		} else {
976ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
977ac9da0e0SDiego Santa Cruz 		}
978ac9da0e0SDiego Santa Cruz 	} else {
979ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
980ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
981ac9da0e0SDiego Santa Cruz 	}
982ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
983ac9da0e0SDiego Santa Cruz 
984ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
985ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
986ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
987ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
988ac9da0e0SDiego Santa Cruz 			return -EINVAL;
989ac9da0e0SDiego Santa Cruz 		}
990ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
991ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
992ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
993ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
994ac9da0e0SDiego Santa Cruz 		}
995ac9da0e0SDiego Santa Cruz 	}
996ac9da0e0SDiego Santa Cruz 
997ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
998ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
999ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1000ac9da0e0SDiego Santa Cruz 	}
1001ac9da0e0SDiego Santa Cruz 
1002ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
1003ac9da0e0SDiego Santa Cruz 	if (err)
1004ac9da0e0SDiego Santa Cruz 		return err;
1005ac9da0e0SDiego Santa Cruz 
1006ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
1007ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
1008ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
1009ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
1010ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
1011ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
1012ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
1013ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1014ac9da0e0SDiego Santa Cruz 	}
1015ac9da0e0SDiego Santa Cruz 
10168dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
10178dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
10188dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
10198dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
10208dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
10218dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
10228dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
10238dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
10248dda5b0eSDiego Santa Cruz 		else
10258dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
10268dda5b0eSDiego Santa Cruz 	}
10278dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
10288dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
10298dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
10308dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
10318dda5b0eSDiego Santa Cruz 			else
10328dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
10338dda5b0eSDiego Santa Cruz 		}
10348dda5b0eSDiego Santa Cruz 	}
10358dda5b0eSDiego Santa Cruz 
10368dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
10378dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
10388dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
10398dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
10408dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
10418dda5b0eSDiego Santa Cruz 	}
10428dda5b0eSDiego Santa Cruz 
1043ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
1044ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
1045ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
1046ac9da0e0SDiego Santa Cruz 		return -EPERM;
1047ac9da0e0SDiego Santa Cruz 	}
1048ac9da0e0SDiego Santa Cruz 
1049ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
1050ac9da0e0SDiego Santa Cruz 		return 0;
1051ac9da0e0SDiego Santa Cruz 
1052ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
1053ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
1054ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1055ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1056ac9da0e0SDiego Santa Cruz 
1057ac9da0e0SDiego Santa Cruz 		if (err)
1058ac9da0e0SDiego Santa Cruz 			return err;
1059ac9da0e0SDiego Santa Cruz 
1060ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1061ac9da0e0SDiego Santa Cruz 
1062ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
1063ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
1064ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1065ac9da0e0SDiego Santa Cruz 
1066ac9da0e0SDiego Santa Cruz 	}
1067ac9da0e0SDiego Santa Cruz 
1068ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
1069ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
1070ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1071ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
1072ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
1073ac9da0e0SDiego Santa Cruz 		if (err)
1074ac9da0e0SDiego Santa Cruz 			return err;
1075ac9da0e0SDiego Santa Cruz 	}
1076ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
1077ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1078ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
1079ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
1080ac9da0e0SDiego Santa Cruz 		if (err)
1081ac9da0e0SDiego Santa Cruz 			return err;
1082ac9da0e0SDiego Santa Cruz 	}
1083ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1084ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
1085ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1086ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
1087ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
1088ac9da0e0SDiego Santa Cruz 			if (err)
1089ac9da0e0SDiego Santa Cruz 				return err;
1090ac9da0e0SDiego Santa Cruz 		}
1091ac9da0e0SDiego Santa Cruz 	}
1092ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1093ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
1094ac9da0e0SDiego Santa Cruz 	if (err)
1095ac9da0e0SDiego Santa Cruz 		return err;
1096ac9da0e0SDiego Santa Cruz 
1097ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
1098ac9da0e0SDiego Santa Cruz 		return 0;
1099ac9da0e0SDiego Santa Cruz 
11008dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
11018dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
11028dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
11038dda5b0eSDiego Santa Cruz 	 * partitioning. */
11048dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
11058dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
11068dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
11078dda5b0eSDiego Santa Cruz 		if (err)
11088dda5b0eSDiego Santa Cruz 			return err;
11098dda5b0eSDiego Santa Cruz 	}
11108dda5b0eSDiego Santa Cruz 
1111ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
1112ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
1113ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
1114ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
1115ac9da0e0SDiego Santa Cruz 
1116ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1117ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
1118ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
1119ac9da0e0SDiego Santa Cruz 	if (err)
1120ac9da0e0SDiego Santa Cruz 		return err;
1121ac9da0e0SDiego Santa Cruz 
1122ac9da0e0SDiego Santa Cruz 	return 0;
1123ac9da0e0SDiego Santa Cruz }
1124ac9da0e0SDiego Santa Cruz 
1125e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
112648972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
112748972d90SThierry Reding {
112848972d90SThierry Reding 	int cd;
112948972d90SThierry Reding 
113048972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
113148972d90SThierry Reding 
1132d4e1da4eSPeter Korsgaard 	if (cd < 0) {
113393bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
113493bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
1135d4e1da4eSPeter Korsgaard 		else
1136d4e1da4eSPeter Korsgaard 			cd = 1;
1137d4e1da4eSPeter Korsgaard 	}
113848972d90SThierry Reding 
113948972d90SThierry Reding 	return cd;
114048972d90SThierry Reding }
11418ca51e51SSimon Glass #endif
114248972d90SThierry Reding 
1143fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
1144272cc70bSAndy Fleming {
1145272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1146272cc70bSAndy Fleming 	struct mmc_data data;
1147272cc70bSAndy Fleming 
1148272cc70bSAndy Fleming 	/* Switch the frequency */
1149272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
1150272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1151272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
1152272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
1153272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
1154272cc70bSAndy Fleming 
1155272cc70bSAndy Fleming 	data.dest = (char *)resp;
1156272cc70bSAndy Fleming 	data.blocksize = 64;
1157272cc70bSAndy Fleming 	data.blocks = 1;
1158272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1159272cc70bSAndy Fleming 
1160272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
1161272cc70bSAndy Fleming }
1162272cc70bSAndy Fleming 
1163272cc70bSAndy Fleming 
1164d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc)
1165272cc70bSAndy Fleming {
1166272cc70bSAndy Fleming 	int err;
1167272cc70bSAndy Fleming 	struct mmc_cmd cmd;
116818e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
116918e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
1170272cc70bSAndy Fleming 	struct mmc_data data;
1171272cc70bSAndy Fleming 	int timeout;
1172c10b85d6SJean-Jacques Hiblot 	u32 sd3_bus_mode;
1173272cc70bSAndy Fleming 
1174*00e446faSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY);
1175272cc70bSAndy Fleming 
1176d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
1177d52ebf10SThomas Chou 		return 0;
1178d52ebf10SThomas Chou 
1179272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
1180272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
1181272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1182272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1183272cc70bSAndy Fleming 
1184272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1185272cc70bSAndy Fleming 
1186272cc70bSAndy Fleming 	if (err)
1187272cc70bSAndy Fleming 		return err;
1188272cc70bSAndy Fleming 
1189272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
1190272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1191272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1192272cc70bSAndy Fleming 
1193272cc70bSAndy Fleming 	timeout = 3;
1194272cc70bSAndy Fleming 
1195272cc70bSAndy Fleming retry_scr:
1196f781dd38SAnton staaf 	data.dest = (char *)scr;
1197272cc70bSAndy Fleming 	data.blocksize = 8;
1198272cc70bSAndy Fleming 	data.blocks = 1;
1199272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1200272cc70bSAndy Fleming 
1201272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
1202272cc70bSAndy Fleming 
1203272cc70bSAndy Fleming 	if (err) {
1204272cc70bSAndy Fleming 		if (timeout--)
1205272cc70bSAndy Fleming 			goto retry_scr;
1206272cc70bSAndy Fleming 
1207272cc70bSAndy Fleming 		return err;
1208272cc70bSAndy Fleming 	}
1209272cc70bSAndy Fleming 
12104e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
12114e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
1212272cc70bSAndy Fleming 
1213272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
1214272cc70bSAndy Fleming 	case 0:
1215272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1216272cc70bSAndy Fleming 		break;
1217272cc70bSAndy Fleming 	case 1:
1218272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
1219272cc70bSAndy Fleming 		break;
1220272cc70bSAndy Fleming 	case 2:
1221272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
12221741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
12231741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
1224272cc70bSAndy Fleming 		break;
1225272cc70bSAndy Fleming 	default:
1226272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1227272cc70bSAndy Fleming 		break;
1228272cc70bSAndy Fleming 	}
1229272cc70bSAndy Fleming 
1230b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1231b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1232b44c7083SAlagu Sankar 
1233272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1234272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1235272cc70bSAndy Fleming 		return 0;
1236272cc70bSAndy Fleming 
1237272cc70bSAndy Fleming 	timeout = 4;
1238272cc70bSAndy Fleming 	while (timeout--) {
1239272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1240f781dd38SAnton staaf 				(u8 *)switch_status);
1241272cc70bSAndy Fleming 
1242272cc70bSAndy Fleming 		if (err)
1243272cc70bSAndy Fleming 			return err;
1244272cc70bSAndy Fleming 
1245272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
12464e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1247272cc70bSAndy Fleming 			break;
1248272cc70bSAndy Fleming 	}
1249272cc70bSAndy Fleming 
1250272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
1251d0c221feSJean-Jacques Hiblot 	if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
1252d0c221feSJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(SD_HS);
1253272cc70bSAndy Fleming 
1254c10b85d6SJean-Jacques Hiblot 	/* Version before 3.0 don't support UHS modes */
1255c10b85d6SJean-Jacques Hiblot 	if (mmc->version < SD_VERSION_3)
1256c10b85d6SJean-Jacques Hiblot 		return 0;
1257c10b85d6SJean-Jacques Hiblot 
1258c10b85d6SJean-Jacques Hiblot 	sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f;
1259c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR104)
1260c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR104);
1261c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR50)
1262c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR50);
1263c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR25)
1264c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR25);
1265c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR12)
1266c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR12);
1267c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_DDR50)
1268c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_DDR50);
1269c10b85d6SJean-Jacques Hiblot 
12702c3fbf4cSMacpaul Lin 	return 0;
1271d0c221feSJean-Jacques Hiblot }
1272d0c221feSJean-Jacques Hiblot 
1273d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
1274d0c221feSJean-Jacques Hiblot {
1275d0c221feSJean-Jacques Hiblot 	int err;
1276d0c221feSJean-Jacques Hiblot 
1277d0c221feSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
1278c10b85d6SJean-Jacques Hiblot 	int speed;
12792c3fbf4cSMacpaul Lin 
1280c10b85d6SJean-Jacques Hiblot 	switch (mode) {
1281c10b85d6SJean-Jacques Hiblot 	case SD_LEGACY:
1282c10b85d6SJean-Jacques Hiblot 	case UHS_SDR12:
1283c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR12_BUS_SPEED;
1284c10b85d6SJean-Jacques Hiblot 		break;
1285c10b85d6SJean-Jacques Hiblot 	case SD_HS:
1286c10b85d6SJean-Jacques Hiblot 	case UHS_SDR25:
1287c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR25_BUS_SPEED;
1288c10b85d6SJean-Jacques Hiblot 		break;
1289c10b85d6SJean-Jacques Hiblot 	case UHS_SDR50:
1290c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR50_BUS_SPEED;
1291c10b85d6SJean-Jacques Hiblot 		break;
1292c10b85d6SJean-Jacques Hiblot 	case UHS_DDR50:
1293c10b85d6SJean-Jacques Hiblot 		speed = UHS_DDR50_BUS_SPEED;
1294c10b85d6SJean-Jacques Hiblot 		break;
1295c10b85d6SJean-Jacques Hiblot 	case UHS_SDR104:
1296c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR104_BUS_SPEED;
1297c10b85d6SJean-Jacques Hiblot 		break;
1298c10b85d6SJean-Jacques Hiblot 	default:
1299c10b85d6SJean-Jacques Hiblot 		return -EINVAL;
1300c10b85d6SJean-Jacques Hiblot 	}
1301c10b85d6SJean-Jacques Hiblot 
1302c10b85d6SJean-Jacques Hiblot 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status);
1303272cc70bSAndy Fleming 	if (err)
1304272cc70bSAndy Fleming 		return err;
1305272cc70bSAndy Fleming 
1306c10b85d6SJean-Jacques Hiblot 	if ((__be32_to_cpu(switch_status[4]) >> 24) != speed)
1307d0c221feSJean-Jacques Hiblot 		return -ENOTSUPP;
1308d0c221feSJean-Jacques Hiblot 
1309d0c221feSJean-Jacques Hiblot 	return 0;
1310d0c221feSJean-Jacques Hiblot }
1311d0c221feSJean-Jacques Hiblot 
1312d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w)
1313d0c221feSJean-Jacques Hiblot {
1314d0c221feSJean-Jacques Hiblot 	int err;
1315d0c221feSJean-Jacques Hiblot 	struct mmc_cmd cmd;
1316d0c221feSJean-Jacques Hiblot 
1317d0c221feSJean-Jacques Hiblot 	if ((w != 4) && (w != 1))
1318d0c221feSJean-Jacques Hiblot 		return -EINVAL;
1319d0c221feSJean-Jacques Hiblot 
1320d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = MMC_CMD_APP_CMD;
1321d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1322d0c221feSJean-Jacques Hiblot 	cmd.cmdarg = mmc->rca << 16;
1323d0c221feSJean-Jacques Hiblot 
1324d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1325d0c221feSJean-Jacques Hiblot 	if (err)
1326d0c221feSJean-Jacques Hiblot 		return err;
1327d0c221feSJean-Jacques Hiblot 
1328d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1329d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1330d0c221feSJean-Jacques Hiblot 	if (w == 4)
1331d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 2;
1332d0c221feSJean-Jacques Hiblot 	else if (w == 1)
1333d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 0;
1334d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1335d0c221feSJean-Jacques Hiblot 	if (err)
1336d0c221feSJean-Jacques Hiblot 		return err;
1337272cc70bSAndy Fleming 
1338272cc70bSAndy Fleming 	return 0;
1339272cc70bSAndy Fleming }
1340272cc70bSAndy Fleming 
13413697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
13423697e599SPeng Fan {
13433697e599SPeng Fan 	int err, i;
13443697e599SPeng Fan 	struct mmc_cmd cmd;
13453697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
13463697e599SPeng Fan 	struct mmc_data data;
13473697e599SPeng Fan 	int timeout = 3;
13483697e599SPeng Fan 	unsigned int au, eo, et, es;
13493697e599SPeng Fan 
13503697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
13513697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
13523697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
13533697e599SPeng Fan 
13543697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
13553697e599SPeng Fan 	if (err)
13563697e599SPeng Fan 		return err;
13573697e599SPeng Fan 
13583697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
13593697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
13603697e599SPeng Fan 	cmd.cmdarg = 0;
13613697e599SPeng Fan 
13623697e599SPeng Fan retry_ssr:
13633697e599SPeng Fan 	data.dest = (char *)ssr;
13643697e599SPeng Fan 	data.blocksize = 64;
13653697e599SPeng Fan 	data.blocks = 1;
13663697e599SPeng Fan 	data.flags = MMC_DATA_READ;
13673697e599SPeng Fan 
13683697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
13693697e599SPeng Fan 	if (err) {
13703697e599SPeng Fan 		if (timeout--)
13713697e599SPeng Fan 			goto retry_ssr;
13723697e599SPeng Fan 
13733697e599SPeng Fan 		return err;
13743697e599SPeng Fan 	}
13753697e599SPeng Fan 
13763697e599SPeng Fan 	for (i = 0; i < 16; i++)
13773697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
13783697e599SPeng Fan 
13793697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
13803697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
13813697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
13823697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
13833697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
13843697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
13853697e599SPeng Fan 		if (es && et) {
13863697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
13873697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
13883697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
13893697e599SPeng Fan 		}
13903697e599SPeng Fan 	} else {
13913697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
13923697e599SPeng Fan 	}
13933697e599SPeng Fan 
13943697e599SPeng Fan 	return 0;
13953697e599SPeng Fan }
13963697e599SPeng Fan 
1397272cc70bSAndy Fleming /* frequency bases */
1398272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
13995f837c2cSMike Frysinger static const int fbase[] = {
1400272cc70bSAndy Fleming 	10000,
1401272cc70bSAndy Fleming 	100000,
1402272cc70bSAndy Fleming 	1000000,
1403272cc70bSAndy Fleming 	10000000,
1404272cc70bSAndy Fleming };
1405272cc70bSAndy Fleming 
1406272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1407272cc70bSAndy Fleming  * to platforms without floating point.
1408272cc70bSAndy Fleming  */
140961fe076fSSimon Glass static const u8 multipliers[] = {
1410272cc70bSAndy Fleming 	0,	/* reserved */
1411272cc70bSAndy Fleming 	10,
1412272cc70bSAndy Fleming 	12,
1413272cc70bSAndy Fleming 	13,
1414272cc70bSAndy Fleming 	15,
1415272cc70bSAndy Fleming 	20,
1416272cc70bSAndy Fleming 	25,
1417272cc70bSAndy Fleming 	30,
1418272cc70bSAndy Fleming 	35,
1419272cc70bSAndy Fleming 	40,
1420272cc70bSAndy Fleming 	45,
1421272cc70bSAndy Fleming 	50,
1422272cc70bSAndy Fleming 	55,
1423272cc70bSAndy Fleming 	60,
1424272cc70bSAndy Fleming 	70,
1425272cc70bSAndy Fleming 	80,
1426272cc70bSAndy Fleming };
1427272cc70bSAndy Fleming 
1428d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap)
1429d0c221feSJean-Jacques Hiblot {
1430d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_8BIT)
1431d0c221feSJean-Jacques Hiblot 		return 8;
1432d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_4BIT)
1433d0c221feSJean-Jacques Hiblot 		return 4;
1434d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_1BIT)
1435d0c221feSJean-Jacques Hiblot 		return 1;
1436d0c221feSJean-Jacques Hiblot 	printf("invalid bus witdh capability 0x%x\n", cap);
1437d0c221feSJean-Jacques Hiblot 	return 0;
1438d0c221feSJean-Jacques Hiblot }
1439d0c221feSJean-Jacques Hiblot 
1440e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1441ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode)
1442ec841209SKishon Vijay Abraham I {
1443ec841209SKishon Vijay Abraham I 	return -ENOTSUPP;
1444ec841209SKishon Vijay Abraham I }
1445ec841209SKishon Vijay Abraham I 
1446318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc)
1447318a7a57SJean-Jacques Hiblot {
1448318a7a57SJean-Jacques Hiblot }
1449318a7a57SJean-Jacques Hiblot 
14502a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc)
1451272cc70bSAndy Fleming {
14522a4d212fSKishon Vijay Abraham I 	int ret = 0;
14532a4d212fSKishon Vijay Abraham I 
145493bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
14552a4d212fSKishon Vijay Abraham I 		ret = mmc->cfg->ops->set_ios(mmc);
14562a4d212fSKishon Vijay Abraham I 
14572a4d212fSKishon Vijay Abraham I 	return ret;
1458272cc70bSAndy Fleming }
14598ca51e51SSimon Glass #endif
1460272cc70bSAndy Fleming 
146135f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable)
1462272cc70bSAndy Fleming {
146393bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
146493bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1465272cc70bSAndy Fleming 
146693bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
146793bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1468272cc70bSAndy Fleming 
1469272cc70bSAndy Fleming 	mmc->clock = clock;
147035f67820SKishon Vijay Abraham I 	mmc->clk_disable = disable;
1471272cc70bSAndy Fleming 
14722a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1473272cc70bSAndy Fleming }
1474272cc70bSAndy Fleming 
14752a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width)
1476272cc70bSAndy Fleming {
1477272cc70bSAndy Fleming 	mmc->bus_width = width;
1478272cc70bSAndy Fleming 
14792a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1480272cc70bSAndy Fleming }
1481272cc70bSAndy Fleming 
14824c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
14834c9d2aaaSJean-Jacques Hiblot /*
14844c9d2aaaSJean-Jacques Hiblot  * helper function to display the capabilities in a human
14854c9d2aaaSJean-Jacques Hiblot  * friendly manner. The capabilities include bus width and
14864c9d2aaaSJean-Jacques Hiblot  * supported modes.
14874c9d2aaaSJean-Jacques Hiblot  */
14884c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps)
14894c9d2aaaSJean-Jacques Hiblot {
14904c9d2aaaSJean-Jacques Hiblot 	enum bus_mode mode;
14914c9d2aaaSJean-Jacques Hiblot 
14924c9d2aaaSJean-Jacques Hiblot 	printf("%s: widths [", text);
14934c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_8BIT)
14944c9d2aaaSJean-Jacques Hiblot 		printf("8, ");
14954c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_4BIT)
14964c9d2aaaSJean-Jacques Hiblot 		printf("4, ");
1497d0c221feSJean-Jacques Hiblot 	if (caps & MMC_MODE_1BIT)
1498d0c221feSJean-Jacques Hiblot 		printf("1, ");
1499d0c221feSJean-Jacques Hiblot 	printf("\b\b] modes [");
15004c9d2aaaSJean-Jacques Hiblot 	for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
15014c9d2aaaSJean-Jacques Hiblot 		if (MMC_CAP(mode) & caps)
15024c9d2aaaSJean-Jacques Hiblot 			printf("%s, ", mmc_mode_name(mode));
15034c9d2aaaSJean-Jacques Hiblot 	printf("\b\b]\n");
15044c9d2aaaSJean-Jacques Hiblot }
15054c9d2aaaSJean-Jacques Hiblot #endif
15064c9d2aaaSJean-Jacques Hiblot 
1507d0c221feSJean-Jacques Hiblot struct mode_width_tuning {
1508d0c221feSJean-Jacques Hiblot 	enum bus_mode mode;
1509d0c221feSJean-Jacques Hiblot 	uint widths;
1510634d4849SKishon Vijay Abraham I 	uint tuning;
1511d0c221feSJean-Jacques Hiblot };
1512d0c221feSJean-Jacques Hiblot 
1513bc1e3272SJean-Jacques Hiblot int mmc_voltage_to_mv(enum mmc_voltage voltage)
1514bc1e3272SJean-Jacques Hiblot {
1515bc1e3272SJean-Jacques Hiblot 	switch (voltage) {
1516bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_000: return 0;
1517bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_330: return 3300;
1518bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_180: return 1800;
1519bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_120: return 1200;
1520bc1e3272SJean-Jacques Hiblot 	}
1521bc1e3272SJean-Jacques Hiblot 	return -EINVAL;
1522bc1e3272SJean-Jacques Hiblot }
1523bc1e3272SJean-Jacques Hiblot 
1524aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1525aff5d3c8SKishon Vijay Abraham I {
1526bc1e3272SJean-Jacques Hiblot 	int err;
1527bc1e3272SJean-Jacques Hiblot 
1528bc1e3272SJean-Jacques Hiblot 	if (mmc->signal_voltage == signal_voltage)
1529bc1e3272SJean-Jacques Hiblot 		return 0;
1530bc1e3272SJean-Jacques Hiblot 
1531aff5d3c8SKishon Vijay Abraham I 	mmc->signal_voltage = signal_voltage;
1532bc1e3272SJean-Jacques Hiblot 	err = mmc_set_ios(mmc);
1533bc1e3272SJean-Jacques Hiblot 	if (err)
1534bc1e3272SJean-Jacques Hiblot 		debug("unable to set voltage (err %d)\n", err);
1535bc1e3272SJean-Jacques Hiblot 
1536bc1e3272SJean-Jacques Hiblot 	return err;
1537aff5d3c8SKishon Vijay Abraham I }
1538aff5d3c8SKishon Vijay Abraham I 
1539d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = {
1540d0c221feSJean-Jacques Hiblot 	{
1541c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR104,
1542c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1543c10b85d6SJean-Jacques Hiblot 		.tuning = MMC_CMD_SEND_TUNING_BLOCK
1544c10b85d6SJean-Jacques Hiblot 	},
1545c10b85d6SJean-Jacques Hiblot 	{
1546c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR50,
1547c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1548c10b85d6SJean-Jacques Hiblot 	},
1549c10b85d6SJean-Jacques Hiblot 	{
1550c10b85d6SJean-Jacques Hiblot 		.mode = UHS_DDR50,
1551c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1552c10b85d6SJean-Jacques Hiblot 	},
1553c10b85d6SJean-Jacques Hiblot 	{
1554c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR25,
1555c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1556c10b85d6SJean-Jacques Hiblot 	},
1557c10b85d6SJean-Jacques Hiblot 	{
1558d0c221feSJean-Jacques Hiblot 		.mode = SD_HS,
1559d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1560d0c221feSJean-Jacques Hiblot 	},
1561d0c221feSJean-Jacques Hiblot 	{
1562c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR12,
1563c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1564c10b85d6SJean-Jacques Hiblot 	},
1565c10b85d6SJean-Jacques Hiblot 	{
1566d0c221feSJean-Jacques Hiblot 		.mode = SD_LEGACY,
1567d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1568d0c221feSJean-Jacques Hiblot 	}
1569d0c221feSJean-Jacques Hiblot };
1570d0c221feSJean-Jacques Hiblot 
1571d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \
1572d0c221feSJean-Jacques Hiblot 	for (mwt = sd_modes_by_pref;\
1573d0c221feSJean-Jacques Hiblot 	     mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\
1574d0c221feSJean-Jacques Hiblot 	     mwt++) \
1575d0c221feSJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
1576d0c221feSJean-Jacques Hiblot 
157701298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
15788ac8a263SJean-Jacques Hiblot {
15798ac8a263SJean-Jacques Hiblot 	int err;
1580d0c221feSJean-Jacques Hiblot 	uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
1581d0c221feSJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
1582c10b85d6SJean-Jacques Hiblot 	bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false;
1583c10b85d6SJean-Jacques Hiblot 	uint caps;
1584c10b85d6SJean-Jacques Hiblot 
158552d241dfSJean-Jacques Hiblot #ifdef DEBUG
158652d241dfSJean-Jacques Hiblot 	mmc_dump_capabilities("sd card", card_caps);
158752d241dfSJean-Jacques Hiblot 	mmc_dump_capabilities("host", mmc->host_caps | MMC_MODE_1BIT);
158852d241dfSJean-Jacques Hiblot #endif
15898ac8a263SJean-Jacques Hiblot 
15908ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
159101298da3SJean-Jacques Hiblot 	caps = card_caps & (mmc->host_caps | MMC_MODE_1BIT);
15928ac8a263SJean-Jacques Hiblot 
1593c10b85d6SJean-Jacques Hiblot 	if (!uhs_en)
1594c10b85d6SJean-Jacques Hiblot 		caps &= ~UHS_CAPS;
1595c10b85d6SJean-Jacques Hiblot 
1596c10b85d6SJean-Jacques Hiblot 	for_each_sd_mode_by_pref(caps, mwt) {
1597d0c221feSJean-Jacques Hiblot 		uint *w;
15988ac8a263SJean-Jacques Hiblot 
1599d0c221feSJean-Jacques Hiblot 		for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
1600c10b85d6SJean-Jacques Hiblot 			if (*w & caps & mwt->widths) {
1601d0c221feSJean-Jacques Hiblot 				debug("trying mode %s width %d (at %d MHz)\n",
1602d0c221feSJean-Jacques Hiblot 				      mmc_mode_name(mwt->mode),
1603d0c221feSJean-Jacques Hiblot 				      bus_width(*w),
1604d0c221feSJean-Jacques Hiblot 				      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1605d0c221feSJean-Jacques Hiblot 
1606d0c221feSJean-Jacques Hiblot 				/* configure the bus width (card + host) */
1607d0c221feSJean-Jacques Hiblot 				err = sd_select_bus_width(mmc, bus_width(*w));
16088ac8a263SJean-Jacques Hiblot 				if (err)
1609d0c221feSJean-Jacques Hiblot 					goto error;
1610d0c221feSJean-Jacques Hiblot 				mmc_set_bus_width(mmc, bus_width(*w));
16118ac8a263SJean-Jacques Hiblot 
1612d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (card) */
1613d0c221feSJean-Jacques Hiblot 				err = sd_set_card_speed(mmc, mwt->mode);
16148ac8a263SJean-Jacques Hiblot 				if (err)
1615d0c221feSJean-Jacques Hiblot 					goto error;
16168ac8a263SJean-Jacques Hiblot 
1617d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (host) */
1618d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, mwt->mode);
161935f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
16208ac8a263SJean-Jacques Hiblot 
1621c10b85d6SJean-Jacques Hiblot 				/* execute tuning if needed */
1622c10b85d6SJean-Jacques Hiblot 				if (mwt->tuning && !mmc_host_is_spi(mmc)) {
1623c10b85d6SJean-Jacques Hiblot 					err = mmc_execute_tuning(mmc,
1624c10b85d6SJean-Jacques Hiblot 								 mwt->tuning);
1625c10b85d6SJean-Jacques Hiblot 					if (err) {
1626c10b85d6SJean-Jacques Hiblot 						debug("tuning failed\n");
1627c10b85d6SJean-Jacques Hiblot 						goto error;
1628c10b85d6SJean-Jacques Hiblot 					}
1629c10b85d6SJean-Jacques Hiblot 				}
1630c10b85d6SJean-Jacques Hiblot 
16318ac8a263SJean-Jacques Hiblot 				err = sd_read_ssr(mmc);
1632d0c221feSJean-Jacques Hiblot 				if (!err)
16338ac8a263SJean-Jacques Hiblot 					return 0;
1634d0c221feSJean-Jacques Hiblot 
1635d0c221feSJean-Jacques Hiblot 				printf("bad ssr\n");
1636d0c221feSJean-Jacques Hiblot 
1637d0c221feSJean-Jacques Hiblot error:
1638d0c221feSJean-Jacques Hiblot 				/* revert to a safer bus speed */
1639d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, SD_LEGACY);
164035f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
1641d0c221feSJean-Jacques Hiblot 			}
1642d0c221feSJean-Jacques Hiblot 		}
1643d0c221feSJean-Jacques Hiblot 	}
1644d0c221feSJean-Jacques Hiblot 
1645d0c221feSJean-Jacques Hiblot 	printf("unable to select a mode\n");
1646d0c221feSJean-Jacques Hiblot 	return -ENOTSUPP;
16478ac8a263SJean-Jacques Hiblot }
16488ac8a263SJean-Jacques Hiblot 
16497382e691SJean-Jacques Hiblot /*
16507382e691SJean-Jacques Hiblot  * read the compare the part of ext csd that is constant.
16517382e691SJean-Jacques Hiblot  * This can be used to check that the transfer is working
16527382e691SJean-Jacques Hiblot  * as expected.
16537382e691SJean-Jacques Hiblot  */
16547382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
16557382e691SJean-Jacques Hiblot {
16567382e691SJean-Jacques Hiblot 	int err;
16577382e691SJean-Jacques Hiblot 	const u8 *ext_csd = mmc->ext_csd;
16587382e691SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
16597382e691SJean-Jacques Hiblot 
16607382e691SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, test_csd);
16617382e691SJean-Jacques Hiblot 	if (err)
16627382e691SJean-Jacques Hiblot 		return err;
16637382e691SJean-Jacques Hiblot 
16647382e691SJean-Jacques Hiblot 	/* Only compare read only fields */
16657382e691SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
16667382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
16677382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
16687382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
16697382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_REV]
16707382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_REV] &&
16717382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
16727382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
16737382e691SJean-Jacques Hiblot 	    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
16747382e691SJean-Jacques Hiblot 		   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
16757382e691SJean-Jacques Hiblot 		return 0;
16767382e691SJean-Jacques Hiblot 
16777382e691SJean-Jacques Hiblot 	return -EBADMSG;
16787382e691SJean-Jacques Hiblot }
16797382e691SJean-Jacques Hiblot 
1680bc1e3272SJean-Jacques Hiblot static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
1681bc1e3272SJean-Jacques Hiblot 				  uint32_t allowed_mask)
1682bc1e3272SJean-Jacques Hiblot {
1683bc1e3272SJean-Jacques Hiblot 	u32 card_mask = 0;
1684bc1e3272SJean-Jacques Hiblot 
1685bc1e3272SJean-Jacques Hiblot 	switch (mode) {
1686bc1e3272SJean-Jacques Hiblot 	case MMC_HS_200:
1687bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
1688bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_180;
1689bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V)
1690bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_120;
1691bc1e3272SJean-Jacques Hiblot 		break;
1692bc1e3272SJean-Jacques Hiblot 	case MMC_DDR_52:
1693bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
1694bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_330 |
1695bc1e3272SJean-Jacques Hiblot 				     MMC_SIGNAL_VOLTAGE_180;
1696bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V)
1697bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_120;
1698bc1e3272SJean-Jacques Hiblot 		break;
1699bc1e3272SJean-Jacques Hiblot 	default:
1700bc1e3272SJean-Jacques Hiblot 		card_mask |= MMC_SIGNAL_VOLTAGE_330;
1701bc1e3272SJean-Jacques Hiblot 		break;
1702bc1e3272SJean-Jacques Hiblot 	}
1703bc1e3272SJean-Jacques Hiblot 
1704bc1e3272SJean-Jacques Hiblot 	while (card_mask & allowed_mask) {
1705bc1e3272SJean-Jacques Hiblot 		enum mmc_voltage best_match;
1706bc1e3272SJean-Jacques Hiblot 
1707bc1e3272SJean-Jacques Hiblot 		best_match = 1 << (ffs(card_mask & allowed_mask) - 1);
1708bc1e3272SJean-Jacques Hiblot 		if (!mmc_set_signal_voltage(mmc,  best_match))
1709bc1e3272SJean-Jacques Hiblot 			return 0;
1710bc1e3272SJean-Jacques Hiblot 
1711bc1e3272SJean-Jacques Hiblot 		allowed_mask &= ~best_match;
1712bc1e3272SJean-Jacques Hiblot 	}
1713bc1e3272SJean-Jacques Hiblot 
1714bc1e3272SJean-Jacques Hiblot 	return -ENOTSUPP;
1715bc1e3272SJean-Jacques Hiblot }
1716bc1e3272SJean-Jacques Hiblot 
17173862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = {
17188ac8a263SJean-Jacques Hiblot 	{
17193862b854SJean-Jacques Hiblot 		.mode = MMC_HS_200,
17203862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
1721634d4849SKishon Vijay Abraham I 		.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
17223862b854SJean-Jacques Hiblot 	},
17233862b854SJean-Jacques Hiblot 	{
17243862b854SJean-Jacques Hiblot 		.mode = MMC_DDR_52,
17253862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
17263862b854SJean-Jacques Hiblot 	},
17273862b854SJean-Jacques Hiblot 	{
17283862b854SJean-Jacques Hiblot 		.mode = MMC_HS_52,
17293862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
17303862b854SJean-Jacques Hiblot 	},
17313862b854SJean-Jacques Hiblot 	{
17323862b854SJean-Jacques Hiblot 		.mode = MMC_HS,
17333862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
17343862b854SJean-Jacques Hiblot 	},
17353862b854SJean-Jacques Hiblot 	{
17363862b854SJean-Jacques Hiblot 		.mode = MMC_LEGACY,
17373862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
17383862b854SJean-Jacques Hiblot 	}
17398ac8a263SJean-Jacques Hiblot };
17408ac8a263SJean-Jacques Hiblot 
17413862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \
17423862b854SJean-Jacques Hiblot 	for (mwt = mmc_modes_by_pref;\
17433862b854SJean-Jacques Hiblot 	    mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\
17443862b854SJean-Jacques Hiblot 	    mwt++) \
17453862b854SJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
17463862b854SJean-Jacques Hiblot 
17473862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width {
17483862b854SJean-Jacques Hiblot 	uint cap;
17493862b854SJean-Jacques Hiblot 	bool is_ddr;
17503862b854SJean-Jacques Hiblot 	uint ext_csd_bits;
17513862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = {
17523862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8},
17533862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4},
17543862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8},
17553862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4},
17563862b854SJean-Jacques Hiblot 	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
17573862b854SJean-Jacques Hiblot };
17583862b854SJean-Jacques Hiblot 
17593862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \
17603862b854SJean-Jacques Hiblot 	for (ecbv = ext_csd_bus_width;\
17613862b854SJean-Jacques Hiblot 	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
17623862b854SJean-Jacques Hiblot 	    ecbv++) \
17633862b854SJean-Jacques Hiblot 		if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
17643862b854SJean-Jacques Hiblot 
176501298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
17663862b854SJean-Jacques Hiblot {
17673862b854SJean-Jacques Hiblot 	int err;
17683862b854SJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
17693862b854SJean-Jacques Hiblot 	const struct ext_csd_bus_width *ecbw;
17703862b854SJean-Jacques Hiblot 
177152d241dfSJean-Jacques Hiblot #ifdef DEBUG
177252d241dfSJean-Jacques Hiblot 	mmc_dump_capabilities("mmc", card_caps);
177352d241dfSJean-Jacques Hiblot 	mmc_dump_capabilities("host", mmc->host_caps | MMC_MODE_1BIT);
177452d241dfSJean-Jacques Hiblot #endif
177552d241dfSJean-Jacques Hiblot 
17768ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
177701298da3SJean-Jacques Hiblot 	card_caps &= (mmc->host_caps | MMC_MODE_1BIT);
17788ac8a263SJean-Jacques Hiblot 
17798ac8a263SJean-Jacques Hiblot 	/* Only version 4 of MMC supports wider bus widths */
17808ac8a263SJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
17818ac8a263SJean-Jacques Hiblot 		return 0;
17828ac8a263SJean-Jacques Hiblot 
1783dfda9d88SJean-Jacques Hiblot 	if (!mmc->ext_csd) {
1784dfda9d88SJean-Jacques Hiblot 		debug("No ext_csd found!\n"); /* this should enver happen */
1785dfda9d88SJean-Jacques Hiblot 		return -ENOTSUPP;
1786dfda9d88SJean-Jacques Hiblot 	}
1787dfda9d88SJean-Jacques Hiblot 
178801298da3SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->legacy_speed, false);
178901298da3SJean-Jacques Hiblot 
179001298da3SJean-Jacques Hiblot 	for_each_mmc_mode_by_pref(card_caps, mwt) {
179101298da3SJean-Jacques Hiblot 		for_each_supported_width(card_caps & mwt->widths,
17923862b854SJean-Jacques Hiblot 					 mmc_is_mode_ddr(mwt->mode), ecbw) {
1793bc1e3272SJean-Jacques Hiblot 			enum mmc_voltage old_voltage;
17943862b854SJean-Jacques Hiblot 			debug("trying mode %s width %d (at %d MHz)\n",
17953862b854SJean-Jacques Hiblot 			      mmc_mode_name(mwt->mode),
17963862b854SJean-Jacques Hiblot 			      bus_width(ecbw->cap),
17973862b854SJean-Jacques Hiblot 			      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1798bc1e3272SJean-Jacques Hiblot 			old_voltage = mmc->signal_voltage;
1799bc1e3272SJean-Jacques Hiblot 			err = mmc_set_lowest_voltage(mmc, mwt->mode,
1800bc1e3272SJean-Jacques Hiblot 						     MMC_ALL_SIGNAL_VOLTAGE);
1801bc1e3272SJean-Jacques Hiblot 			if (err)
1802bc1e3272SJean-Jacques Hiblot 				continue;
1803bc1e3272SJean-Jacques Hiblot 
18043862b854SJean-Jacques Hiblot 			/* configure the bus width (card + host) */
18053862b854SJean-Jacques Hiblot 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
18063862b854SJean-Jacques Hiblot 				    EXT_CSD_BUS_WIDTH,
18073862b854SJean-Jacques Hiblot 				    ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG);
18083862b854SJean-Jacques Hiblot 			if (err)
18093862b854SJean-Jacques Hiblot 				goto error;
18103862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
18113862b854SJean-Jacques Hiblot 
18123862b854SJean-Jacques Hiblot 			/* configure the bus speed (card) */
18133862b854SJean-Jacques Hiblot 			err = mmc_set_card_speed(mmc, mwt->mode);
18143862b854SJean-Jacques Hiblot 			if (err)
18153862b854SJean-Jacques Hiblot 				goto error;
18163862b854SJean-Jacques Hiblot 
18178ac8a263SJean-Jacques Hiblot 			/*
18183862b854SJean-Jacques Hiblot 			 * configure the bus width AND the ddr mode (card)
18193862b854SJean-Jacques Hiblot 			 * The host side will be taken care of in the next step
18208ac8a263SJean-Jacques Hiblot 			 */
18213862b854SJean-Jacques Hiblot 			if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
18223862b854SJean-Jacques Hiblot 				err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
18233862b854SJean-Jacques Hiblot 						 EXT_CSD_BUS_WIDTH,
18243862b854SJean-Jacques Hiblot 						 ecbw->ext_csd_bits);
18253862b854SJean-Jacques Hiblot 				if (err)
18263862b854SJean-Jacques Hiblot 					goto error;
18278ac8a263SJean-Jacques Hiblot 			}
18288ac8a263SJean-Jacques Hiblot 
18293862b854SJean-Jacques Hiblot 			/* configure the bus mode (host) */
18303862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, mwt->mode);
183135f67820SKishon Vijay Abraham I 			mmc_set_clock(mmc, mmc->tran_speed, false);
18328ac8a263SJean-Jacques Hiblot 
1833634d4849SKishon Vijay Abraham I 			/* execute tuning if needed */
1834634d4849SKishon Vijay Abraham I 			if (mwt->tuning) {
1835634d4849SKishon Vijay Abraham I 				err = mmc_execute_tuning(mmc, mwt->tuning);
1836634d4849SKishon Vijay Abraham I 				if (err) {
1837634d4849SKishon Vijay Abraham I 					debug("tuning failed\n");
1838634d4849SKishon Vijay Abraham I 					goto error;
1839634d4849SKishon Vijay Abraham I 				}
1840634d4849SKishon Vijay Abraham I 			}
1841634d4849SKishon Vijay Abraham I 
18423862b854SJean-Jacques Hiblot 			/* do a transfer to check the configuration */
18437382e691SJean-Jacques Hiblot 			err = mmc_read_and_compare_ext_csd(mmc);
18447382e691SJean-Jacques Hiblot 			if (!err)
18453862b854SJean-Jacques Hiblot 				return 0;
18463862b854SJean-Jacques Hiblot error:
1847bc1e3272SJean-Jacques Hiblot 			mmc_set_signal_voltage(mmc, old_voltage);
18483862b854SJean-Jacques Hiblot 			/* if an error occured, revert to a safer bus mode */
18493862b854SJean-Jacques Hiblot 			mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
18503862b854SJean-Jacques Hiblot 				   EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
18513862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_LEGACY);
18523862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, 1);
18533862b854SJean-Jacques Hiblot 		}
18548ac8a263SJean-Jacques Hiblot 	}
18558ac8a263SJean-Jacques Hiblot 
18563862b854SJean-Jacques Hiblot 	printf("unable to select a mode\n");
18578ac8a263SJean-Jacques Hiblot 
18583862b854SJean-Jacques Hiblot 	return -ENOTSUPP;
18598ac8a263SJean-Jacques Hiblot }
18608ac8a263SJean-Jacques Hiblot 
1861dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
1862c744b6f6SJean-Jacques Hiblot {
1863c744b6f6SJean-Jacques Hiblot 	int err, i;
1864c744b6f6SJean-Jacques Hiblot 	u64 capacity;
1865c744b6f6SJean-Jacques Hiblot 	bool has_parts = false;
1866c744b6f6SJean-Jacques Hiblot 	bool part_completed;
1867dfda9d88SJean-Jacques Hiblot 	u8 *ext_csd;
1868c744b6f6SJean-Jacques Hiblot 
1869c744b6f6SJean-Jacques Hiblot 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
1870c744b6f6SJean-Jacques Hiblot 		return 0;
1871c744b6f6SJean-Jacques Hiblot 
1872dfda9d88SJean-Jacques Hiblot 	ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN);
1873dfda9d88SJean-Jacques Hiblot 	if (!ext_csd)
1874dfda9d88SJean-Jacques Hiblot 		return -ENOMEM;
1875dfda9d88SJean-Jacques Hiblot 
1876dfda9d88SJean-Jacques Hiblot 	mmc->ext_csd = ext_csd;
1877dfda9d88SJean-Jacques Hiblot 
1878c744b6f6SJean-Jacques Hiblot 	/* check  ext_csd version and capacity */
1879c744b6f6SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, ext_csd);
1880c744b6f6SJean-Jacques Hiblot 	if (err)
1881c744b6f6SJean-Jacques Hiblot 		return err;
1882c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_REV] >= 2) {
1883c744b6f6SJean-Jacques Hiblot 		/*
1884c744b6f6SJean-Jacques Hiblot 		 * According to the JEDEC Standard, the value of
1885c744b6f6SJean-Jacques Hiblot 		 * ext_csd's capacity is valid if the value is more
1886c744b6f6SJean-Jacques Hiblot 		 * than 2GB
1887c744b6f6SJean-Jacques Hiblot 		 */
1888c744b6f6SJean-Jacques Hiblot 		capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
1889c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
1890c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
1891c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1892c744b6f6SJean-Jacques Hiblot 		capacity *= MMC_MAX_BLOCK_LEN;
1893c744b6f6SJean-Jacques Hiblot 		if ((capacity >> 20) > 2 * 1024)
1894c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1895c744b6f6SJean-Jacques Hiblot 	}
1896c744b6f6SJean-Jacques Hiblot 
1897c744b6f6SJean-Jacques Hiblot 	switch (ext_csd[EXT_CSD_REV]) {
1898c744b6f6SJean-Jacques Hiblot 	case 1:
1899c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_1;
1900c744b6f6SJean-Jacques Hiblot 		break;
1901c744b6f6SJean-Jacques Hiblot 	case 2:
1902c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_2;
1903c744b6f6SJean-Jacques Hiblot 		break;
1904c744b6f6SJean-Jacques Hiblot 	case 3:
1905c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_3;
1906c744b6f6SJean-Jacques Hiblot 		break;
1907c744b6f6SJean-Jacques Hiblot 	case 5:
1908c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_41;
1909c744b6f6SJean-Jacques Hiblot 		break;
1910c744b6f6SJean-Jacques Hiblot 	case 6:
1911c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_5;
1912c744b6f6SJean-Jacques Hiblot 		break;
1913c744b6f6SJean-Jacques Hiblot 	case 7:
1914c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_0;
1915c744b6f6SJean-Jacques Hiblot 		break;
1916c744b6f6SJean-Jacques Hiblot 	case 8:
1917c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_1;
1918c744b6f6SJean-Jacques Hiblot 		break;
1919c744b6f6SJean-Jacques Hiblot 	}
1920c744b6f6SJean-Jacques Hiblot 
1921c744b6f6SJean-Jacques Hiblot 	/* The partition data may be non-zero but it is only
1922c744b6f6SJean-Jacques Hiblot 	 * effective if PARTITION_SETTING_COMPLETED is set in
1923c744b6f6SJean-Jacques Hiblot 	 * EXT_CSD, so ignore any data if this bit is not set,
1924c744b6f6SJean-Jacques Hiblot 	 * except for enabling the high-capacity group size
1925c744b6f6SJean-Jacques Hiblot 	 * definition (see below).
1926c744b6f6SJean-Jacques Hiblot 	 */
1927c744b6f6SJean-Jacques Hiblot 	part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
1928c744b6f6SJean-Jacques Hiblot 			    EXT_CSD_PARTITION_SETTING_COMPLETED);
1929c744b6f6SJean-Jacques Hiblot 
1930c744b6f6SJean-Jacques Hiblot 	/* store the partition info of emmc */
1931c744b6f6SJean-Jacques Hiblot 	mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
1932c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
1933c744b6f6SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_BOOT_MULT])
1934c744b6f6SJean-Jacques Hiblot 		mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
1935c744b6f6SJean-Jacques Hiblot 	if (part_completed &&
1936c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
1937c744b6f6SJean-Jacques Hiblot 		mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
1938c744b6f6SJean-Jacques Hiblot 
1939c744b6f6SJean-Jacques Hiblot 	mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
1940c744b6f6SJean-Jacques Hiblot 
1941c744b6f6SJean-Jacques Hiblot 	mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
1942c744b6f6SJean-Jacques Hiblot 
1943c744b6f6SJean-Jacques Hiblot 	for (i = 0; i < 4; i++) {
1944c744b6f6SJean-Jacques Hiblot 		int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
1945c744b6f6SJean-Jacques Hiblot 		uint mult = (ext_csd[idx + 2] << 16) +
1946c744b6f6SJean-Jacques Hiblot 			(ext_csd[idx + 1] << 8) + ext_csd[idx];
1947c744b6f6SJean-Jacques Hiblot 		if (mult)
1948c744b6f6SJean-Jacques Hiblot 			has_parts = true;
1949c744b6f6SJean-Jacques Hiblot 		if (!part_completed)
1950c744b6f6SJean-Jacques Hiblot 			continue;
1951c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] = mult;
1952c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *=
1953c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1954c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1955c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] <<= 19;
1956c744b6f6SJean-Jacques Hiblot 	}
1957c744b6f6SJean-Jacques Hiblot 
1958c744b6f6SJean-Jacques Hiblot 	if (part_completed) {
1959c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size =
1960c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
1961c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
1962c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_SIZE_MULT];
1963c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1964c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1965c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size <<= 19;
1966c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_start =
1967c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
1968c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
1969c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
1970c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_START_ADDR];
1971c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity)
1972c744b6f6SJean-Jacques Hiblot 			mmc->enh_user_start <<= 9;
1973c744b6f6SJean-Jacques Hiblot 	}
1974c744b6f6SJean-Jacques Hiblot 
1975c744b6f6SJean-Jacques Hiblot 	/*
1976c744b6f6SJean-Jacques Hiblot 	 * Host needs to enable ERASE_GRP_DEF bit if device is
1977c744b6f6SJean-Jacques Hiblot 	 * partitioned. This bit will be lost every time after a reset
1978c744b6f6SJean-Jacques Hiblot 	 * or power off. This will affect erase size.
1979c744b6f6SJean-Jacques Hiblot 	 */
1980c744b6f6SJean-Jacques Hiblot 	if (part_completed)
1981c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1982c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
1983c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
1984c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1985c744b6f6SJean-Jacques Hiblot 	if (has_parts) {
1986c744b6f6SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1987c744b6f6SJean-Jacques Hiblot 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1988c744b6f6SJean-Jacques Hiblot 
1989c744b6f6SJean-Jacques Hiblot 		if (err)
1990c744b6f6SJean-Jacques Hiblot 			return err;
1991c744b6f6SJean-Jacques Hiblot 
1992c744b6f6SJean-Jacques Hiblot 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1993c744b6f6SJean-Jacques Hiblot 	}
1994c744b6f6SJean-Jacques Hiblot 
1995c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
1996c744b6f6SJean-Jacques Hiblot 		/* Read out group size from ext_csd */
1997c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size =
1998c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1999c744b6f6SJean-Jacques Hiblot 		/*
2000c744b6f6SJean-Jacques Hiblot 		 * if high capacity and partition setting completed
2001c744b6f6SJean-Jacques Hiblot 		 * SEC_COUNT is valid even if it is smaller than 2 GiB
2002c744b6f6SJean-Jacques Hiblot 		 * JEDEC Standard JESD84-B45, 6.2.4
2003c744b6f6SJean-Jacques Hiblot 		 */
2004c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity && part_completed) {
2005c744b6f6SJean-Jacques Hiblot 			capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
2006c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
2007c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
2008c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
2009c744b6f6SJean-Jacques Hiblot 			capacity *= MMC_MAX_BLOCK_LEN;
2010c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
2011c744b6f6SJean-Jacques Hiblot 		}
2012c744b6f6SJean-Jacques Hiblot 	} else {
2013c744b6f6SJean-Jacques Hiblot 		/* Calculate the group size from the csd value. */
2014c744b6f6SJean-Jacques Hiblot 		int erase_gsz, erase_gmul;
2015c744b6f6SJean-Jacques Hiblot 
2016c744b6f6SJean-Jacques Hiblot 		erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
2017c744b6f6SJean-Jacques Hiblot 		erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
2018c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size = (erase_gsz + 1)
2019c744b6f6SJean-Jacques Hiblot 			* (erase_gmul + 1);
2020c744b6f6SJean-Jacques Hiblot 	}
2021c744b6f6SJean-Jacques Hiblot 
2022c744b6f6SJean-Jacques Hiblot 	mmc->hc_wp_grp_size = 1024
2023c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
2024c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2025c744b6f6SJean-Jacques Hiblot 
2026c744b6f6SJean-Jacques Hiblot 	mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
2027c744b6f6SJean-Jacques Hiblot 
2028c744b6f6SJean-Jacques Hiblot 	return 0;
2029c744b6f6SJean-Jacques Hiblot }
2030c744b6f6SJean-Jacques Hiblot 
2031fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
2032272cc70bSAndy Fleming {
2033f866a46dSStephen Warren 	int err, i;
2034272cc70bSAndy Fleming 	uint mult, freq;
2035c744b6f6SJean-Jacques Hiblot 	u64 cmult, csize;
2036272cc70bSAndy Fleming 	struct mmc_cmd cmd;
2037c40fdca6SSimon Glass 	struct blk_desc *bdesc;
2038272cc70bSAndy Fleming 
2039d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
2040d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
2041d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
2042d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
2043d52ebf10SThomas Chou 		cmd.cmdarg = 1;
2044d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
2045d52ebf10SThomas Chou 		if (err)
2046d52ebf10SThomas Chou 			return err;
2047d52ebf10SThomas Chou 	}
2048d52ebf10SThomas Chou #endif
2049d52ebf10SThomas Chou 
2050272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
2051d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
2052d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
2053272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
2054272cc70bSAndy Fleming 	cmd.cmdarg = 0;
2055272cc70bSAndy Fleming 
2056272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2057272cc70bSAndy Fleming 
205883dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
205983dc4227SKishon Vijay Abraham I 	if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) {
206083dc4227SKishon Vijay Abraham I 		int retries = 4;
206183dc4227SKishon Vijay Abraham I 		/*
206283dc4227SKishon Vijay Abraham I 		 * It has been seen that SEND_CID may fail on the first
206383dc4227SKishon Vijay Abraham I 		 * attempt, let's try a few more time
206483dc4227SKishon Vijay Abraham I 		 */
206583dc4227SKishon Vijay Abraham I 		do {
206683dc4227SKishon Vijay Abraham I 			err = mmc_send_cmd(mmc, &cmd, NULL);
206783dc4227SKishon Vijay Abraham I 			if (!err)
206883dc4227SKishon Vijay Abraham I 				break;
206983dc4227SKishon Vijay Abraham I 		} while (retries--);
207083dc4227SKishon Vijay Abraham I 	}
207183dc4227SKishon Vijay Abraham I #endif
207283dc4227SKishon Vijay Abraham I 
2073272cc70bSAndy Fleming 	if (err)
2074272cc70bSAndy Fleming 		return err;
2075272cc70bSAndy Fleming 
2076272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
2077272cc70bSAndy Fleming 
2078272cc70bSAndy Fleming 	/*
2079272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
2080272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
2081272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
2082272cc70bSAndy Fleming 	 */
2083d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2084272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
2085272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
2086272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
2087272cc70bSAndy Fleming 
2088272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
2089272cc70bSAndy Fleming 
2090272cc70bSAndy Fleming 		if (err)
2091272cc70bSAndy Fleming 			return err;
2092272cc70bSAndy Fleming 
2093272cc70bSAndy Fleming 		if (IS_SD(mmc))
2094998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
2095d52ebf10SThomas Chou 	}
2096272cc70bSAndy Fleming 
2097272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
2098272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
2099272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
2100272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
2101272cc70bSAndy Fleming 
2102272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2103272cc70bSAndy Fleming 
2104272cc70bSAndy Fleming 	if (err)
2105272cc70bSAndy Fleming 		return err;
2106272cc70bSAndy Fleming 
2107998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
2108998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
2109998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
2110998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
2111272cc70bSAndy Fleming 
2112272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
21130b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
2114272cc70bSAndy Fleming 
2115272cc70bSAndy Fleming 		switch (version) {
2116272cc70bSAndy Fleming 		case 0:
2117272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
2118272cc70bSAndy Fleming 			break;
2119272cc70bSAndy Fleming 		case 1:
2120272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
2121272cc70bSAndy Fleming 			break;
2122272cc70bSAndy Fleming 		case 2:
2123272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
2124272cc70bSAndy Fleming 			break;
2125272cc70bSAndy Fleming 		case 3:
2126272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
2127272cc70bSAndy Fleming 			break;
2128272cc70bSAndy Fleming 		case 4:
2129272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
2130272cc70bSAndy Fleming 			break;
2131272cc70bSAndy Fleming 		default:
2132272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
2133272cc70bSAndy Fleming 			break;
2134272cc70bSAndy Fleming 		}
2135272cc70bSAndy Fleming 	}
2136272cc70bSAndy Fleming 
2137272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
21380b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
21390b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
2140272cc70bSAndy Fleming 
214135f9e196SJean-Jacques Hiblot 	mmc->legacy_speed = freq * mult;
214235f9e196SJean-Jacques Hiblot 	mmc_select_mode(mmc, MMC_LEGACY);
2143272cc70bSAndy Fleming 
2144ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
2145998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
2146272cc70bSAndy Fleming 
2147272cc70bSAndy Fleming 	if (IS_SD(mmc))
2148272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
2149272cc70bSAndy Fleming 	else
2150998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
2151272cc70bSAndy Fleming 
2152272cc70bSAndy Fleming 	if (mmc->high_capacity) {
2153272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
2154272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
2155272cc70bSAndy Fleming 		cmult = 8;
2156272cc70bSAndy Fleming 	} else {
2157272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
2158272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
2159272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
2160272cc70bSAndy Fleming 	}
2161272cc70bSAndy Fleming 
2162f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
2163f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
2164f866a46dSStephen Warren 	mmc->capacity_boot = 0;
2165f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
2166f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
2167f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
2168272cc70bSAndy Fleming 
21698bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
21708bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
2171272cc70bSAndy Fleming 
21728bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
21738bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
2174272cc70bSAndy Fleming 
2175ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
2176ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
2177ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
2178ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
2179ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
2180ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
2181ab71188cSMarkus Niebel 	}
2182ab71188cSMarkus Niebel 
2183272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
2184d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2185272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
2186fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
2187272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
2188272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
2189272cc70bSAndy Fleming 
2190272cc70bSAndy Fleming 		if (err)
2191272cc70bSAndy Fleming 			return err;
2192d52ebf10SThomas Chou 	}
2193272cc70bSAndy Fleming 
2194e6f99a56SLei Wen 	/*
2195e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
2196e6f99a56SLei Wen 	 */
2197e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
2198bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
2199c744b6f6SJean-Jacques Hiblot 
2200dfda9d88SJean-Jacques Hiblot 	err = mmc_startup_v4(mmc);
22019cf199ebSDiego Santa Cruz 	if (err)
22029cf199ebSDiego Santa Cruz 		return err;
2203f866a46dSStephen Warren 
2204c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
2205f866a46dSStephen Warren 	if (err)
2206f866a46dSStephen Warren 		return err;
2207d23e2c09SSukumar Ghorai 
220801298da3SJean-Jacques Hiblot 	if (IS_SD(mmc)) {
220901298da3SJean-Jacques Hiblot 		err = sd_get_capabilities(mmc);
221001298da3SJean-Jacques Hiblot 		if (err)
221101298da3SJean-Jacques Hiblot 			return err;
221201298da3SJean-Jacques Hiblot 		err = sd_select_mode_and_width(mmc, mmc->card_caps);
221301298da3SJean-Jacques Hiblot 	} else {
221401298da3SJean-Jacques Hiblot 		err = mmc_get_capabilities(mmc);
221501298da3SJean-Jacques Hiblot 		if (err)
221601298da3SJean-Jacques Hiblot 			return err;
221701298da3SJean-Jacques Hiblot 		mmc_select_mode_and_width(mmc, mmc->card_caps);
221801298da3SJean-Jacques Hiblot 	}
2219272cc70bSAndy Fleming 
2220272cc70bSAndy Fleming 	if (err)
2221272cc70bSAndy Fleming 		return err;
2222272cc70bSAndy Fleming 
222301298da3SJean-Jacques Hiblot 	mmc->best_mode = mmc->selected_mode;
2224272cc70bSAndy Fleming 
22255af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
22265af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
22275af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
22285af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
22295af8f45cSAndrew Gabbasov 	}
22305af8f45cSAndrew Gabbasov 
2231272cc70bSAndy Fleming 	/* fill in device description */
2232c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
2233c40fdca6SSimon Glass 	bdesc->lun = 0;
2234c40fdca6SSimon Glass 	bdesc->hwpart = 0;
2235c40fdca6SSimon Glass 	bdesc->type = 0;
2236c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
2237c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
2238c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
2239fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
2240fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
2241fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
2242c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
2243babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
2244babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
2245c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
22460b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
2247babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
2248babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
2249c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
2250babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
225156196826SPaul Burton #else
2252c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
2253c40fdca6SSimon Glass 	bdesc->product[0] = 0;
2254c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
225556196826SPaul Burton #endif
2256122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
2257c40fdca6SSimon Glass 	part_init(bdesc);
2258122efd43SMikhail Kshevetskiy #endif
2259272cc70bSAndy Fleming 
2260272cc70bSAndy Fleming 	return 0;
2261272cc70bSAndy Fleming }
2262272cc70bSAndy Fleming 
2263fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
2264272cc70bSAndy Fleming {
2265272cc70bSAndy Fleming 	struct mmc_cmd cmd;
2266272cc70bSAndy Fleming 	int err;
2267272cc70bSAndy Fleming 
2268272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
2269272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
227093bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
2271272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
2272272cc70bSAndy Fleming 
2273272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2274272cc70bSAndy Fleming 
2275272cc70bSAndy Fleming 	if (err)
2276272cc70bSAndy Fleming 		return err;
2277272cc70bSAndy Fleming 
2278998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
2279915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
2280272cc70bSAndy Fleming 	else
2281272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
2282272cc70bSAndy Fleming 
2283272cc70bSAndy Fleming 	return 0;
2284272cc70bSAndy Fleming }
2285272cc70bSAndy Fleming 
2286c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
228795de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
228895de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
228995de9ab2SPaul Kocialkowski {
229095de9ab2SPaul Kocialkowski }
229105cbeb7cSSimon Glass #endif
229295de9ab2SPaul Kocialkowski 
22932051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
22942051aefeSPeng Fan {
2295c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
229606ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
22972051aefeSPeng Fan 	int ret;
22982051aefeSPeng Fan 
22992051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
230006ec045fSJean-Jacques Hiblot 					  &mmc->vmmc_supply);
230106ec045fSJean-Jacques Hiblot 	if (ret)
2302288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
23032051aefeSPeng Fan 
230406ec045fSJean-Jacques Hiblot 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
230506ec045fSJean-Jacques Hiblot 					  &mmc->vqmmc_supply);
230606ec045fSJean-Jacques Hiblot 	if (ret)
230706ec045fSJean-Jacques Hiblot 		debug("%s: No vqmmc supply\n", mmc->dev->name);
23082051aefeSPeng Fan #endif
230905cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
231005cbeb7cSSimon Glass 	/*
231105cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
231205cbeb7cSSimon Glass 	 * out to board code.
231305cbeb7cSSimon Glass 	 */
231405cbeb7cSSimon Glass 	board_mmc_power_init();
231505cbeb7cSSimon Glass #endif
23162051aefeSPeng Fan 	return 0;
23172051aefeSPeng Fan }
23182051aefeSPeng Fan 
2319fb7c3bebSKishon Vijay Abraham I /*
2320fb7c3bebSKishon Vijay Abraham I  * put the host in the initial state:
2321fb7c3bebSKishon Vijay Abraham I  * - turn on Vdd (card power supply)
2322fb7c3bebSKishon Vijay Abraham I  * - configure the bus width and clock to minimal values
2323fb7c3bebSKishon Vijay Abraham I  */
2324fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc)
2325fb7c3bebSKishon Vijay Abraham I {
2326fb7c3bebSKishon Vijay Abraham I 	int err;
2327fb7c3bebSKishon Vijay Abraham I 
2328fb7c3bebSKishon Vijay Abraham I 	/* First try to set 3.3V. If it fails set to 1.8V */
2329fb7c3bebSKishon Vijay Abraham I 	err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330);
2330fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2331fb7c3bebSKishon Vijay Abraham I 		err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
2332fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2333fb7c3bebSKishon Vijay Abraham I 		printf("mmc: failed to set signal voltage\n");
2334fb7c3bebSKishon Vijay Abraham I 
2335fb7c3bebSKishon Vijay Abraham I 	mmc_select_mode(mmc, MMC_LEGACY);
2336fb7c3bebSKishon Vijay Abraham I 	mmc_set_bus_width(mmc, 1);
233735f67820SKishon Vijay Abraham I 	mmc_set_clock(mmc, 0, false);
2338fb7c3bebSKishon Vijay Abraham I }
2339fb7c3bebSKishon Vijay Abraham I 
2340fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc)
2341fb7c3bebSKishon Vijay Abraham I {
2342fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2343fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2344fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, true);
2345fb7c3bebSKishon Vijay Abraham I 
2346fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2347fb7c3bebSKishon Vijay Abraham I 			puts("Error enabling VMMC supply\n");
2348fb7c3bebSKishon Vijay Abraham I 			return ret;
2349fb7c3bebSKishon Vijay Abraham I 		}
2350fb7c3bebSKishon Vijay Abraham I 	}
2351fb7c3bebSKishon Vijay Abraham I #endif
2352fb7c3bebSKishon Vijay Abraham I 	return 0;
2353fb7c3bebSKishon Vijay Abraham I }
2354fb7c3bebSKishon Vijay Abraham I 
2355fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc)
2356fb7c3bebSKishon Vijay Abraham I {
23572e7410d7SKishon Vijay Abraham I 	mmc_set_clock(mmc, 1, true);
2358fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2359fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2360fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, false);
2361fb7c3bebSKishon Vijay Abraham I 
2362fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2363c10b85d6SJean-Jacques Hiblot 			debug("Error disabling VMMC supply\n");
2364fb7c3bebSKishon Vijay Abraham I 			return ret;
2365fb7c3bebSKishon Vijay Abraham I 		}
2366fb7c3bebSKishon Vijay Abraham I 	}
2367fb7c3bebSKishon Vijay Abraham I #endif
2368fb7c3bebSKishon Vijay Abraham I 	return 0;
2369fb7c3bebSKishon Vijay Abraham I }
2370fb7c3bebSKishon Vijay Abraham I 
2371fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc)
2372fb7c3bebSKishon Vijay Abraham I {
2373fb7c3bebSKishon Vijay Abraham I 	int ret;
2374fb7c3bebSKishon Vijay Abraham I 
2375fb7c3bebSKishon Vijay Abraham I 	ret = mmc_power_off(mmc);
2376fb7c3bebSKishon Vijay Abraham I 	if (ret)
2377fb7c3bebSKishon Vijay Abraham I 		return ret;
2378fb7c3bebSKishon Vijay Abraham I 	/*
2379fb7c3bebSKishon Vijay Abraham I 	 * SD spec recommends at least 1ms of delay. Let's wait for 2ms
2380fb7c3bebSKishon Vijay Abraham I 	 * to be on the safer side.
2381fb7c3bebSKishon Vijay Abraham I 	 */
2382fb7c3bebSKishon Vijay Abraham I 	udelay(2000);
2383fb7c3bebSKishon Vijay Abraham I 	return mmc_power_on(mmc);
2384fb7c3bebSKishon Vijay Abraham I }
2385fb7c3bebSKishon Vijay Abraham I 
2386e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
2387272cc70bSAndy Fleming {
23888ca51e51SSimon Glass 	bool no_card;
2389c10b85d6SJean-Jacques Hiblot 	bool uhs_en = supports_uhs(mmc->cfg->host_caps);
2390afd5932bSMacpaul Lin 	int err;
2391272cc70bSAndy Fleming 
239204a2ea24SJean-Jacques Hiblot 	mmc->host_caps = mmc->cfg->host_caps;
239304a2ea24SJean-Jacques Hiblot 
2394ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
23958ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
2396e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
23978ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
23988ca51e51SSimon Glass #endif
23998ca51e51SSimon Glass 	if (no_card) {
240048972d90SThierry Reding 		mmc->has_init = 0;
240156196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
240248972d90SThierry Reding 		printf("MMC: no card present\n");
240356196826SPaul Burton #endif
2404915ffa52SJaehoon Chung 		return -ENOMEDIUM;
240548972d90SThierry Reding 	}
240648972d90SThierry Reding 
2407bc897b1dSLei Wen 	if (mmc->has_init)
2408bc897b1dSLei Wen 		return 0;
2409bc897b1dSLei Wen 
24105a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
24115a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
24125a8dbdc6SYangbo Lu #endif
24132051aefeSPeng Fan 	err = mmc_power_init(mmc);
24142051aefeSPeng Fan 	if (err)
24152051aefeSPeng Fan 		return err;
241695de9ab2SPaul Kocialkowski 
241783dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
241883dc4227SKishon Vijay Abraham I 	mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN |
241983dc4227SKishon Vijay Abraham I 		      MMC_QUIRK_RETRY_SEND_CID;
242083dc4227SKishon Vijay Abraham I #endif
242183dc4227SKishon Vijay Abraham I 
242204a2ea24SJean-Jacques Hiblot 	err = mmc_power_cycle(mmc);
242304a2ea24SJean-Jacques Hiblot 	if (err) {
242404a2ea24SJean-Jacques Hiblot 		/*
242504a2ea24SJean-Jacques Hiblot 		 * if power cycling is not supported, we should not try
242604a2ea24SJean-Jacques Hiblot 		 * to use the UHS modes, because we wouldn't be able to
242704a2ea24SJean-Jacques Hiblot 		 * recover from an error during the UHS initialization.
242804a2ea24SJean-Jacques Hiblot 		 */
242904a2ea24SJean-Jacques Hiblot 		debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n");
243004a2ea24SJean-Jacques Hiblot 		uhs_en = false;
243104a2ea24SJean-Jacques Hiblot 		mmc->host_caps &= ~UHS_CAPS;
2432fb7c3bebSKishon Vijay Abraham I 		err = mmc_power_on(mmc);
243304a2ea24SJean-Jacques Hiblot 	}
2434fb7c3bebSKishon Vijay Abraham I 	if (err)
2435fb7c3bebSKishon Vijay Abraham I 		return err;
2436fb7c3bebSKishon Vijay Abraham I 
2437e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
24388ca51e51SSimon Glass 	/* The device has already been probed ready for use */
24398ca51e51SSimon Glass #else
2440ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
244193bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
2442272cc70bSAndy Fleming 	if (err)
2443272cc70bSAndy Fleming 		return err;
24448ca51e51SSimon Glass #endif
2445786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
2446aff5d3c8SKishon Vijay Abraham I 
2447c10b85d6SJean-Jacques Hiblot retry:
2448fb7c3bebSKishon Vijay Abraham I 	mmc_set_initial_state(mmc);
2449318a7a57SJean-Jacques Hiblot 	mmc_send_init_stream(mmc);
2450318a7a57SJean-Jacques Hiblot 
2451272cc70bSAndy Fleming 	/* Reset the Card */
2452272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
2453272cc70bSAndy Fleming 
2454272cc70bSAndy Fleming 	if (err)
2455272cc70bSAndy Fleming 		return err;
2456272cc70bSAndy Fleming 
2457bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
2458c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
2459bc897b1dSLei Wen 
2460272cc70bSAndy Fleming 	/* Test for SD version 2 */
2461272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
2462272cc70bSAndy Fleming 
2463272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
2464c10b85d6SJean-Jacques Hiblot 	err = sd_send_op_cond(mmc, uhs_en);
2465c10b85d6SJean-Jacques Hiblot 	if (err && uhs_en) {
2466c10b85d6SJean-Jacques Hiblot 		uhs_en = false;
2467c10b85d6SJean-Jacques Hiblot 		mmc_power_cycle(mmc);
2468c10b85d6SJean-Jacques Hiblot 		goto retry;
2469c10b85d6SJean-Jacques Hiblot 	}
2470272cc70bSAndy Fleming 
2471272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
2472915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
2473272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
2474272cc70bSAndy Fleming 
2475bd47c135SAndrew Gabbasov 		if (err) {
247656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2477272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
247856196826SPaul Burton #endif
2479915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
2480272cc70bSAndy Fleming 		}
2481272cc70bSAndy Fleming 	}
2482272cc70bSAndy Fleming 
2483bd47c135SAndrew Gabbasov 	if (!err)
2484e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
2485e9550449SChe-Liang Chiou 
2486e9550449SChe-Liang Chiou 	return err;
2487e9550449SChe-Liang Chiou }
2488e9550449SChe-Liang Chiou 
2489e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2490e9550449SChe-Liang Chiou {
2491e9550449SChe-Liang Chiou 	int err = 0;
2492e9550449SChe-Liang Chiou 
2493bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
2494e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
2495e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
2496e9550449SChe-Liang Chiou 
2497e9550449SChe-Liang Chiou 	if (!err)
2498bc897b1dSLei Wen 		err = mmc_startup(mmc);
2499bc897b1dSLei Wen 	if (err)
2500bc897b1dSLei Wen 		mmc->has_init = 0;
2501bc897b1dSLei Wen 	else
2502bc897b1dSLei Wen 		mmc->has_init = 1;
2503e9550449SChe-Liang Chiou 	return err;
2504e9550449SChe-Liang Chiou }
2505e9550449SChe-Liang Chiou 
2506e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2507e9550449SChe-Liang Chiou {
2508bd47c135SAndrew Gabbasov 	int err = 0;
2509ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
2510c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
251133fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2512e9550449SChe-Liang Chiou 
251333fb211dSSimon Glass 	upriv->mmc = mmc;
251433fb211dSSimon Glass #endif
2515e9550449SChe-Liang Chiou 	if (mmc->has_init)
2516e9550449SChe-Liang Chiou 		return 0;
2517d803fea5SMateusz Zalega 
2518d803fea5SMateusz Zalega 	start = get_timer(0);
2519d803fea5SMateusz Zalega 
2520e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2521e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2522e9550449SChe-Liang Chiou 
2523bd47c135SAndrew Gabbasov 	if (!err)
2524e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2525919b4858SJagan Teki 	if (err)
2526919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
2527919b4858SJagan Teki 
2528bc897b1dSLei Wen 	return err;
2529272cc70bSAndy Fleming }
2530272cc70bSAndy Fleming 
2531ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2532ab71188cSMarkus Niebel {
2533ab71188cSMarkus Niebel 	mmc->dsr = val;
2534ab71188cSMarkus Niebel 	return 0;
2535ab71188cSMarkus Niebel }
2536ab71188cSMarkus Niebel 
2537cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2538cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2539272cc70bSAndy Fleming {
2540272cc70bSAndy Fleming 	return -1;
2541272cc70bSAndy Fleming }
2542272cc70bSAndy Fleming 
2543cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2544cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2545cee9ab7cSJeroen Hofstee {
2546cee9ab7cSJeroen Hofstee 	return -1;
2547cee9ab7cSJeroen Hofstee }
2548272cc70bSAndy Fleming 
2549e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2550e9550449SChe-Liang Chiou {
2551e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2552e9550449SChe-Liang Chiou }
2553e9550449SChe-Liang Chiou 
2554c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
25558e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
25568e3332e2SSjoerd Simons {
25578e3332e2SSjoerd Simons 	return 0;
25588e3332e2SSjoerd Simons }
2559c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
25608e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
25618e3332e2SSjoerd Simons {
25624a1db6d8SSimon Glass 	int ret, i;
25638e3332e2SSjoerd Simons 	struct uclass *uc;
25644a1db6d8SSimon Glass 	struct udevice *dev;
25658e3332e2SSjoerd Simons 
25668e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
25678e3332e2SSjoerd Simons 	if (ret)
25688e3332e2SSjoerd Simons 		return ret;
25698e3332e2SSjoerd Simons 
25704a1db6d8SSimon Glass 	/*
25714a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
25724a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
25734a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
25744a1db6d8SSimon Glass 	 */
25754a1db6d8SSimon Glass 	for (i = 0; ; i++) {
25764a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
25774a1db6d8SSimon Glass 		if (ret == -ENODEV)
25784a1db6d8SSimon Glass 			break;
25794a1db6d8SSimon Glass 	}
25804a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
25814a1db6d8SSimon Glass 		ret = device_probe(dev);
25828e3332e2SSjoerd Simons 		if (ret)
25834a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
25848e3332e2SSjoerd Simons 	}
25858e3332e2SSjoerd Simons 
25868e3332e2SSjoerd Simons 	return 0;
25878e3332e2SSjoerd Simons }
25888e3332e2SSjoerd Simons #else
25898e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
25908e3332e2SSjoerd Simons {
25918e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
25928e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
25938e3332e2SSjoerd Simons 
25948e3332e2SSjoerd Simons 	return 0;
25958e3332e2SSjoerd Simons }
25968e3332e2SSjoerd Simons #endif
2597e9550449SChe-Liang Chiou 
2598272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2599272cc70bSAndy Fleming {
26001b26bab1SDaniel Kochmański 	static int initialized = 0;
26018e3332e2SSjoerd Simons 	int ret;
26021b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
26031b26bab1SDaniel Kochmański 		return 0;
26041b26bab1SDaniel Kochmański 	initialized = 1;
26051b26bab1SDaniel Kochmański 
2606c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2607b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2608c40fdca6SSimon Glass 	mmc_list_init();
2609c40fdca6SSimon Glass #endif
2610b5b838f1SMarek Vasut #endif
26118e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
26128e3332e2SSjoerd Simons 	if (ret)
26138e3332e2SSjoerd Simons 		return ret;
2614272cc70bSAndy Fleming 
2615bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2616272cc70bSAndy Fleming 	print_mmc_devices(',');
2617bb0dc108SYing Zhang #endif
2618272cc70bSAndy Fleming 
2619c40fdca6SSimon Glass 	mmc_do_preinit();
2620272cc70bSAndy Fleming 	return 0;
2621272cc70bSAndy Fleming }
2622cd3d4880STomas Melin 
2623cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2624cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2625cd3d4880STomas Melin {
2626cd3d4880STomas Melin 	int err;
2627cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2628cd3d4880STomas Melin 
2629cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2630cd3d4880STomas Melin 	if (err) {
2631cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2632cd3d4880STomas Melin 		return err;
2633cd3d4880STomas Melin 	}
2634cd3d4880STomas Melin 
2635cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2636cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2637cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2638cd3d4880STomas Melin 	}
2639cd3d4880STomas Melin 
2640cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2641cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2642cd3d4880STomas Melin 		return 0;
2643cd3d4880STomas Melin 	}
2644cd3d4880STomas Melin 
2645cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2646cd3d4880STomas Melin 	if (err) {
2647cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2648cd3d4880STomas Melin 		return err;
2649cd3d4880STomas Melin 	}
2650cd3d4880STomas Melin 
2651cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2652cd3d4880STomas Melin 
2653cd3d4880STomas Melin 	return 0;
2654cd3d4880STomas Melin }
2655cd3d4880STomas Melin #endif
2656