xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision bc1e3272)
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 
311ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
312fdbb873eSKim Phillips 			   lbaint_t blkcnt)
313272cc70bSAndy Fleming {
314272cc70bSAndy Fleming 	struct mmc_cmd cmd;
315272cc70bSAndy Fleming 	struct mmc_data data;
316272cc70bSAndy Fleming 
3174a1a06bcSAlagu Sankar 	if (blkcnt > 1)
3184a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
3194a1a06bcSAlagu Sankar 	else
320272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
321272cc70bSAndy Fleming 
322272cc70bSAndy Fleming 	if (mmc->high_capacity)
3234a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
324272cc70bSAndy Fleming 	else
3254a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
326272cc70bSAndy Fleming 
327272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
328272cc70bSAndy Fleming 
329272cc70bSAndy Fleming 	data.dest = dst;
3304a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
331272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
332272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
333272cc70bSAndy Fleming 
3344a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
3354a1a06bcSAlagu Sankar 		return 0;
3364a1a06bcSAlagu Sankar 
3374a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
3384a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
3394a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
3404a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
3414a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
34256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
3434a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
34456196826SPaul Burton #endif
3454a1a06bcSAlagu Sankar 			return 0;
3464a1a06bcSAlagu Sankar 		}
347272cc70bSAndy Fleming 	}
348272cc70bSAndy Fleming 
3494a1a06bcSAlagu Sankar 	return blkcnt;
350272cc70bSAndy Fleming }
351272cc70bSAndy Fleming 
352c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
3537dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
35433fb211dSSimon Glass #else
3557dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
3567dba0b93SSimon Glass 		void *dst)
35733fb211dSSimon Glass #endif
358272cc70bSAndy Fleming {
359c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
36033fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
36133fb211dSSimon Glass #endif
362bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
363873cc1d7SStephen Warren 	int err;
3644a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
365272cc70bSAndy Fleming 
3664a1a06bcSAlagu Sankar 	if (blkcnt == 0)
3674a1a06bcSAlagu Sankar 		return 0;
3684a1a06bcSAlagu Sankar 
3694a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
370272cc70bSAndy Fleming 	if (!mmc)
371272cc70bSAndy Fleming 		return 0;
372272cc70bSAndy Fleming 
373b5b838f1SMarek Vasut 	if (CONFIG_IS_ENABLED(MMC_TINY))
374b5b838f1SMarek Vasut 		err = mmc_switch_part(mmc, block_dev->hwpart);
375b5b838f1SMarek Vasut 	else
37669f45cd5SSimon Glass 		err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
377b5b838f1SMarek Vasut 
378873cc1d7SStephen Warren 	if (err < 0)
379873cc1d7SStephen Warren 		return 0;
380873cc1d7SStephen Warren 
381c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
38256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
383ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
384c40fdca6SSimon Glass 			start + blkcnt, block_dev->lba);
38556196826SPaul Burton #endif
386d2bf29e3SLei Wen 		return 0;
387d2bf29e3SLei Wen 	}
388272cc70bSAndy Fleming 
38911692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
39011692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
391272cc70bSAndy Fleming 		return 0;
39211692991SSimon Glass 	}
393272cc70bSAndy Fleming 
3944a1a06bcSAlagu Sankar 	do {
39593bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
39693bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
39711692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
39811692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
3994a1a06bcSAlagu Sankar 			return 0;
40011692991SSimon Glass 		}
4014a1a06bcSAlagu Sankar 		blocks_todo -= cur;
4024a1a06bcSAlagu Sankar 		start += cur;
4034a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
4044a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
405272cc70bSAndy Fleming 
406272cc70bSAndy Fleming 	return blkcnt;
407272cc70bSAndy Fleming }
408272cc70bSAndy Fleming 
409fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
410272cc70bSAndy Fleming {
411272cc70bSAndy Fleming 	struct mmc_cmd cmd;
412272cc70bSAndy Fleming 	int err;
413272cc70bSAndy Fleming 
414272cc70bSAndy Fleming 	udelay(1000);
415272cc70bSAndy Fleming 
416272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
417272cc70bSAndy Fleming 	cmd.cmdarg = 0;
418272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
419272cc70bSAndy Fleming 
420272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
421272cc70bSAndy Fleming 
422272cc70bSAndy Fleming 	if (err)
423272cc70bSAndy Fleming 		return err;
424272cc70bSAndy Fleming 
425272cc70bSAndy Fleming 	udelay(2000);
426272cc70bSAndy Fleming 
427272cc70bSAndy Fleming 	return 0;
428272cc70bSAndy Fleming }
429272cc70bSAndy Fleming 
430c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage)
431c10b85d6SJean-Jacques Hiblot {
432c10b85d6SJean-Jacques Hiblot 	struct mmc_cmd cmd;
433c10b85d6SJean-Jacques Hiblot 	int err = 0;
434c10b85d6SJean-Jacques Hiblot 
435c10b85d6SJean-Jacques Hiblot 	/*
436c10b85d6SJean-Jacques Hiblot 	 * Send CMD11 only if the request is to switch the card to
437c10b85d6SJean-Jacques Hiblot 	 * 1.8V signalling.
438c10b85d6SJean-Jacques Hiblot 	 */
439c10b85d6SJean-Jacques Hiblot 	if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
440c10b85d6SJean-Jacques Hiblot 		return mmc_set_signal_voltage(mmc, signal_voltage);
441c10b85d6SJean-Jacques Hiblot 
442c10b85d6SJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_SWITCH_UHS18V;
443c10b85d6SJean-Jacques Hiblot 	cmd.cmdarg = 0;
444c10b85d6SJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
445c10b85d6SJean-Jacques Hiblot 
446c10b85d6SJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
447c10b85d6SJean-Jacques Hiblot 	if (err)
448c10b85d6SJean-Jacques Hiblot 		return err;
449c10b85d6SJean-Jacques Hiblot 
450c10b85d6SJean-Jacques Hiblot 	if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR))
451c10b85d6SJean-Jacques Hiblot 		return -EIO;
452c10b85d6SJean-Jacques Hiblot 
453c10b85d6SJean-Jacques Hiblot 	/*
454c10b85d6SJean-Jacques Hiblot 	 * The card should drive cmd and dat[0:3] low immediately
455c10b85d6SJean-Jacques Hiblot 	 * after the response of cmd11, but wait 100 us to be sure
456c10b85d6SJean-Jacques Hiblot 	 */
457c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 0, 100);
458c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
459c10b85d6SJean-Jacques Hiblot 		udelay(100);
460c10b85d6SJean-Jacques Hiblot 	else if (err)
461c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
462c10b85d6SJean-Jacques Hiblot 
463c10b85d6SJean-Jacques Hiblot 	/*
464c10b85d6SJean-Jacques Hiblot 	 * During a signal voltage level switch, the clock must be gated
465c10b85d6SJean-Jacques Hiblot 	 * for 5 ms according to the SD spec
466c10b85d6SJean-Jacques Hiblot 	 */
467c10b85d6SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->clock, true);
468c10b85d6SJean-Jacques Hiblot 
469c10b85d6SJean-Jacques Hiblot 	err = mmc_set_signal_voltage(mmc, signal_voltage);
470c10b85d6SJean-Jacques Hiblot 	if (err)
471c10b85d6SJean-Jacques Hiblot 		return err;
472c10b85d6SJean-Jacques Hiblot 
473c10b85d6SJean-Jacques Hiblot 	/* Keep clock gated for at least 10 ms, though spec only says 5 ms */
474c10b85d6SJean-Jacques Hiblot 	mdelay(10);
475c10b85d6SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->clock, false);
476c10b85d6SJean-Jacques Hiblot 
477c10b85d6SJean-Jacques Hiblot 	/*
478c10b85d6SJean-Jacques Hiblot 	 * Failure to switch is indicated by the card holding
479c10b85d6SJean-Jacques Hiblot 	 * dat[0:3] low. Wait for at least 1 ms according to spec
480c10b85d6SJean-Jacques Hiblot 	 */
481c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 1, 1000);
482c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
483c10b85d6SJean-Jacques Hiblot 		udelay(1000);
484c10b85d6SJean-Jacques Hiblot 	else if (err)
485c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
486c10b85d6SJean-Jacques Hiblot 
487c10b85d6SJean-Jacques Hiblot 	return 0;
488c10b85d6SJean-Jacques Hiblot }
489c10b85d6SJean-Jacques Hiblot 
490c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en)
491272cc70bSAndy Fleming {
492272cc70bSAndy Fleming 	int timeout = 1000;
493272cc70bSAndy Fleming 	int err;
494272cc70bSAndy Fleming 	struct mmc_cmd cmd;
495272cc70bSAndy Fleming 
4961677eef4SAndrew Gabbasov 	while (1) {
497272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
498272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
499272cc70bSAndy Fleming 		cmd.cmdarg = 0;
500272cc70bSAndy Fleming 
501272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
502272cc70bSAndy Fleming 
503272cc70bSAndy Fleming 		if (err)
504272cc70bSAndy Fleming 			return err;
505272cc70bSAndy Fleming 
506272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
507272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
508250de12bSStefano Babic 
509250de12bSStefano Babic 		/*
510250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
511250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
512250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
513250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
514250de12bSStefano Babic 		 * specified.
515250de12bSStefano Babic 		 */
516d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
51793bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
518272cc70bSAndy Fleming 
519272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
520272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
521272cc70bSAndy Fleming 
522c10b85d6SJean-Jacques Hiblot 		if (uhs_en)
523c10b85d6SJean-Jacques Hiblot 			cmd.cmdarg |= OCR_S18R;
524c10b85d6SJean-Jacques Hiblot 
525272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
526272cc70bSAndy Fleming 
527272cc70bSAndy Fleming 		if (err)
528272cc70bSAndy Fleming 			return err;
529272cc70bSAndy Fleming 
5301677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
5311677eef4SAndrew Gabbasov 			break;
532272cc70bSAndy Fleming 
5331677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
534915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
535272cc70bSAndy Fleming 
5361677eef4SAndrew Gabbasov 		udelay(1000);
5371677eef4SAndrew Gabbasov 	}
5381677eef4SAndrew Gabbasov 
539272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
540272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
541272cc70bSAndy Fleming 
542d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
543d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
544d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
545d52ebf10SThomas Chou 		cmd.cmdarg = 0;
546d52ebf10SThomas Chou 
547d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
548d52ebf10SThomas Chou 
549d52ebf10SThomas Chou 		if (err)
550d52ebf10SThomas Chou 			return err;
551d52ebf10SThomas Chou 	}
552d52ebf10SThomas Chou 
553998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
554272cc70bSAndy Fleming 
555c10b85d6SJean-Jacques Hiblot 	if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000)
556c10b85d6SJean-Jacques Hiblot 	    == 0x41000000) {
557c10b85d6SJean-Jacques Hiblot 		err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
558c10b85d6SJean-Jacques Hiblot 		if (err)
559c10b85d6SJean-Jacques Hiblot 			return err;
560c10b85d6SJean-Jacques Hiblot 	}
561c10b85d6SJean-Jacques Hiblot 
562272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
563272cc70bSAndy Fleming 	mmc->rca = 0;
564272cc70bSAndy Fleming 
565272cc70bSAndy Fleming 	return 0;
566272cc70bSAndy Fleming }
567272cc70bSAndy Fleming 
5685289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
569272cc70bSAndy Fleming {
5705289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
571272cc70bSAndy Fleming 	int err;
572272cc70bSAndy Fleming 
5735289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
5745289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
5755289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
5765a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
5775a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
57893bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
579a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
580a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
581e9550449SChe-Liang Chiou 
5825289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
583e9550449SChe-Liang Chiou 	if (err)
584e9550449SChe-Liang Chiou 		return err;
5855289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
586e9550449SChe-Liang Chiou 	return 0;
587e9550449SChe-Liang Chiou }
588e9550449SChe-Liang Chiou 
589750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
590e9550449SChe-Liang Chiou {
591e9550449SChe-Liang Chiou 	int err, i;
592e9550449SChe-Liang Chiou 
593272cc70bSAndy Fleming 	/* Some cards seem to need this */
594272cc70bSAndy Fleming 	mmc_go_idle(mmc);
595272cc70bSAndy Fleming 
59631cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
597e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
5985289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
59931cacbabSRaffaele Recalcati 		if (err)
60031cacbabSRaffaele Recalcati 			return err;
60131cacbabSRaffaele Recalcati 
602e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
603a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
604bd47c135SAndrew Gabbasov 			break;
605e9550449SChe-Liang Chiou 	}
606bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
607bd47c135SAndrew Gabbasov 	return 0;
608e9550449SChe-Liang Chiou }
60931cacbabSRaffaele Recalcati 
610750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
611e9550449SChe-Liang Chiou {
612e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
613e9550449SChe-Liang Chiou 	int timeout = 1000;
614e9550449SChe-Liang Chiou 	uint start;
615e9550449SChe-Liang Chiou 	int err;
616e9550449SChe-Liang Chiou 
617e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
618cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
619d188b113SYangbo Lu 		/* Some cards seem to need this */
620d188b113SYangbo Lu 		mmc_go_idle(mmc);
621d188b113SYangbo Lu 
622e9550449SChe-Liang Chiou 		start = get_timer(0);
6231677eef4SAndrew Gabbasov 		while (1) {
6245289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
625272cc70bSAndy Fleming 			if (err)
626272cc70bSAndy Fleming 				return err;
6271677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
6281677eef4SAndrew Gabbasov 				break;
629e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
630915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
631e9550449SChe-Liang Chiou 			udelay(100);
6321677eef4SAndrew Gabbasov 		}
633cc17c01fSAndrew Gabbasov 	}
634272cc70bSAndy Fleming 
635d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
636d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
637d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
638d52ebf10SThomas Chou 		cmd.cmdarg = 0;
639d52ebf10SThomas Chou 
640d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
641d52ebf10SThomas Chou 
642d52ebf10SThomas Chou 		if (err)
643d52ebf10SThomas Chou 			return err;
644a626c8d4SAndrew Gabbasov 
645a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
646d52ebf10SThomas Chou 	}
647d52ebf10SThomas Chou 
648272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
649272cc70bSAndy Fleming 
650272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
651def816a2SStephen Warren 	mmc->rca = 1;
652272cc70bSAndy Fleming 
653272cc70bSAndy Fleming 	return 0;
654272cc70bSAndy Fleming }
655272cc70bSAndy Fleming 
656272cc70bSAndy Fleming 
657fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
658272cc70bSAndy Fleming {
659272cc70bSAndy Fleming 	struct mmc_cmd cmd;
660272cc70bSAndy Fleming 	struct mmc_data data;
661272cc70bSAndy Fleming 	int err;
662272cc70bSAndy Fleming 
663272cc70bSAndy Fleming 	/* Get the Card Status Register */
664272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
665272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
666272cc70bSAndy Fleming 	cmd.cmdarg = 0;
667272cc70bSAndy Fleming 
668cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
669272cc70bSAndy Fleming 	data.blocks = 1;
6708bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
671272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
672272cc70bSAndy Fleming 
673272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
674272cc70bSAndy Fleming 
675272cc70bSAndy Fleming 	return err;
676272cc70bSAndy Fleming }
677272cc70bSAndy Fleming 
678c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
679272cc70bSAndy Fleming {
680272cc70bSAndy Fleming 	struct mmc_cmd cmd;
6815d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
682a9003dc6SMaxime Ripard 	int retries = 3;
6835d4fc8d9SRaffaele Recalcati 	int ret;
684272cc70bSAndy Fleming 
685272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
686272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
687272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
688272cc70bSAndy Fleming 				 (index << 16) |
689272cc70bSAndy Fleming 				 (value << 8);
690272cc70bSAndy Fleming 
691a9003dc6SMaxime Ripard 	while (retries > 0) {
6925d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
6935d4fc8d9SRaffaele Recalcati 
6945d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
695a9003dc6SMaxime Ripard 		if (!ret) {
69693ad0d18SJan Kloetzke 			ret = mmc_send_status(mmc, timeout);
697a9003dc6SMaxime Ripard 			return ret;
698a9003dc6SMaxime Ripard 		}
699a9003dc6SMaxime Ripard 
700a9003dc6SMaxime Ripard 		retries--;
701a9003dc6SMaxime Ripard 	}
7025d4fc8d9SRaffaele Recalcati 
7035d4fc8d9SRaffaele Recalcati 	return ret;
7045d4fc8d9SRaffaele Recalcati 
705272cc70bSAndy Fleming }
706272cc70bSAndy Fleming 
7073862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
708272cc70bSAndy Fleming {
709272cc70bSAndy Fleming 	int err;
7103862b854SJean-Jacques Hiblot 	int speed_bits;
7113862b854SJean-Jacques Hiblot 
7123862b854SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
7133862b854SJean-Jacques Hiblot 
7143862b854SJean-Jacques Hiblot 	switch (mode) {
7153862b854SJean-Jacques Hiblot 	case MMC_HS:
7163862b854SJean-Jacques Hiblot 	case MMC_HS_52:
7173862b854SJean-Jacques Hiblot 	case MMC_DDR_52:
7183862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_HS;
719634d4849SKishon Vijay Abraham I 		break;
720634d4849SKishon Vijay Abraham I 	case MMC_HS_200:
721634d4849SKishon Vijay Abraham I 		speed_bits = EXT_CSD_TIMING_HS200;
722634d4849SKishon Vijay Abraham I 		break;
7233862b854SJean-Jacques Hiblot 	case MMC_LEGACY:
7243862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_LEGACY;
7253862b854SJean-Jacques Hiblot 		break;
7263862b854SJean-Jacques Hiblot 	default:
7273862b854SJean-Jacques Hiblot 		return -EINVAL;
7283862b854SJean-Jacques Hiblot 	}
7293862b854SJean-Jacques Hiblot 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
7303862b854SJean-Jacques Hiblot 			 speed_bits);
7313862b854SJean-Jacques Hiblot 	if (err)
7323862b854SJean-Jacques Hiblot 		return err;
7333862b854SJean-Jacques Hiblot 
7343862b854SJean-Jacques Hiblot 	if ((mode == MMC_HS) || (mode == MMC_HS_52)) {
7353862b854SJean-Jacques Hiblot 		/* Now check to see that it worked */
7363862b854SJean-Jacques Hiblot 		err = mmc_send_ext_csd(mmc, test_csd);
7373862b854SJean-Jacques Hiblot 		if (err)
7383862b854SJean-Jacques Hiblot 			return err;
7393862b854SJean-Jacques Hiblot 
7403862b854SJean-Jacques Hiblot 		/* No high-speed support */
7413862b854SJean-Jacques Hiblot 		if (!test_csd[EXT_CSD_HS_TIMING])
7423862b854SJean-Jacques Hiblot 			return -ENOTSUPP;
7433862b854SJean-Jacques Hiblot 	}
7443862b854SJean-Jacques Hiblot 
7453862b854SJean-Jacques Hiblot 	return 0;
7463862b854SJean-Jacques Hiblot }
7473862b854SJean-Jacques Hiblot 
7483862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc)
7493862b854SJean-Jacques Hiblot {
7503862b854SJean-Jacques Hiblot 	u8 *ext_csd = mmc->ext_csd;
7513862b854SJean-Jacques Hiblot 	char cardtype;
752272cc70bSAndy Fleming 
753d0c221feSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT;
754272cc70bSAndy Fleming 
755d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
756d52ebf10SThomas Chou 		return 0;
757d52ebf10SThomas Chou 
758272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
759272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
760272cc70bSAndy Fleming 		return 0;
761272cc70bSAndy Fleming 
7623862b854SJean-Jacques Hiblot 	if (!ext_csd) {
7633862b854SJean-Jacques Hiblot 		printf("No ext_csd found!\n"); /* this should enver happen */
7643862b854SJean-Jacques Hiblot 		return -ENOTSUPP;
7653862b854SJean-Jacques Hiblot 	}
7663862b854SJean-Jacques Hiblot 
767fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
768fc5b32fbSAndrew Gabbasov 
769634d4849SKishon Vijay Abraham I 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
770*bc1e3272SJean-Jacques Hiblot 	mmc->cardtype = cardtype;
771272cc70bSAndy Fleming 
772634d4849SKishon Vijay Abraham I 	if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
773634d4849SKishon Vijay Abraham I 			EXT_CSD_CARD_TYPE_HS200_1_8V)) {
774634d4849SKishon Vijay Abraham I 		mmc->card_caps |= MMC_MODE_HS200;
775634d4849SKishon Vijay Abraham I 	}
776d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
7773862b854SJean-Jacques Hiblot 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
778d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
7793862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS_52MHz;
780d22e3d46SJaehoon Chung 	}
7813862b854SJean-Jacques Hiblot 	if (cardtype & EXT_CSD_CARD_TYPE_26)
7823862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS;
783272cc70bSAndy Fleming 
784272cc70bSAndy Fleming 	return 0;
785272cc70bSAndy Fleming }
786272cc70bSAndy Fleming 
787f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
788f866a46dSStephen Warren {
789f866a46dSStephen Warren 	switch (part_num) {
790f866a46dSStephen Warren 	case 0:
791f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
792f866a46dSStephen Warren 		break;
793f866a46dSStephen Warren 	case 1:
794f866a46dSStephen Warren 	case 2:
795f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
796f866a46dSStephen Warren 		break;
797f866a46dSStephen Warren 	case 3:
798f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
799f866a46dSStephen Warren 		break;
800f866a46dSStephen Warren 	case 4:
801f866a46dSStephen Warren 	case 5:
802f866a46dSStephen Warren 	case 6:
803f866a46dSStephen Warren 	case 7:
804f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
805f866a46dSStephen Warren 		break;
806f866a46dSStephen Warren 	default:
807f866a46dSStephen Warren 		return -1;
808f866a46dSStephen Warren 	}
809f866a46dSStephen Warren 
810c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
811f866a46dSStephen Warren 
812f866a46dSStephen Warren 	return 0;
813f866a46dSStephen Warren }
814f866a46dSStephen Warren 
81501298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num)
81601298da3SJean-Jacques Hiblot {
81701298da3SJean-Jacques Hiblot 	int forbidden = 0;
81801298da3SJean-Jacques Hiblot 	bool change = false;
81901298da3SJean-Jacques Hiblot 
82001298da3SJean-Jacques Hiblot 	if (part_num & PART_ACCESS_MASK)
82101298da3SJean-Jacques Hiblot 		forbidden = MMC_CAP(MMC_HS_200);
82201298da3SJean-Jacques Hiblot 
82301298da3SJean-Jacques Hiblot 	if (MMC_CAP(mmc->selected_mode) & forbidden) {
82401298da3SJean-Jacques Hiblot 		debug("selected mode (%s) is forbidden for part %d\n",
82501298da3SJean-Jacques Hiblot 		      mmc_mode_name(mmc->selected_mode), part_num);
82601298da3SJean-Jacques Hiblot 		change = true;
82701298da3SJean-Jacques Hiblot 	} else if (mmc->selected_mode != mmc->best_mode) {
82801298da3SJean-Jacques Hiblot 		debug("selected mode is not optimal\n");
82901298da3SJean-Jacques Hiblot 		change = true;
83001298da3SJean-Jacques Hiblot 	}
83101298da3SJean-Jacques Hiblot 
83201298da3SJean-Jacques Hiblot 	if (change)
83301298da3SJean-Jacques Hiblot 		return mmc_select_mode_and_width(mmc,
83401298da3SJean-Jacques Hiblot 						 mmc->card_caps & ~forbidden);
83501298da3SJean-Jacques Hiblot 
83601298da3SJean-Jacques Hiblot 	return 0;
83701298da3SJean-Jacques Hiblot }
83801298da3SJean-Jacques Hiblot 
8397dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
840bc897b1dSLei Wen {
841f866a46dSStephen Warren 	int ret;
842bc897b1dSLei Wen 
84301298da3SJean-Jacques Hiblot 	ret = mmc_boot_part_access_chk(mmc, part_num);
84401298da3SJean-Jacques Hiblot 	if (ret)
84501298da3SJean-Jacques Hiblot 		return ret;
84601298da3SJean-Jacques Hiblot 
847f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
848bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
849bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
850f866a46dSStephen Warren 
8516dc93e70SPeter Bigot 	/*
8526dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
8536dc93e70SPeter Bigot 	 * to return to representing the raw device.
8546dc93e70SPeter Bigot 	 */
855873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
8566dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
857fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
858873cc1d7SStephen Warren 	}
8596dc93e70SPeter Bigot 
8606dc93e70SPeter Bigot 	return ret;
861bc897b1dSLei Wen }
862bc897b1dSLei Wen 
863ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
864ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
865ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
866ac9da0e0SDiego Santa Cruz {
867ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
868ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
869ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
870ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
871ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
872ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
8738dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
874ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
875ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
876ac9da0e0SDiego Santa Cruz 
877ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
878ac9da0e0SDiego Santa Cruz 		return -EINVAL;
879ac9da0e0SDiego Santa Cruz 
880ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
881ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
882ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
883ac9da0e0SDiego Santa Cruz 	}
884ac9da0e0SDiego Santa Cruz 
885ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
886ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
887ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
888ac9da0e0SDiego Santa Cruz 	}
889ac9da0e0SDiego Santa Cruz 
890ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
891ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
892ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
893ac9da0e0SDiego Santa Cruz 	}
894ac9da0e0SDiego Santa Cruz 
895ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
896ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
897ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
898ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
899ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
900ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
901ac9da0e0SDiego Santa Cruz 			return -EINVAL;
902ac9da0e0SDiego Santa Cruz 		}
903ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
904ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
905ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
906ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
907ac9da0e0SDiego Santa Cruz 		} else {
908ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
909ac9da0e0SDiego Santa Cruz 		}
910ac9da0e0SDiego Santa Cruz 	} else {
911ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
912ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
913ac9da0e0SDiego Santa Cruz 	}
914ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
915ac9da0e0SDiego Santa Cruz 
916ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
917ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
918ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
919ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
920ac9da0e0SDiego Santa Cruz 			return -EINVAL;
921ac9da0e0SDiego Santa Cruz 		}
922ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
923ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
924ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
925ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
926ac9da0e0SDiego Santa Cruz 		}
927ac9da0e0SDiego Santa Cruz 	}
928ac9da0e0SDiego Santa Cruz 
929ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
930ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
931ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
932ac9da0e0SDiego Santa Cruz 	}
933ac9da0e0SDiego Santa Cruz 
934ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
935ac9da0e0SDiego Santa Cruz 	if (err)
936ac9da0e0SDiego Santa Cruz 		return err;
937ac9da0e0SDiego Santa Cruz 
938ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
939ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
940ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
941ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
942ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
943ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
944ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
945ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
946ac9da0e0SDiego Santa Cruz 	}
947ac9da0e0SDiego Santa Cruz 
9488dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
9498dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
9508dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
9518dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
9528dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
9538dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
9548dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
9558dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
9568dda5b0eSDiego Santa Cruz 		else
9578dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
9588dda5b0eSDiego Santa Cruz 	}
9598dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
9608dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
9618dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
9628dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
9638dda5b0eSDiego Santa Cruz 			else
9648dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
9658dda5b0eSDiego Santa Cruz 		}
9668dda5b0eSDiego Santa Cruz 	}
9678dda5b0eSDiego Santa Cruz 
9688dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
9698dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
9708dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
9718dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
9728dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
9738dda5b0eSDiego Santa Cruz 	}
9748dda5b0eSDiego Santa Cruz 
975ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
976ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
977ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
978ac9da0e0SDiego Santa Cruz 		return -EPERM;
979ac9da0e0SDiego Santa Cruz 	}
980ac9da0e0SDiego Santa Cruz 
981ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
982ac9da0e0SDiego Santa Cruz 		return 0;
983ac9da0e0SDiego Santa Cruz 
984ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
985ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
986ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
987ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
988ac9da0e0SDiego Santa Cruz 
989ac9da0e0SDiego Santa Cruz 		if (err)
990ac9da0e0SDiego Santa Cruz 			return err;
991ac9da0e0SDiego Santa Cruz 
992ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
993ac9da0e0SDiego Santa Cruz 
994ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
995ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
996ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
997ac9da0e0SDiego Santa Cruz 
998ac9da0e0SDiego Santa Cruz 	}
999ac9da0e0SDiego Santa Cruz 
1000ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
1001ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
1002ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1003ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
1004ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
1005ac9da0e0SDiego Santa Cruz 		if (err)
1006ac9da0e0SDiego Santa Cruz 			return err;
1007ac9da0e0SDiego Santa Cruz 	}
1008ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
1009ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1010ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
1011ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
1012ac9da0e0SDiego Santa Cruz 		if (err)
1013ac9da0e0SDiego Santa Cruz 			return err;
1014ac9da0e0SDiego Santa Cruz 	}
1015ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1016ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
1017ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1018ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
1019ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
1020ac9da0e0SDiego Santa Cruz 			if (err)
1021ac9da0e0SDiego Santa Cruz 				return err;
1022ac9da0e0SDiego Santa Cruz 		}
1023ac9da0e0SDiego Santa Cruz 	}
1024ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1025ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
1026ac9da0e0SDiego Santa Cruz 	if (err)
1027ac9da0e0SDiego Santa Cruz 		return err;
1028ac9da0e0SDiego Santa Cruz 
1029ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
1030ac9da0e0SDiego Santa Cruz 		return 0;
1031ac9da0e0SDiego Santa Cruz 
10328dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
10338dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
10348dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
10358dda5b0eSDiego Santa Cruz 	 * partitioning. */
10368dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
10378dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
10388dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
10398dda5b0eSDiego Santa Cruz 		if (err)
10408dda5b0eSDiego Santa Cruz 			return err;
10418dda5b0eSDiego Santa Cruz 	}
10428dda5b0eSDiego Santa Cruz 
1043ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
1044ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
1045ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
1046ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
1047ac9da0e0SDiego Santa Cruz 
1048ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1049ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
1050ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
1051ac9da0e0SDiego Santa Cruz 	if (err)
1052ac9da0e0SDiego Santa Cruz 		return err;
1053ac9da0e0SDiego Santa Cruz 
1054ac9da0e0SDiego Santa Cruz 	return 0;
1055ac9da0e0SDiego Santa Cruz }
1056ac9da0e0SDiego Santa Cruz 
1057e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
105848972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
105948972d90SThierry Reding {
106048972d90SThierry Reding 	int cd;
106148972d90SThierry Reding 
106248972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
106348972d90SThierry Reding 
1064d4e1da4eSPeter Korsgaard 	if (cd < 0) {
106593bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
106693bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
1067d4e1da4eSPeter Korsgaard 		else
1068d4e1da4eSPeter Korsgaard 			cd = 1;
1069d4e1da4eSPeter Korsgaard 	}
107048972d90SThierry Reding 
107148972d90SThierry Reding 	return cd;
107248972d90SThierry Reding }
10738ca51e51SSimon Glass #endif
107448972d90SThierry Reding 
1075fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
1076272cc70bSAndy Fleming {
1077272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1078272cc70bSAndy Fleming 	struct mmc_data data;
1079272cc70bSAndy Fleming 
1080272cc70bSAndy Fleming 	/* Switch the frequency */
1081272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
1082272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1083272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
1084272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
1085272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
1086272cc70bSAndy Fleming 
1087272cc70bSAndy Fleming 	data.dest = (char *)resp;
1088272cc70bSAndy Fleming 	data.blocksize = 64;
1089272cc70bSAndy Fleming 	data.blocks = 1;
1090272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1091272cc70bSAndy Fleming 
1092272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
1093272cc70bSAndy Fleming }
1094272cc70bSAndy Fleming 
1095272cc70bSAndy Fleming 
1096d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc)
1097272cc70bSAndy Fleming {
1098272cc70bSAndy Fleming 	int err;
1099272cc70bSAndy Fleming 	struct mmc_cmd cmd;
110018e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
110118e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
1102272cc70bSAndy Fleming 	struct mmc_data data;
1103272cc70bSAndy Fleming 	int timeout;
1104c10b85d6SJean-Jacques Hiblot 	u32 sd3_bus_mode;
1105272cc70bSAndy Fleming 
1106d0c221feSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT;
1107272cc70bSAndy Fleming 
1108d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
1109d52ebf10SThomas Chou 		return 0;
1110d52ebf10SThomas Chou 
1111272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
1112272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
1113272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1114272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1115272cc70bSAndy Fleming 
1116272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1117272cc70bSAndy Fleming 
1118272cc70bSAndy Fleming 	if (err)
1119272cc70bSAndy Fleming 		return err;
1120272cc70bSAndy Fleming 
1121272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
1122272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1123272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1124272cc70bSAndy Fleming 
1125272cc70bSAndy Fleming 	timeout = 3;
1126272cc70bSAndy Fleming 
1127272cc70bSAndy Fleming retry_scr:
1128f781dd38SAnton staaf 	data.dest = (char *)scr;
1129272cc70bSAndy Fleming 	data.blocksize = 8;
1130272cc70bSAndy Fleming 	data.blocks = 1;
1131272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1132272cc70bSAndy Fleming 
1133272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
1134272cc70bSAndy Fleming 
1135272cc70bSAndy Fleming 	if (err) {
1136272cc70bSAndy Fleming 		if (timeout--)
1137272cc70bSAndy Fleming 			goto retry_scr;
1138272cc70bSAndy Fleming 
1139272cc70bSAndy Fleming 		return err;
1140272cc70bSAndy Fleming 	}
1141272cc70bSAndy Fleming 
11424e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
11434e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
1144272cc70bSAndy Fleming 
1145272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
1146272cc70bSAndy Fleming 	case 0:
1147272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1148272cc70bSAndy Fleming 		break;
1149272cc70bSAndy Fleming 	case 1:
1150272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
1151272cc70bSAndy Fleming 		break;
1152272cc70bSAndy Fleming 	case 2:
1153272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
11541741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
11551741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
1156272cc70bSAndy Fleming 		break;
1157272cc70bSAndy Fleming 	default:
1158272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1159272cc70bSAndy Fleming 		break;
1160272cc70bSAndy Fleming 	}
1161272cc70bSAndy Fleming 
1162b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1163b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1164b44c7083SAlagu Sankar 
1165272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1166272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1167272cc70bSAndy Fleming 		return 0;
1168272cc70bSAndy Fleming 
1169272cc70bSAndy Fleming 	timeout = 4;
1170272cc70bSAndy Fleming 	while (timeout--) {
1171272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1172f781dd38SAnton staaf 				(u8 *)switch_status);
1173272cc70bSAndy Fleming 
1174272cc70bSAndy Fleming 		if (err)
1175272cc70bSAndy Fleming 			return err;
1176272cc70bSAndy Fleming 
1177272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
11784e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1179272cc70bSAndy Fleming 			break;
1180272cc70bSAndy Fleming 	}
1181272cc70bSAndy Fleming 
1182272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
1183d0c221feSJean-Jacques Hiblot 	if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
1184d0c221feSJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(SD_HS);
1185272cc70bSAndy Fleming 
1186c10b85d6SJean-Jacques Hiblot 	/* Version before 3.0 don't support UHS modes */
1187c10b85d6SJean-Jacques Hiblot 	if (mmc->version < SD_VERSION_3)
1188c10b85d6SJean-Jacques Hiblot 		return 0;
1189c10b85d6SJean-Jacques Hiblot 
1190c10b85d6SJean-Jacques Hiblot 	sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f;
1191c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR104)
1192c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR104);
1193c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR50)
1194c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR50);
1195c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR25)
1196c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR25);
1197c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR12)
1198c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR12);
1199c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_DDR50)
1200c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_DDR50);
1201c10b85d6SJean-Jacques Hiblot 
12022c3fbf4cSMacpaul Lin 	return 0;
1203d0c221feSJean-Jacques Hiblot }
1204d0c221feSJean-Jacques Hiblot 
1205d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
1206d0c221feSJean-Jacques Hiblot {
1207d0c221feSJean-Jacques Hiblot 	int err;
1208d0c221feSJean-Jacques Hiblot 
1209d0c221feSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
1210c10b85d6SJean-Jacques Hiblot 	int speed;
12112c3fbf4cSMacpaul Lin 
1212c10b85d6SJean-Jacques Hiblot 	switch (mode) {
1213c10b85d6SJean-Jacques Hiblot 	case SD_LEGACY:
1214c10b85d6SJean-Jacques Hiblot 	case UHS_SDR12:
1215c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR12_BUS_SPEED;
1216c10b85d6SJean-Jacques Hiblot 		break;
1217c10b85d6SJean-Jacques Hiblot 	case SD_HS:
1218c10b85d6SJean-Jacques Hiblot 	case UHS_SDR25:
1219c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR25_BUS_SPEED;
1220c10b85d6SJean-Jacques Hiblot 		break;
1221c10b85d6SJean-Jacques Hiblot 	case UHS_SDR50:
1222c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR50_BUS_SPEED;
1223c10b85d6SJean-Jacques Hiblot 		break;
1224c10b85d6SJean-Jacques Hiblot 	case UHS_DDR50:
1225c10b85d6SJean-Jacques Hiblot 		speed = UHS_DDR50_BUS_SPEED;
1226c10b85d6SJean-Jacques Hiblot 		break;
1227c10b85d6SJean-Jacques Hiblot 	case UHS_SDR104:
1228c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR104_BUS_SPEED;
1229c10b85d6SJean-Jacques Hiblot 		break;
1230c10b85d6SJean-Jacques Hiblot 	default:
1231c10b85d6SJean-Jacques Hiblot 		return -EINVAL;
1232c10b85d6SJean-Jacques Hiblot 	}
1233c10b85d6SJean-Jacques Hiblot 
1234c10b85d6SJean-Jacques Hiblot 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status);
1235272cc70bSAndy Fleming 	if (err)
1236272cc70bSAndy Fleming 		return err;
1237272cc70bSAndy Fleming 
1238c10b85d6SJean-Jacques Hiblot 	if ((__be32_to_cpu(switch_status[4]) >> 24) != speed)
1239d0c221feSJean-Jacques Hiblot 		return -ENOTSUPP;
1240d0c221feSJean-Jacques Hiblot 
1241d0c221feSJean-Jacques Hiblot 	return 0;
1242d0c221feSJean-Jacques Hiblot }
1243d0c221feSJean-Jacques Hiblot 
1244d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w)
1245d0c221feSJean-Jacques Hiblot {
1246d0c221feSJean-Jacques Hiblot 	int err;
1247d0c221feSJean-Jacques Hiblot 	struct mmc_cmd cmd;
1248d0c221feSJean-Jacques Hiblot 
1249d0c221feSJean-Jacques Hiblot 	if ((w != 4) && (w != 1))
1250d0c221feSJean-Jacques Hiblot 		return -EINVAL;
1251d0c221feSJean-Jacques Hiblot 
1252d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = MMC_CMD_APP_CMD;
1253d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1254d0c221feSJean-Jacques Hiblot 	cmd.cmdarg = mmc->rca << 16;
1255d0c221feSJean-Jacques Hiblot 
1256d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1257d0c221feSJean-Jacques Hiblot 	if (err)
1258d0c221feSJean-Jacques Hiblot 		return err;
1259d0c221feSJean-Jacques Hiblot 
1260d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1261d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1262d0c221feSJean-Jacques Hiblot 	if (w == 4)
1263d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 2;
1264d0c221feSJean-Jacques Hiblot 	else if (w == 1)
1265d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 0;
1266d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1267d0c221feSJean-Jacques Hiblot 	if (err)
1268d0c221feSJean-Jacques Hiblot 		return err;
1269272cc70bSAndy Fleming 
1270272cc70bSAndy Fleming 	return 0;
1271272cc70bSAndy Fleming }
1272272cc70bSAndy Fleming 
12733697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
12743697e599SPeng Fan {
12753697e599SPeng Fan 	int err, i;
12763697e599SPeng Fan 	struct mmc_cmd cmd;
12773697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
12783697e599SPeng Fan 	struct mmc_data data;
12793697e599SPeng Fan 	int timeout = 3;
12803697e599SPeng Fan 	unsigned int au, eo, et, es;
12813697e599SPeng Fan 
12823697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
12833697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
12843697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
12853697e599SPeng Fan 
12863697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
12873697e599SPeng Fan 	if (err)
12883697e599SPeng Fan 		return err;
12893697e599SPeng Fan 
12903697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
12913697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
12923697e599SPeng Fan 	cmd.cmdarg = 0;
12933697e599SPeng Fan 
12943697e599SPeng Fan retry_ssr:
12953697e599SPeng Fan 	data.dest = (char *)ssr;
12963697e599SPeng Fan 	data.blocksize = 64;
12973697e599SPeng Fan 	data.blocks = 1;
12983697e599SPeng Fan 	data.flags = MMC_DATA_READ;
12993697e599SPeng Fan 
13003697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
13013697e599SPeng Fan 	if (err) {
13023697e599SPeng Fan 		if (timeout--)
13033697e599SPeng Fan 			goto retry_ssr;
13043697e599SPeng Fan 
13053697e599SPeng Fan 		return err;
13063697e599SPeng Fan 	}
13073697e599SPeng Fan 
13083697e599SPeng Fan 	for (i = 0; i < 16; i++)
13093697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
13103697e599SPeng Fan 
13113697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
13123697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
13133697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
13143697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
13153697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
13163697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
13173697e599SPeng Fan 		if (es && et) {
13183697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
13193697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
13203697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
13213697e599SPeng Fan 		}
13223697e599SPeng Fan 	} else {
13233697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
13243697e599SPeng Fan 	}
13253697e599SPeng Fan 
13263697e599SPeng Fan 	return 0;
13273697e599SPeng Fan }
13283697e599SPeng Fan 
1329272cc70bSAndy Fleming /* frequency bases */
1330272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
13315f837c2cSMike Frysinger static const int fbase[] = {
1332272cc70bSAndy Fleming 	10000,
1333272cc70bSAndy Fleming 	100000,
1334272cc70bSAndy Fleming 	1000000,
1335272cc70bSAndy Fleming 	10000000,
1336272cc70bSAndy Fleming };
1337272cc70bSAndy Fleming 
1338272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1339272cc70bSAndy Fleming  * to platforms without floating point.
1340272cc70bSAndy Fleming  */
134161fe076fSSimon Glass static const u8 multipliers[] = {
1342272cc70bSAndy Fleming 	0,	/* reserved */
1343272cc70bSAndy Fleming 	10,
1344272cc70bSAndy Fleming 	12,
1345272cc70bSAndy Fleming 	13,
1346272cc70bSAndy Fleming 	15,
1347272cc70bSAndy Fleming 	20,
1348272cc70bSAndy Fleming 	25,
1349272cc70bSAndy Fleming 	30,
1350272cc70bSAndy Fleming 	35,
1351272cc70bSAndy Fleming 	40,
1352272cc70bSAndy Fleming 	45,
1353272cc70bSAndy Fleming 	50,
1354272cc70bSAndy Fleming 	55,
1355272cc70bSAndy Fleming 	60,
1356272cc70bSAndy Fleming 	70,
1357272cc70bSAndy Fleming 	80,
1358272cc70bSAndy Fleming };
1359272cc70bSAndy Fleming 
1360d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap)
1361d0c221feSJean-Jacques Hiblot {
1362d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_8BIT)
1363d0c221feSJean-Jacques Hiblot 		return 8;
1364d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_4BIT)
1365d0c221feSJean-Jacques Hiblot 		return 4;
1366d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_1BIT)
1367d0c221feSJean-Jacques Hiblot 		return 1;
1368d0c221feSJean-Jacques Hiblot 	printf("invalid bus witdh capability 0x%x\n", cap);
1369d0c221feSJean-Jacques Hiblot 	return 0;
1370d0c221feSJean-Jacques Hiblot }
1371d0c221feSJean-Jacques Hiblot 
1372e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1373ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode)
1374ec841209SKishon Vijay Abraham I {
1375ec841209SKishon Vijay Abraham I 	return -ENOTSUPP;
1376ec841209SKishon Vijay Abraham I }
1377ec841209SKishon Vijay Abraham I 
1378318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc)
1379318a7a57SJean-Jacques Hiblot {
1380318a7a57SJean-Jacques Hiblot }
1381318a7a57SJean-Jacques Hiblot 
13822a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc)
1383272cc70bSAndy Fleming {
13842a4d212fSKishon Vijay Abraham I 	int ret = 0;
13852a4d212fSKishon Vijay Abraham I 
138693bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
13872a4d212fSKishon Vijay Abraham I 		ret = mmc->cfg->ops->set_ios(mmc);
13882a4d212fSKishon Vijay Abraham I 
13892a4d212fSKishon Vijay Abraham I 	return ret;
1390272cc70bSAndy Fleming }
13918ca51e51SSimon Glass #endif
1392272cc70bSAndy Fleming 
139335f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable)
1394272cc70bSAndy Fleming {
139593bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
139693bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1397272cc70bSAndy Fleming 
139893bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
139993bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1400272cc70bSAndy Fleming 
1401272cc70bSAndy Fleming 	mmc->clock = clock;
140235f67820SKishon Vijay Abraham I 	mmc->clk_disable = disable;
1403272cc70bSAndy Fleming 
14042a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1405272cc70bSAndy Fleming }
1406272cc70bSAndy Fleming 
14072a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width)
1408272cc70bSAndy Fleming {
1409272cc70bSAndy Fleming 	mmc->bus_width = width;
1410272cc70bSAndy Fleming 
14112a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1412272cc70bSAndy Fleming }
1413272cc70bSAndy Fleming 
14144c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
14154c9d2aaaSJean-Jacques Hiblot /*
14164c9d2aaaSJean-Jacques Hiblot  * helper function to display the capabilities in a human
14174c9d2aaaSJean-Jacques Hiblot  * friendly manner. The capabilities include bus width and
14184c9d2aaaSJean-Jacques Hiblot  * supported modes.
14194c9d2aaaSJean-Jacques Hiblot  */
14204c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps)
14214c9d2aaaSJean-Jacques Hiblot {
14224c9d2aaaSJean-Jacques Hiblot 	enum bus_mode mode;
14234c9d2aaaSJean-Jacques Hiblot 
14244c9d2aaaSJean-Jacques Hiblot 	printf("%s: widths [", text);
14254c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_8BIT)
14264c9d2aaaSJean-Jacques Hiblot 		printf("8, ");
14274c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_4BIT)
14284c9d2aaaSJean-Jacques Hiblot 		printf("4, ");
1429d0c221feSJean-Jacques Hiblot 	if (caps & MMC_MODE_1BIT)
1430d0c221feSJean-Jacques Hiblot 		printf("1, ");
1431d0c221feSJean-Jacques Hiblot 	printf("\b\b] modes [");
14324c9d2aaaSJean-Jacques Hiblot 	for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
14334c9d2aaaSJean-Jacques Hiblot 		if (MMC_CAP(mode) & caps)
14344c9d2aaaSJean-Jacques Hiblot 			printf("%s, ", mmc_mode_name(mode));
14354c9d2aaaSJean-Jacques Hiblot 	printf("\b\b]\n");
14364c9d2aaaSJean-Jacques Hiblot }
14374c9d2aaaSJean-Jacques Hiblot #endif
14384c9d2aaaSJean-Jacques Hiblot 
1439d0c221feSJean-Jacques Hiblot struct mode_width_tuning {
1440d0c221feSJean-Jacques Hiblot 	enum bus_mode mode;
1441d0c221feSJean-Jacques Hiblot 	uint widths;
1442634d4849SKishon Vijay Abraham I 	uint tuning;
1443d0c221feSJean-Jacques Hiblot };
1444d0c221feSJean-Jacques Hiblot 
1445*bc1e3272SJean-Jacques Hiblot int mmc_voltage_to_mv(enum mmc_voltage voltage)
1446*bc1e3272SJean-Jacques Hiblot {
1447*bc1e3272SJean-Jacques Hiblot 	switch (voltage) {
1448*bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_000: return 0;
1449*bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_330: return 3300;
1450*bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_180: return 1800;
1451*bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_120: return 1200;
1452*bc1e3272SJean-Jacques Hiblot 	}
1453*bc1e3272SJean-Jacques Hiblot 	return -EINVAL;
1454*bc1e3272SJean-Jacques Hiblot }
1455*bc1e3272SJean-Jacques Hiblot 
1456aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1457aff5d3c8SKishon Vijay Abraham I {
1458*bc1e3272SJean-Jacques Hiblot 	int err;
1459*bc1e3272SJean-Jacques Hiblot 
1460*bc1e3272SJean-Jacques Hiblot 	if (mmc->signal_voltage == signal_voltage)
1461*bc1e3272SJean-Jacques Hiblot 		return 0;
1462*bc1e3272SJean-Jacques Hiblot 
1463aff5d3c8SKishon Vijay Abraham I 	mmc->signal_voltage = signal_voltage;
1464*bc1e3272SJean-Jacques Hiblot 	err = mmc_set_ios(mmc);
1465*bc1e3272SJean-Jacques Hiblot 	if (err)
1466*bc1e3272SJean-Jacques Hiblot 		debug("unable to set voltage (err %d)\n", err);
1467*bc1e3272SJean-Jacques Hiblot 
1468*bc1e3272SJean-Jacques Hiblot 	return err;
1469aff5d3c8SKishon Vijay Abraham I }
1470aff5d3c8SKishon Vijay Abraham I 
1471d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = {
1472d0c221feSJean-Jacques Hiblot 	{
1473c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR104,
1474c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1475c10b85d6SJean-Jacques Hiblot 		.tuning = MMC_CMD_SEND_TUNING_BLOCK
1476c10b85d6SJean-Jacques Hiblot 	},
1477c10b85d6SJean-Jacques Hiblot 	{
1478c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR50,
1479c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1480c10b85d6SJean-Jacques Hiblot 	},
1481c10b85d6SJean-Jacques Hiblot 	{
1482c10b85d6SJean-Jacques Hiblot 		.mode = UHS_DDR50,
1483c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1484c10b85d6SJean-Jacques Hiblot 	},
1485c10b85d6SJean-Jacques Hiblot 	{
1486c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR25,
1487c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1488c10b85d6SJean-Jacques Hiblot 	},
1489c10b85d6SJean-Jacques Hiblot 	{
1490d0c221feSJean-Jacques Hiblot 		.mode = SD_HS,
1491d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1492d0c221feSJean-Jacques Hiblot 	},
1493d0c221feSJean-Jacques Hiblot 	{
1494c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR12,
1495c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1496c10b85d6SJean-Jacques Hiblot 	},
1497c10b85d6SJean-Jacques Hiblot 	{
1498d0c221feSJean-Jacques Hiblot 		.mode = SD_LEGACY,
1499d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1500d0c221feSJean-Jacques Hiblot 	}
1501d0c221feSJean-Jacques Hiblot };
1502d0c221feSJean-Jacques Hiblot 
1503d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \
1504d0c221feSJean-Jacques Hiblot 	for (mwt = sd_modes_by_pref;\
1505d0c221feSJean-Jacques Hiblot 	     mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\
1506d0c221feSJean-Jacques Hiblot 	     mwt++) \
1507d0c221feSJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
1508d0c221feSJean-Jacques Hiblot 
150901298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
15108ac8a263SJean-Jacques Hiblot {
15118ac8a263SJean-Jacques Hiblot 	int err;
1512d0c221feSJean-Jacques Hiblot 	uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
1513d0c221feSJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
1514c10b85d6SJean-Jacques Hiblot 	bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false;
1515c10b85d6SJean-Jacques Hiblot 	uint caps;
1516c10b85d6SJean-Jacques Hiblot 
15178ac8a263SJean-Jacques Hiblot 
15188ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
151901298da3SJean-Jacques Hiblot 	caps = card_caps & (mmc->host_caps | MMC_MODE_1BIT);
15208ac8a263SJean-Jacques Hiblot 
1521c10b85d6SJean-Jacques Hiblot 	if (!uhs_en)
1522c10b85d6SJean-Jacques Hiblot 		caps &= ~UHS_CAPS;
1523c10b85d6SJean-Jacques Hiblot 
1524c10b85d6SJean-Jacques Hiblot 	for_each_sd_mode_by_pref(caps, mwt) {
1525d0c221feSJean-Jacques Hiblot 		uint *w;
15268ac8a263SJean-Jacques Hiblot 
1527d0c221feSJean-Jacques Hiblot 		for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
1528c10b85d6SJean-Jacques Hiblot 			if (*w & caps & mwt->widths) {
1529d0c221feSJean-Jacques Hiblot 				debug("trying mode %s width %d (at %d MHz)\n",
1530d0c221feSJean-Jacques Hiblot 				      mmc_mode_name(mwt->mode),
1531d0c221feSJean-Jacques Hiblot 				      bus_width(*w),
1532d0c221feSJean-Jacques Hiblot 				      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1533d0c221feSJean-Jacques Hiblot 
1534d0c221feSJean-Jacques Hiblot 				/* configure the bus width (card + host) */
1535d0c221feSJean-Jacques Hiblot 				err = sd_select_bus_width(mmc, bus_width(*w));
15368ac8a263SJean-Jacques Hiblot 				if (err)
1537d0c221feSJean-Jacques Hiblot 					goto error;
1538d0c221feSJean-Jacques Hiblot 				mmc_set_bus_width(mmc, bus_width(*w));
15398ac8a263SJean-Jacques Hiblot 
1540d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (card) */
1541d0c221feSJean-Jacques Hiblot 				err = sd_set_card_speed(mmc, mwt->mode);
15428ac8a263SJean-Jacques Hiblot 				if (err)
1543d0c221feSJean-Jacques Hiblot 					goto error;
15448ac8a263SJean-Jacques Hiblot 
1545d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (host) */
1546d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, mwt->mode);
154735f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
15488ac8a263SJean-Jacques Hiblot 
1549c10b85d6SJean-Jacques Hiblot 				/* execute tuning if needed */
1550c10b85d6SJean-Jacques Hiblot 				if (mwt->tuning && !mmc_host_is_spi(mmc)) {
1551c10b85d6SJean-Jacques Hiblot 					err = mmc_execute_tuning(mmc,
1552c10b85d6SJean-Jacques Hiblot 								 mwt->tuning);
1553c10b85d6SJean-Jacques Hiblot 					if (err) {
1554c10b85d6SJean-Jacques Hiblot 						debug("tuning failed\n");
1555c10b85d6SJean-Jacques Hiblot 						goto error;
1556c10b85d6SJean-Jacques Hiblot 					}
1557c10b85d6SJean-Jacques Hiblot 				}
1558c10b85d6SJean-Jacques Hiblot 
15598ac8a263SJean-Jacques Hiblot 				err = sd_read_ssr(mmc);
1560d0c221feSJean-Jacques Hiblot 				if (!err)
15618ac8a263SJean-Jacques Hiblot 					return 0;
1562d0c221feSJean-Jacques Hiblot 
1563d0c221feSJean-Jacques Hiblot 				printf("bad ssr\n");
1564d0c221feSJean-Jacques Hiblot 
1565d0c221feSJean-Jacques Hiblot error:
1566d0c221feSJean-Jacques Hiblot 				/* revert to a safer bus speed */
1567d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, SD_LEGACY);
156835f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
1569d0c221feSJean-Jacques Hiblot 			}
1570d0c221feSJean-Jacques Hiblot 		}
1571d0c221feSJean-Jacques Hiblot 	}
1572d0c221feSJean-Jacques Hiblot 
1573d0c221feSJean-Jacques Hiblot 	printf("unable to select a mode\n");
1574d0c221feSJean-Jacques Hiblot 	return -ENOTSUPP;
15758ac8a263SJean-Jacques Hiblot }
15768ac8a263SJean-Jacques Hiblot 
15777382e691SJean-Jacques Hiblot /*
15787382e691SJean-Jacques Hiblot  * read the compare the part of ext csd that is constant.
15797382e691SJean-Jacques Hiblot  * This can be used to check that the transfer is working
15807382e691SJean-Jacques Hiblot  * as expected.
15817382e691SJean-Jacques Hiblot  */
15827382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
15837382e691SJean-Jacques Hiblot {
15847382e691SJean-Jacques Hiblot 	int err;
15857382e691SJean-Jacques Hiblot 	const u8 *ext_csd = mmc->ext_csd;
15867382e691SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
15877382e691SJean-Jacques Hiblot 
15887382e691SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, test_csd);
15897382e691SJean-Jacques Hiblot 	if (err)
15907382e691SJean-Jacques Hiblot 		return err;
15917382e691SJean-Jacques Hiblot 
15927382e691SJean-Jacques Hiblot 	/* Only compare read only fields */
15937382e691SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
15947382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
15957382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
15967382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
15977382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_REV]
15987382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_REV] &&
15997382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
16007382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
16017382e691SJean-Jacques Hiblot 	    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
16027382e691SJean-Jacques Hiblot 		   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
16037382e691SJean-Jacques Hiblot 		return 0;
16047382e691SJean-Jacques Hiblot 
16057382e691SJean-Jacques Hiblot 	return -EBADMSG;
16067382e691SJean-Jacques Hiblot }
16077382e691SJean-Jacques Hiblot 
1608*bc1e3272SJean-Jacques Hiblot static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
1609*bc1e3272SJean-Jacques Hiblot 				  uint32_t allowed_mask)
1610*bc1e3272SJean-Jacques Hiblot {
1611*bc1e3272SJean-Jacques Hiblot 	u32 card_mask = 0;
1612*bc1e3272SJean-Jacques Hiblot 
1613*bc1e3272SJean-Jacques Hiblot 	switch (mode) {
1614*bc1e3272SJean-Jacques Hiblot 	case MMC_HS_200:
1615*bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
1616*bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_180;
1617*bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V)
1618*bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_120;
1619*bc1e3272SJean-Jacques Hiblot 		break;
1620*bc1e3272SJean-Jacques Hiblot 	case MMC_DDR_52:
1621*bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
1622*bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_330 |
1623*bc1e3272SJean-Jacques Hiblot 				     MMC_SIGNAL_VOLTAGE_180;
1624*bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V)
1625*bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_120;
1626*bc1e3272SJean-Jacques Hiblot 		break;
1627*bc1e3272SJean-Jacques Hiblot 	default:
1628*bc1e3272SJean-Jacques Hiblot 		card_mask |= MMC_SIGNAL_VOLTAGE_330;
1629*bc1e3272SJean-Jacques Hiblot 		break;
1630*bc1e3272SJean-Jacques Hiblot 	}
1631*bc1e3272SJean-Jacques Hiblot 
1632*bc1e3272SJean-Jacques Hiblot 	while (card_mask & allowed_mask) {
1633*bc1e3272SJean-Jacques Hiblot 		enum mmc_voltage best_match;
1634*bc1e3272SJean-Jacques Hiblot 
1635*bc1e3272SJean-Jacques Hiblot 		best_match = 1 << (ffs(card_mask & allowed_mask) - 1);
1636*bc1e3272SJean-Jacques Hiblot 		if (!mmc_set_signal_voltage(mmc,  best_match))
1637*bc1e3272SJean-Jacques Hiblot 			return 0;
1638*bc1e3272SJean-Jacques Hiblot 
1639*bc1e3272SJean-Jacques Hiblot 		allowed_mask &= ~best_match;
1640*bc1e3272SJean-Jacques Hiblot 	}
1641*bc1e3272SJean-Jacques Hiblot 
1642*bc1e3272SJean-Jacques Hiblot 	return -ENOTSUPP;
1643*bc1e3272SJean-Jacques Hiblot }
1644*bc1e3272SJean-Jacques Hiblot 
16453862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = {
16468ac8a263SJean-Jacques Hiblot 	{
16473862b854SJean-Jacques Hiblot 		.mode = MMC_HS_200,
16483862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
1649634d4849SKishon Vijay Abraham I 		.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
16503862b854SJean-Jacques Hiblot 	},
16513862b854SJean-Jacques Hiblot 	{
16523862b854SJean-Jacques Hiblot 		.mode = MMC_DDR_52,
16533862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
16543862b854SJean-Jacques Hiblot 	},
16553862b854SJean-Jacques Hiblot 	{
16563862b854SJean-Jacques Hiblot 		.mode = MMC_HS_52,
16573862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
16583862b854SJean-Jacques Hiblot 	},
16593862b854SJean-Jacques Hiblot 	{
16603862b854SJean-Jacques Hiblot 		.mode = MMC_HS,
16613862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
16623862b854SJean-Jacques Hiblot 	},
16633862b854SJean-Jacques Hiblot 	{
16643862b854SJean-Jacques Hiblot 		.mode = MMC_LEGACY,
16653862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
16663862b854SJean-Jacques Hiblot 	}
16678ac8a263SJean-Jacques Hiblot };
16688ac8a263SJean-Jacques Hiblot 
16693862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \
16703862b854SJean-Jacques Hiblot 	for (mwt = mmc_modes_by_pref;\
16713862b854SJean-Jacques Hiblot 	    mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\
16723862b854SJean-Jacques Hiblot 	    mwt++) \
16733862b854SJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
16743862b854SJean-Jacques Hiblot 
16753862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width {
16763862b854SJean-Jacques Hiblot 	uint cap;
16773862b854SJean-Jacques Hiblot 	bool is_ddr;
16783862b854SJean-Jacques Hiblot 	uint ext_csd_bits;
16793862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = {
16803862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8},
16813862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4},
16823862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8},
16833862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4},
16843862b854SJean-Jacques Hiblot 	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
16853862b854SJean-Jacques Hiblot };
16863862b854SJean-Jacques Hiblot 
16873862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \
16883862b854SJean-Jacques Hiblot 	for (ecbv = ext_csd_bus_width;\
16893862b854SJean-Jacques Hiblot 	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
16903862b854SJean-Jacques Hiblot 	    ecbv++) \
16913862b854SJean-Jacques Hiblot 		if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
16923862b854SJean-Jacques Hiblot 
169301298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
16943862b854SJean-Jacques Hiblot {
16953862b854SJean-Jacques Hiblot 	int err;
16963862b854SJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
16973862b854SJean-Jacques Hiblot 	const struct ext_csd_bus_width *ecbw;
16983862b854SJean-Jacques Hiblot 
16998ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
170001298da3SJean-Jacques Hiblot 	card_caps &= (mmc->host_caps | MMC_MODE_1BIT);
17018ac8a263SJean-Jacques Hiblot 
17028ac8a263SJean-Jacques Hiblot 	/* Only version 4 of MMC supports wider bus widths */
17038ac8a263SJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
17048ac8a263SJean-Jacques Hiblot 		return 0;
17058ac8a263SJean-Jacques Hiblot 
1706dfda9d88SJean-Jacques Hiblot 	if (!mmc->ext_csd) {
1707dfda9d88SJean-Jacques Hiblot 		debug("No ext_csd found!\n"); /* this should enver happen */
1708dfda9d88SJean-Jacques Hiblot 		return -ENOTSUPP;
1709dfda9d88SJean-Jacques Hiblot 	}
1710dfda9d88SJean-Jacques Hiblot 
171101298da3SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->legacy_speed, false);
171201298da3SJean-Jacques Hiblot 
171301298da3SJean-Jacques Hiblot 	for_each_mmc_mode_by_pref(card_caps, mwt) {
171401298da3SJean-Jacques Hiblot 		for_each_supported_width(card_caps & mwt->widths,
17153862b854SJean-Jacques Hiblot 					 mmc_is_mode_ddr(mwt->mode), ecbw) {
1716*bc1e3272SJean-Jacques Hiblot 			enum mmc_voltage old_voltage;
17173862b854SJean-Jacques Hiblot 			debug("trying mode %s width %d (at %d MHz)\n",
17183862b854SJean-Jacques Hiblot 			      mmc_mode_name(mwt->mode),
17193862b854SJean-Jacques Hiblot 			      bus_width(ecbw->cap),
17203862b854SJean-Jacques Hiblot 			      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1721*bc1e3272SJean-Jacques Hiblot 			old_voltage = mmc->signal_voltage;
1722*bc1e3272SJean-Jacques Hiblot 			err = mmc_set_lowest_voltage(mmc, mwt->mode,
1723*bc1e3272SJean-Jacques Hiblot 						     MMC_ALL_SIGNAL_VOLTAGE);
1724*bc1e3272SJean-Jacques Hiblot 			if (err)
1725*bc1e3272SJean-Jacques Hiblot 				continue;
1726*bc1e3272SJean-Jacques Hiblot 
17273862b854SJean-Jacques Hiblot 			/* configure the bus width (card + host) */
17283862b854SJean-Jacques Hiblot 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
17293862b854SJean-Jacques Hiblot 				    EXT_CSD_BUS_WIDTH,
17303862b854SJean-Jacques Hiblot 				    ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG);
17313862b854SJean-Jacques Hiblot 			if (err)
17323862b854SJean-Jacques Hiblot 				goto error;
17333862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
17343862b854SJean-Jacques Hiblot 
17353862b854SJean-Jacques Hiblot 			/* configure the bus speed (card) */
17363862b854SJean-Jacques Hiblot 			err = mmc_set_card_speed(mmc, mwt->mode);
17373862b854SJean-Jacques Hiblot 			if (err)
17383862b854SJean-Jacques Hiblot 				goto error;
17393862b854SJean-Jacques Hiblot 
17408ac8a263SJean-Jacques Hiblot 			/*
17413862b854SJean-Jacques Hiblot 			 * configure the bus width AND the ddr mode (card)
17423862b854SJean-Jacques Hiblot 			 * The host side will be taken care of in the next step
17438ac8a263SJean-Jacques Hiblot 			 */
17443862b854SJean-Jacques Hiblot 			if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
17453862b854SJean-Jacques Hiblot 				err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
17463862b854SJean-Jacques Hiblot 						 EXT_CSD_BUS_WIDTH,
17473862b854SJean-Jacques Hiblot 						 ecbw->ext_csd_bits);
17483862b854SJean-Jacques Hiblot 				if (err)
17493862b854SJean-Jacques Hiblot 					goto error;
17508ac8a263SJean-Jacques Hiblot 			}
17518ac8a263SJean-Jacques Hiblot 
17523862b854SJean-Jacques Hiblot 			/* configure the bus mode (host) */
17533862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, mwt->mode);
175435f67820SKishon Vijay Abraham I 			mmc_set_clock(mmc, mmc->tran_speed, false);
17558ac8a263SJean-Jacques Hiblot 
1756634d4849SKishon Vijay Abraham I 			/* execute tuning if needed */
1757634d4849SKishon Vijay Abraham I 			if (mwt->tuning) {
1758634d4849SKishon Vijay Abraham I 				err = mmc_execute_tuning(mmc, mwt->tuning);
1759634d4849SKishon Vijay Abraham I 				if (err) {
1760634d4849SKishon Vijay Abraham I 					debug("tuning failed\n");
1761634d4849SKishon Vijay Abraham I 					goto error;
1762634d4849SKishon Vijay Abraham I 				}
1763634d4849SKishon Vijay Abraham I 			}
1764634d4849SKishon Vijay Abraham I 
17653862b854SJean-Jacques Hiblot 			/* do a transfer to check the configuration */
17667382e691SJean-Jacques Hiblot 			err = mmc_read_and_compare_ext_csd(mmc);
17677382e691SJean-Jacques Hiblot 			if (!err)
17683862b854SJean-Jacques Hiblot 				return 0;
17693862b854SJean-Jacques Hiblot error:
1770*bc1e3272SJean-Jacques Hiblot 			mmc_set_signal_voltage(mmc, old_voltage);
17713862b854SJean-Jacques Hiblot 			/* if an error occured, revert to a safer bus mode */
17723862b854SJean-Jacques Hiblot 			mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
17733862b854SJean-Jacques Hiblot 				   EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
17743862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_LEGACY);
17753862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, 1);
17763862b854SJean-Jacques Hiblot 		}
17778ac8a263SJean-Jacques Hiblot 	}
17788ac8a263SJean-Jacques Hiblot 
17793862b854SJean-Jacques Hiblot 	printf("unable to select a mode\n");
17808ac8a263SJean-Jacques Hiblot 
17813862b854SJean-Jacques Hiblot 	return -ENOTSUPP;
17828ac8a263SJean-Jacques Hiblot }
17838ac8a263SJean-Jacques Hiblot 
1784dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
1785c744b6f6SJean-Jacques Hiblot {
1786c744b6f6SJean-Jacques Hiblot 	int err, i;
1787c744b6f6SJean-Jacques Hiblot 	u64 capacity;
1788c744b6f6SJean-Jacques Hiblot 	bool has_parts = false;
1789c744b6f6SJean-Jacques Hiblot 	bool part_completed;
1790dfda9d88SJean-Jacques Hiblot 	u8 *ext_csd;
1791c744b6f6SJean-Jacques Hiblot 
1792c744b6f6SJean-Jacques Hiblot 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
1793c744b6f6SJean-Jacques Hiblot 		return 0;
1794c744b6f6SJean-Jacques Hiblot 
1795dfda9d88SJean-Jacques Hiblot 	ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN);
1796dfda9d88SJean-Jacques Hiblot 	if (!ext_csd)
1797dfda9d88SJean-Jacques Hiblot 		return -ENOMEM;
1798dfda9d88SJean-Jacques Hiblot 
1799dfda9d88SJean-Jacques Hiblot 	mmc->ext_csd = ext_csd;
1800dfda9d88SJean-Jacques Hiblot 
1801c744b6f6SJean-Jacques Hiblot 	/* check  ext_csd version and capacity */
1802c744b6f6SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, ext_csd);
1803c744b6f6SJean-Jacques Hiblot 	if (err)
1804c744b6f6SJean-Jacques Hiblot 		return err;
1805c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_REV] >= 2) {
1806c744b6f6SJean-Jacques Hiblot 		/*
1807c744b6f6SJean-Jacques Hiblot 		 * According to the JEDEC Standard, the value of
1808c744b6f6SJean-Jacques Hiblot 		 * ext_csd's capacity is valid if the value is more
1809c744b6f6SJean-Jacques Hiblot 		 * than 2GB
1810c744b6f6SJean-Jacques Hiblot 		 */
1811c744b6f6SJean-Jacques Hiblot 		capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
1812c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
1813c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
1814c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1815c744b6f6SJean-Jacques Hiblot 		capacity *= MMC_MAX_BLOCK_LEN;
1816c744b6f6SJean-Jacques Hiblot 		if ((capacity >> 20) > 2 * 1024)
1817c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1818c744b6f6SJean-Jacques Hiblot 	}
1819c744b6f6SJean-Jacques Hiblot 
1820c744b6f6SJean-Jacques Hiblot 	switch (ext_csd[EXT_CSD_REV]) {
1821c744b6f6SJean-Jacques Hiblot 	case 1:
1822c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_1;
1823c744b6f6SJean-Jacques Hiblot 		break;
1824c744b6f6SJean-Jacques Hiblot 	case 2:
1825c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_2;
1826c744b6f6SJean-Jacques Hiblot 		break;
1827c744b6f6SJean-Jacques Hiblot 	case 3:
1828c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_3;
1829c744b6f6SJean-Jacques Hiblot 		break;
1830c744b6f6SJean-Jacques Hiblot 	case 5:
1831c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_41;
1832c744b6f6SJean-Jacques Hiblot 		break;
1833c744b6f6SJean-Jacques Hiblot 	case 6:
1834c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_5;
1835c744b6f6SJean-Jacques Hiblot 		break;
1836c744b6f6SJean-Jacques Hiblot 	case 7:
1837c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_0;
1838c744b6f6SJean-Jacques Hiblot 		break;
1839c744b6f6SJean-Jacques Hiblot 	case 8:
1840c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_1;
1841c744b6f6SJean-Jacques Hiblot 		break;
1842c744b6f6SJean-Jacques Hiblot 	}
1843c744b6f6SJean-Jacques Hiblot 
1844c744b6f6SJean-Jacques Hiblot 	/* The partition data may be non-zero but it is only
1845c744b6f6SJean-Jacques Hiblot 	 * effective if PARTITION_SETTING_COMPLETED is set in
1846c744b6f6SJean-Jacques Hiblot 	 * EXT_CSD, so ignore any data if this bit is not set,
1847c744b6f6SJean-Jacques Hiblot 	 * except for enabling the high-capacity group size
1848c744b6f6SJean-Jacques Hiblot 	 * definition (see below).
1849c744b6f6SJean-Jacques Hiblot 	 */
1850c744b6f6SJean-Jacques Hiblot 	part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
1851c744b6f6SJean-Jacques Hiblot 			    EXT_CSD_PARTITION_SETTING_COMPLETED);
1852c744b6f6SJean-Jacques Hiblot 
1853c744b6f6SJean-Jacques Hiblot 	/* store the partition info of emmc */
1854c744b6f6SJean-Jacques Hiblot 	mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
1855c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
1856c744b6f6SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_BOOT_MULT])
1857c744b6f6SJean-Jacques Hiblot 		mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
1858c744b6f6SJean-Jacques Hiblot 	if (part_completed &&
1859c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
1860c744b6f6SJean-Jacques Hiblot 		mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
1861c744b6f6SJean-Jacques Hiblot 
1862c744b6f6SJean-Jacques Hiblot 	mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
1863c744b6f6SJean-Jacques Hiblot 
1864c744b6f6SJean-Jacques Hiblot 	mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
1865c744b6f6SJean-Jacques Hiblot 
1866c744b6f6SJean-Jacques Hiblot 	for (i = 0; i < 4; i++) {
1867c744b6f6SJean-Jacques Hiblot 		int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
1868c744b6f6SJean-Jacques Hiblot 		uint mult = (ext_csd[idx + 2] << 16) +
1869c744b6f6SJean-Jacques Hiblot 			(ext_csd[idx + 1] << 8) + ext_csd[idx];
1870c744b6f6SJean-Jacques Hiblot 		if (mult)
1871c744b6f6SJean-Jacques Hiblot 			has_parts = true;
1872c744b6f6SJean-Jacques Hiblot 		if (!part_completed)
1873c744b6f6SJean-Jacques Hiblot 			continue;
1874c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] = mult;
1875c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *=
1876c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1877c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1878c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] <<= 19;
1879c744b6f6SJean-Jacques Hiblot 	}
1880c744b6f6SJean-Jacques Hiblot 
1881c744b6f6SJean-Jacques Hiblot 	if (part_completed) {
1882c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size =
1883c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
1884c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
1885c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_SIZE_MULT];
1886c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1887c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1888c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size <<= 19;
1889c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_start =
1890c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
1891c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
1892c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
1893c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_START_ADDR];
1894c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity)
1895c744b6f6SJean-Jacques Hiblot 			mmc->enh_user_start <<= 9;
1896c744b6f6SJean-Jacques Hiblot 	}
1897c744b6f6SJean-Jacques Hiblot 
1898c744b6f6SJean-Jacques Hiblot 	/*
1899c744b6f6SJean-Jacques Hiblot 	 * Host needs to enable ERASE_GRP_DEF bit if device is
1900c744b6f6SJean-Jacques Hiblot 	 * partitioned. This bit will be lost every time after a reset
1901c744b6f6SJean-Jacques Hiblot 	 * or power off. This will affect erase size.
1902c744b6f6SJean-Jacques Hiblot 	 */
1903c744b6f6SJean-Jacques Hiblot 	if (part_completed)
1904c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1905c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
1906c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
1907c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1908c744b6f6SJean-Jacques Hiblot 	if (has_parts) {
1909c744b6f6SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1910c744b6f6SJean-Jacques Hiblot 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1911c744b6f6SJean-Jacques Hiblot 
1912c744b6f6SJean-Jacques Hiblot 		if (err)
1913c744b6f6SJean-Jacques Hiblot 			return err;
1914c744b6f6SJean-Jacques Hiblot 
1915c744b6f6SJean-Jacques Hiblot 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1916c744b6f6SJean-Jacques Hiblot 	}
1917c744b6f6SJean-Jacques Hiblot 
1918c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
1919c744b6f6SJean-Jacques Hiblot 		/* Read out group size from ext_csd */
1920c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size =
1921c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1922c744b6f6SJean-Jacques Hiblot 		/*
1923c744b6f6SJean-Jacques Hiblot 		 * if high capacity and partition setting completed
1924c744b6f6SJean-Jacques Hiblot 		 * SEC_COUNT is valid even if it is smaller than 2 GiB
1925c744b6f6SJean-Jacques Hiblot 		 * JEDEC Standard JESD84-B45, 6.2.4
1926c744b6f6SJean-Jacques Hiblot 		 */
1927c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity && part_completed) {
1928c744b6f6SJean-Jacques Hiblot 			capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1929c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1930c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1931c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1932c744b6f6SJean-Jacques Hiblot 			capacity *= MMC_MAX_BLOCK_LEN;
1933c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1934c744b6f6SJean-Jacques Hiblot 		}
1935c744b6f6SJean-Jacques Hiblot 	} else {
1936c744b6f6SJean-Jacques Hiblot 		/* Calculate the group size from the csd value. */
1937c744b6f6SJean-Jacques Hiblot 		int erase_gsz, erase_gmul;
1938c744b6f6SJean-Jacques Hiblot 
1939c744b6f6SJean-Jacques Hiblot 		erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1940c744b6f6SJean-Jacques Hiblot 		erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1941c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size = (erase_gsz + 1)
1942c744b6f6SJean-Jacques Hiblot 			* (erase_gmul + 1);
1943c744b6f6SJean-Jacques Hiblot 	}
1944c744b6f6SJean-Jacques Hiblot 
1945c744b6f6SJean-Jacques Hiblot 	mmc->hc_wp_grp_size = 1024
1946c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1947c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1948c744b6f6SJean-Jacques Hiblot 
1949c744b6f6SJean-Jacques Hiblot 	mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1950c744b6f6SJean-Jacques Hiblot 
1951c744b6f6SJean-Jacques Hiblot 	return 0;
1952c744b6f6SJean-Jacques Hiblot }
1953c744b6f6SJean-Jacques Hiblot 
1954fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1955272cc70bSAndy Fleming {
1956f866a46dSStephen Warren 	int err, i;
1957272cc70bSAndy Fleming 	uint mult, freq;
1958c744b6f6SJean-Jacques Hiblot 	u64 cmult, csize;
1959272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1960c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1961272cc70bSAndy Fleming 
1962d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1963d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1964d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1965d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1966d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1967d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1968d52ebf10SThomas Chou 		if (err)
1969d52ebf10SThomas Chou 			return err;
1970d52ebf10SThomas Chou 	}
1971d52ebf10SThomas Chou #endif
1972d52ebf10SThomas Chou 
1973272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1974d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1975d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1976272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1977272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1978272cc70bSAndy Fleming 
1979272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1980272cc70bSAndy Fleming 
198183dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
198283dc4227SKishon Vijay Abraham I 	if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) {
198383dc4227SKishon Vijay Abraham I 		int retries = 4;
198483dc4227SKishon Vijay Abraham I 		/*
198583dc4227SKishon Vijay Abraham I 		 * It has been seen that SEND_CID may fail on the first
198683dc4227SKishon Vijay Abraham I 		 * attempt, let's try a few more time
198783dc4227SKishon Vijay Abraham I 		 */
198883dc4227SKishon Vijay Abraham I 		do {
198983dc4227SKishon Vijay Abraham I 			err = mmc_send_cmd(mmc, &cmd, NULL);
199083dc4227SKishon Vijay Abraham I 			if (!err)
199183dc4227SKishon Vijay Abraham I 				break;
199283dc4227SKishon Vijay Abraham I 		} while (retries--);
199383dc4227SKishon Vijay Abraham I 	}
199483dc4227SKishon Vijay Abraham I #endif
199583dc4227SKishon Vijay Abraham I 
1996272cc70bSAndy Fleming 	if (err)
1997272cc70bSAndy Fleming 		return err;
1998272cc70bSAndy Fleming 
1999272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
2000272cc70bSAndy Fleming 
2001272cc70bSAndy Fleming 	/*
2002272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
2003272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
2004272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
2005272cc70bSAndy Fleming 	 */
2006d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2007272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
2008272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
2009272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
2010272cc70bSAndy Fleming 
2011272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
2012272cc70bSAndy Fleming 
2013272cc70bSAndy Fleming 		if (err)
2014272cc70bSAndy Fleming 			return err;
2015272cc70bSAndy Fleming 
2016272cc70bSAndy Fleming 		if (IS_SD(mmc))
2017998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
2018d52ebf10SThomas Chou 	}
2019272cc70bSAndy Fleming 
2020272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
2021272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
2022272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
2023272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
2024272cc70bSAndy Fleming 
2025272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2026272cc70bSAndy Fleming 
2027272cc70bSAndy Fleming 	if (err)
2028272cc70bSAndy Fleming 		return err;
2029272cc70bSAndy Fleming 
2030998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
2031998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
2032998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
2033998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
2034272cc70bSAndy Fleming 
2035272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
20360b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
2037272cc70bSAndy Fleming 
2038272cc70bSAndy Fleming 		switch (version) {
2039272cc70bSAndy Fleming 		case 0:
2040272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
2041272cc70bSAndy Fleming 			break;
2042272cc70bSAndy Fleming 		case 1:
2043272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
2044272cc70bSAndy Fleming 			break;
2045272cc70bSAndy Fleming 		case 2:
2046272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
2047272cc70bSAndy Fleming 			break;
2048272cc70bSAndy Fleming 		case 3:
2049272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
2050272cc70bSAndy Fleming 			break;
2051272cc70bSAndy Fleming 		case 4:
2052272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
2053272cc70bSAndy Fleming 			break;
2054272cc70bSAndy Fleming 		default:
2055272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
2056272cc70bSAndy Fleming 			break;
2057272cc70bSAndy Fleming 		}
2058272cc70bSAndy Fleming 	}
2059272cc70bSAndy Fleming 
2060272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
20610b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
20620b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
2063272cc70bSAndy Fleming 
206435f9e196SJean-Jacques Hiblot 	mmc->legacy_speed = freq * mult;
206535f9e196SJean-Jacques Hiblot 	mmc_select_mode(mmc, MMC_LEGACY);
2066272cc70bSAndy Fleming 
2067ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
2068998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
2069272cc70bSAndy Fleming 
2070272cc70bSAndy Fleming 	if (IS_SD(mmc))
2071272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
2072272cc70bSAndy Fleming 	else
2073998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
2074272cc70bSAndy Fleming 
2075272cc70bSAndy Fleming 	if (mmc->high_capacity) {
2076272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
2077272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
2078272cc70bSAndy Fleming 		cmult = 8;
2079272cc70bSAndy Fleming 	} else {
2080272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
2081272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
2082272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
2083272cc70bSAndy Fleming 	}
2084272cc70bSAndy Fleming 
2085f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
2086f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
2087f866a46dSStephen Warren 	mmc->capacity_boot = 0;
2088f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
2089f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
2090f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
2091272cc70bSAndy Fleming 
20928bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
20938bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
2094272cc70bSAndy Fleming 
20958bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
20968bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
2097272cc70bSAndy Fleming 
2098ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
2099ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
2100ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
2101ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
2102ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
2103ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
2104ab71188cSMarkus Niebel 	}
2105ab71188cSMarkus Niebel 
2106272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
2107d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2108272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
2109fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
2110272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
2111272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
2112272cc70bSAndy Fleming 
2113272cc70bSAndy Fleming 		if (err)
2114272cc70bSAndy Fleming 			return err;
2115d52ebf10SThomas Chou 	}
2116272cc70bSAndy Fleming 
2117e6f99a56SLei Wen 	/*
2118e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
2119e6f99a56SLei Wen 	 */
2120e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
2121bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
2122c744b6f6SJean-Jacques Hiblot 
2123dfda9d88SJean-Jacques Hiblot 	err = mmc_startup_v4(mmc);
21249cf199ebSDiego Santa Cruz 	if (err)
21259cf199ebSDiego Santa Cruz 		return err;
2126f866a46dSStephen Warren 
2127c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
2128f866a46dSStephen Warren 	if (err)
2129f866a46dSStephen Warren 		return err;
2130d23e2c09SSukumar Ghorai 
213101298da3SJean-Jacques Hiblot 	if (IS_SD(mmc)) {
213201298da3SJean-Jacques Hiblot 		err = sd_get_capabilities(mmc);
213301298da3SJean-Jacques Hiblot 		if (err)
213401298da3SJean-Jacques Hiblot 			return err;
213501298da3SJean-Jacques Hiblot 		err = sd_select_mode_and_width(mmc, mmc->card_caps);
213601298da3SJean-Jacques Hiblot 	} else {
213701298da3SJean-Jacques Hiblot 		err = mmc_get_capabilities(mmc);
213801298da3SJean-Jacques Hiblot 		if (err)
213901298da3SJean-Jacques Hiblot 			return err;
214001298da3SJean-Jacques Hiblot 		mmc_select_mode_and_width(mmc, mmc->card_caps);
214101298da3SJean-Jacques Hiblot 	}
2142272cc70bSAndy Fleming 
2143272cc70bSAndy Fleming 	if (err)
2144272cc70bSAndy Fleming 		return err;
2145272cc70bSAndy Fleming 
214601298da3SJean-Jacques Hiblot 	mmc->best_mode = mmc->selected_mode;
2147272cc70bSAndy Fleming 
21485af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
21495af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
21505af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
21515af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
21525af8f45cSAndrew Gabbasov 	}
21535af8f45cSAndrew Gabbasov 
2154272cc70bSAndy Fleming 	/* fill in device description */
2155c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
2156c40fdca6SSimon Glass 	bdesc->lun = 0;
2157c40fdca6SSimon Glass 	bdesc->hwpart = 0;
2158c40fdca6SSimon Glass 	bdesc->type = 0;
2159c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
2160c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
2161c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
2162fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
2163fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
2164fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
2165c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
2166babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
2167babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
2168c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
21690b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
2170babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
2171babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
2172c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
2173babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
217456196826SPaul Burton #else
2175c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
2176c40fdca6SSimon Glass 	bdesc->product[0] = 0;
2177c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
217856196826SPaul Burton #endif
2179122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
2180c40fdca6SSimon Glass 	part_init(bdesc);
2181122efd43SMikhail Kshevetskiy #endif
2182272cc70bSAndy Fleming 
2183272cc70bSAndy Fleming 	return 0;
2184272cc70bSAndy Fleming }
2185272cc70bSAndy Fleming 
2186fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
2187272cc70bSAndy Fleming {
2188272cc70bSAndy Fleming 	struct mmc_cmd cmd;
2189272cc70bSAndy Fleming 	int err;
2190272cc70bSAndy Fleming 
2191272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
2192272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
219393bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
2194272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
2195272cc70bSAndy Fleming 
2196272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2197272cc70bSAndy Fleming 
2198272cc70bSAndy Fleming 	if (err)
2199272cc70bSAndy Fleming 		return err;
2200272cc70bSAndy Fleming 
2201998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
2202915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
2203272cc70bSAndy Fleming 	else
2204272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
2205272cc70bSAndy Fleming 
2206272cc70bSAndy Fleming 	return 0;
2207272cc70bSAndy Fleming }
2208272cc70bSAndy Fleming 
2209c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
221095de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
221195de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
221295de9ab2SPaul Kocialkowski {
221395de9ab2SPaul Kocialkowski }
221405cbeb7cSSimon Glass #endif
221595de9ab2SPaul Kocialkowski 
22162051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
22172051aefeSPeng Fan {
2218c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
221906ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
22202051aefeSPeng Fan 	int ret;
22212051aefeSPeng Fan 
22222051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
222306ec045fSJean-Jacques Hiblot 					  &mmc->vmmc_supply);
222406ec045fSJean-Jacques Hiblot 	if (ret)
2225288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
22262051aefeSPeng Fan 
222706ec045fSJean-Jacques Hiblot 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
222806ec045fSJean-Jacques Hiblot 					  &mmc->vqmmc_supply);
222906ec045fSJean-Jacques Hiblot 	if (ret)
223006ec045fSJean-Jacques Hiblot 		debug("%s: No vqmmc supply\n", mmc->dev->name);
22312051aefeSPeng Fan #endif
223205cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
223305cbeb7cSSimon Glass 	/*
223405cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
223505cbeb7cSSimon Glass 	 * out to board code.
223605cbeb7cSSimon Glass 	 */
223705cbeb7cSSimon Glass 	board_mmc_power_init();
223805cbeb7cSSimon Glass #endif
22392051aefeSPeng Fan 	return 0;
22402051aefeSPeng Fan }
22412051aefeSPeng Fan 
2242fb7c3bebSKishon Vijay Abraham I /*
2243fb7c3bebSKishon Vijay Abraham I  * put the host in the initial state:
2244fb7c3bebSKishon Vijay Abraham I  * - turn on Vdd (card power supply)
2245fb7c3bebSKishon Vijay Abraham I  * - configure the bus width and clock to minimal values
2246fb7c3bebSKishon Vijay Abraham I  */
2247fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc)
2248fb7c3bebSKishon Vijay Abraham I {
2249fb7c3bebSKishon Vijay Abraham I 	int err;
2250fb7c3bebSKishon Vijay Abraham I 
2251fb7c3bebSKishon Vijay Abraham I 	/* First try to set 3.3V. If it fails set to 1.8V */
2252fb7c3bebSKishon Vijay Abraham I 	err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330);
2253fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2254fb7c3bebSKishon Vijay Abraham I 		err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
2255fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2256fb7c3bebSKishon Vijay Abraham I 		printf("mmc: failed to set signal voltage\n");
2257fb7c3bebSKishon Vijay Abraham I 
2258fb7c3bebSKishon Vijay Abraham I 	mmc_select_mode(mmc, MMC_LEGACY);
2259fb7c3bebSKishon Vijay Abraham I 	mmc_set_bus_width(mmc, 1);
226035f67820SKishon Vijay Abraham I 	mmc_set_clock(mmc, 0, false);
2261fb7c3bebSKishon Vijay Abraham I }
2262fb7c3bebSKishon Vijay Abraham I 
2263fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc)
2264fb7c3bebSKishon Vijay Abraham I {
2265fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2266fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2267fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, true);
2268fb7c3bebSKishon Vijay Abraham I 
2269fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2270fb7c3bebSKishon Vijay Abraham I 			puts("Error enabling VMMC supply\n");
2271fb7c3bebSKishon Vijay Abraham I 			return ret;
2272fb7c3bebSKishon Vijay Abraham I 		}
2273fb7c3bebSKishon Vijay Abraham I 	}
2274fb7c3bebSKishon Vijay Abraham I #endif
2275fb7c3bebSKishon Vijay Abraham I 	return 0;
2276fb7c3bebSKishon Vijay Abraham I }
2277fb7c3bebSKishon Vijay Abraham I 
2278fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc)
2279fb7c3bebSKishon Vijay Abraham I {
22802e7410d7SKishon Vijay Abraham I 	mmc_set_clock(mmc, 1, true);
2281fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2282fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2283fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, false);
2284fb7c3bebSKishon Vijay Abraham I 
2285fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2286c10b85d6SJean-Jacques Hiblot 			debug("Error disabling VMMC supply\n");
2287fb7c3bebSKishon Vijay Abraham I 			return ret;
2288fb7c3bebSKishon Vijay Abraham I 		}
2289fb7c3bebSKishon Vijay Abraham I 	}
2290fb7c3bebSKishon Vijay Abraham I #endif
2291fb7c3bebSKishon Vijay Abraham I 	return 0;
2292fb7c3bebSKishon Vijay Abraham I }
2293fb7c3bebSKishon Vijay Abraham I 
2294fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc)
2295fb7c3bebSKishon Vijay Abraham I {
2296fb7c3bebSKishon Vijay Abraham I 	int ret;
2297fb7c3bebSKishon Vijay Abraham I 
2298fb7c3bebSKishon Vijay Abraham I 	ret = mmc_power_off(mmc);
2299fb7c3bebSKishon Vijay Abraham I 	if (ret)
2300fb7c3bebSKishon Vijay Abraham I 		return ret;
2301fb7c3bebSKishon Vijay Abraham I 	/*
2302fb7c3bebSKishon Vijay Abraham I 	 * SD spec recommends at least 1ms of delay. Let's wait for 2ms
2303fb7c3bebSKishon Vijay Abraham I 	 * to be on the safer side.
2304fb7c3bebSKishon Vijay Abraham I 	 */
2305fb7c3bebSKishon Vijay Abraham I 	udelay(2000);
2306fb7c3bebSKishon Vijay Abraham I 	return mmc_power_on(mmc);
2307fb7c3bebSKishon Vijay Abraham I }
2308fb7c3bebSKishon Vijay Abraham I 
2309e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
2310272cc70bSAndy Fleming {
23118ca51e51SSimon Glass 	bool no_card;
2312c10b85d6SJean-Jacques Hiblot 	bool uhs_en = supports_uhs(mmc->cfg->host_caps);
2313afd5932bSMacpaul Lin 	int err;
2314272cc70bSAndy Fleming 
231504a2ea24SJean-Jacques Hiblot 	mmc->host_caps = mmc->cfg->host_caps;
231604a2ea24SJean-Jacques Hiblot 
2317ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
23188ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
2319e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
23208ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
23218ca51e51SSimon Glass #endif
23228ca51e51SSimon Glass 	if (no_card) {
232348972d90SThierry Reding 		mmc->has_init = 0;
232456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
232548972d90SThierry Reding 		printf("MMC: no card present\n");
232656196826SPaul Burton #endif
2327915ffa52SJaehoon Chung 		return -ENOMEDIUM;
232848972d90SThierry Reding 	}
232948972d90SThierry Reding 
2330bc897b1dSLei Wen 	if (mmc->has_init)
2331bc897b1dSLei Wen 		return 0;
2332bc897b1dSLei Wen 
23335a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
23345a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
23355a8dbdc6SYangbo Lu #endif
23362051aefeSPeng Fan 	err = mmc_power_init(mmc);
23372051aefeSPeng Fan 	if (err)
23382051aefeSPeng Fan 		return err;
233995de9ab2SPaul Kocialkowski 
234083dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
234183dc4227SKishon Vijay Abraham I 	mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN |
234283dc4227SKishon Vijay Abraham I 		      MMC_QUIRK_RETRY_SEND_CID;
234383dc4227SKishon Vijay Abraham I #endif
234483dc4227SKishon Vijay Abraham I 
234504a2ea24SJean-Jacques Hiblot 	err = mmc_power_cycle(mmc);
234604a2ea24SJean-Jacques Hiblot 	if (err) {
234704a2ea24SJean-Jacques Hiblot 		/*
234804a2ea24SJean-Jacques Hiblot 		 * if power cycling is not supported, we should not try
234904a2ea24SJean-Jacques Hiblot 		 * to use the UHS modes, because we wouldn't be able to
235004a2ea24SJean-Jacques Hiblot 		 * recover from an error during the UHS initialization.
235104a2ea24SJean-Jacques Hiblot 		 */
235204a2ea24SJean-Jacques Hiblot 		debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n");
235304a2ea24SJean-Jacques Hiblot 		uhs_en = false;
235404a2ea24SJean-Jacques Hiblot 		mmc->host_caps &= ~UHS_CAPS;
2355fb7c3bebSKishon Vijay Abraham I 		err = mmc_power_on(mmc);
235604a2ea24SJean-Jacques Hiblot 	}
2357fb7c3bebSKishon Vijay Abraham I 	if (err)
2358fb7c3bebSKishon Vijay Abraham I 		return err;
2359fb7c3bebSKishon Vijay Abraham I 
2360e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
23618ca51e51SSimon Glass 	/* The device has already been probed ready for use */
23628ca51e51SSimon Glass #else
2363ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
236493bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
2365272cc70bSAndy Fleming 	if (err)
2366272cc70bSAndy Fleming 		return err;
23678ca51e51SSimon Glass #endif
2368786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
2369aff5d3c8SKishon Vijay Abraham I 
2370c10b85d6SJean-Jacques Hiblot retry:
2371fb7c3bebSKishon Vijay Abraham I 	mmc_set_initial_state(mmc);
2372318a7a57SJean-Jacques Hiblot 	mmc_send_init_stream(mmc);
2373318a7a57SJean-Jacques Hiblot 
2374272cc70bSAndy Fleming 	/* Reset the Card */
2375272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
2376272cc70bSAndy Fleming 
2377272cc70bSAndy Fleming 	if (err)
2378272cc70bSAndy Fleming 		return err;
2379272cc70bSAndy Fleming 
2380bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
2381c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
2382bc897b1dSLei Wen 
2383272cc70bSAndy Fleming 	/* Test for SD version 2 */
2384272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
2385272cc70bSAndy Fleming 
2386272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
2387c10b85d6SJean-Jacques Hiblot 	err = sd_send_op_cond(mmc, uhs_en);
2388c10b85d6SJean-Jacques Hiblot 	if (err && uhs_en) {
2389c10b85d6SJean-Jacques Hiblot 		uhs_en = false;
2390c10b85d6SJean-Jacques Hiblot 		mmc_power_cycle(mmc);
2391c10b85d6SJean-Jacques Hiblot 		goto retry;
2392c10b85d6SJean-Jacques Hiblot 	}
2393272cc70bSAndy Fleming 
2394272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
2395915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
2396272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
2397272cc70bSAndy Fleming 
2398bd47c135SAndrew Gabbasov 		if (err) {
239956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2400272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
240156196826SPaul Burton #endif
2402915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
2403272cc70bSAndy Fleming 		}
2404272cc70bSAndy Fleming 	}
2405272cc70bSAndy Fleming 
2406bd47c135SAndrew Gabbasov 	if (!err)
2407e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
2408e9550449SChe-Liang Chiou 
2409e9550449SChe-Liang Chiou 	return err;
2410e9550449SChe-Liang Chiou }
2411e9550449SChe-Liang Chiou 
2412e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2413e9550449SChe-Liang Chiou {
2414e9550449SChe-Liang Chiou 	int err = 0;
2415e9550449SChe-Liang Chiou 
2416bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
2417e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
2418e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
2419e9550449SChe-Liang Chiou 
2420e9550449SChe-Liang Chiou 	if (!err)
2421bc897b1dSLei Wen 		err = mmc_startup(mmc);
2422bc897b1dSLei Wen 	if (err)
2423bc897b1dSLei Wen 		mmc->has_init = 0;
2424bc897b1dSLei Wen 	else
2425bc897b1dSLei Wen 		mmc->has_init = 1;
2426e9550449SChe-Liang Chiou 	return err;
2427e9550449SChe-Liang Chiou }
2428e9550449SChe-Liang Chiou 
2429e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2430e9550449SChe-Liang Chiou {
2431bd47c135SAndrew Gabbasov 	int err = 0;
2432ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
2433c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
243433fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2435e9550449SChe-Liang Chiou 
243633fb211dSSimon Glass 	upriv->mmc = mmc;
243733fb211dSSimon Glass #endif
2438e9550449SChe-Liang Chiou 	if (mmc->has_init)
2439e9550449SChe-Liang Chiou 		return 0;
2440d803fea5SMateusz Zalega 
2441d803fea5SMateusz Zalega 	start = get_timer(0);
2442d803fea5SMateusz Zalega 
2443e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2444e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2445e9550449SChe-Liang Chiou 
2446bd47c135SAndrew Gabbasov 	if (!err)
2447e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2448919b4858SJagan Teki 	if (err)
2449919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
2450919b4858SJagan Teki 
2451bc897b1dSLei Wen 	return err;
2452272cc70bSAndy Fleming }
2453272cc70bSAndy Fleming 
2454ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2455ab71188cSMarkus Niebel {
2456ab71188cSMarkus Niebel 	mmc->dsr = val;
2457ab71188cSMarkus Niebel 	return 0;
2458ab71188cSMarkus Niebel }
2459ab71188cSMarkus Niebel 
2460cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2461cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2462272cc70bSAndy Fleming {
2463272cc70bSAndy Fleming 	return -1;
2464272cc70bSAndy Fleming }
2465272cc70bSAndy Fleming 
2466cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2467cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2468cee9ab7cSJeroen Hofstee {
2469cee9ab7cSJeroen Hofstee 	return -1;
2470cee9ab7cSJeroen Hofstee }
2471272cc70bSAndy Fleming 
2472e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2473e9550449SChe-Liang Chiou {
2474e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2475e9550449SChe-Liang Chiou }
2476e9550449SChe-Liang Chiou 
2477c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
24788e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
24798e3332e2SSjoerd Simons {
24808e3332e2SSjoerd Simons 	return 0;
24818e3332e2SSjoerd Simons }
2482c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
24838e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
24848e3332e2SSjoerd Simons {
24854a1db6d8SSimon Glass 	int ret, i;
24868e3332e2SSjoerd Simons 	struct uclass *uc;
24874a1db6d8SSimon Glass 	struct udevice *dev;
24888e3332e2SSjoerd Simons 
24898e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
24908e3332e2SSjoerd Simons 	if (ret)
24918e3332e2SSjoerd Simons 		return ret;
24928e3332e2SSjoerd Simons 
24934a1db6d8SSimon Glass 	/*
24944a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
24954a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
24964a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
24974a1db6d8SSimon Glass 	 */
24984a1db6d8SSimon Glass 	for (i = 0; ; i++) {
24994a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
25004a1db6d8SSimon Glass 		if (ret == -ENODEV)
25014a1db6d8SSimon Glass 			break;
25024a1db6d8SSimon Glass 	}
25034a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
25044a1db6d8SSimon Glass 		ret = device_probe(dev);
25058e3332e2SSjoerd Simons 		if (ret)
25064a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
25078e3332e2SSjoerd Simons 	}
25088e3332e2SSjoerd Simons 
25098e3332e2SSjoerd Simons 	return 0;
25108e3332e2SSjoerd Simons }
25118e3332e2SSjoerd Simons #else
25128e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
25138e3332e2SSjoerd Simons {
25148e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
25158e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
25168e3332e2SSjoerd Simons 
25178e3332e2SSjoerd Simons 	return 0;
25188e3332e2SSjoerd Simons }
25198e3332e2SSjoerd Simons #endif
2520e9550449SChe-Liang Chiou 
2521272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2522272cc70bSAndy Fleming {
25231b26bab1SDaniel Kochmański 	static int initialized = 0;
25248e3332e2SSjoerd Simons 	int ret;
25251b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
25261b26bab1SDaniel Kochmański 		return 0;
25271b26bab1SDaniel Kochmański 	initialized = 1;
25281b26bab1SDaniel Kochmański 
2529c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2530b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2531c40fdca6SSimon Glass 	mmc_list_init();
2532c40fdca6SSimon Glass #endif
2533b5b838f1SMarek Vasut #endif
25348e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
25358e3332e2SSjoerd Simons 	if (ret)
25368e3332e2SSjoerd Simons 		return ret;
2537272cc70bSAndy Fleming 
2538bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2539272cc70bSAndy Fleming 	print_mmc_devices(',');
2540bb0dc108SYing Zhang #endif
2541272cc70bSAndy Fleming 
2542c40fdca6SSimon Glass 	mmc_do_preinit();
2543272cc70bSAndy Fleming 	return 0;
2544272cc70bSAndy Fleming }
2545cd3d4880STomas Melin 
2546cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2547cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2548cd3d4880STomas Melin {
2549cd3d4880STomas Melin 	int err;
2550cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2551cd3d4880STomas Melin 
2552cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2553cd3d4880STomas Melin 	if (err) {
2554cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2555cd3d4880STomas Melin 		return err;
2556cd3d4880STomas Melin 	}
2557cd3d4880STomas Melin 
2558cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2559cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2560cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2561cd3d4880STomas Melin 	}
2562cd3d4880STomas Melin 
2563cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2564cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2565cd3d4880STomas Melin 		return 0;
2566cd3d4880STomas Melin 	}
2567cd3d4880STomas Melin 
2568cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2569cd3d4880STomas Melin 	if (err) {
2570cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2571cd3d4880STomas Melin 		return err;
2572cd3d4880STomas Melin 	}
2573cd3d4880STomas Melin 
2574cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2575cd3d4880STomas Melin 
2576cd3d4880STomas Melin 	return 0;
2577cd3d4880STomas Melin }
2578cd3d4880STomas Melin #endif
2579