xref: /arm-trusted-firmware/drivers/mmc/mmc.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu /* Define a simple and generic interface to access eMMC and SD-card devices. */
8*91f16700Schasinglulu 
9*91f16700Schasinglulu #include <assert.h>
10*91f16700Schasinglulu #include <errno.h>
11*91f16700Schasinglulu #include <stdbool.h>
12*91f16700Schasinglulu #include <string.h>
13*91f16700Schasinglulu 
14*91f16700Schasinglulu #include <arch_helpers.h>
15*91f16700Schasinglulu #include <common/debug.h>
16*91f16700Schasinglulu #include <drivers/delay_timer.h>
17*91f16700Schasinglulu #include <drivers/mmc.h>
18*91f16700Schasinglulu #include <lib/utils.h>
19*91f16700Schasinglulu #include <plat/common/common_def.h>
20*91f16700Schasinglulu 
21*91f16700Schasinglulu #define MMC_DEFAULT_MAX_RETRIES		5
22*91f16700Schasinglulu #define SEND_OP_COND_MAX_RETRIES	100
23*91f16700Schasinglulu 
24*91f16700Schasinglulu #define MULT_BY_512K_SHIFT		19
25*91f16700Schasinglulu 
26*91f16700Schasinglulu static const struct mmc_ops *ops;
27*91f16700Schasinglulu static unsigned int mmc_ocr_value;
28*91f16700Schasinglulu static struct mmc_csd_emmc mmc_csd;
29*91f16700Schasinglulu static struct sd_switch_status sd_switch_func_status;
30*91f16700Schasinglulu static unsigned char mmc_ext_csd[512] __aligned(16);
31*91f16700Schasinglulu static unsigned int mmc_flags;
32*91f16700Schasinglulu static struct mmc_device_info *mmc_dev_info;
33*91f16700Schasinglulu static unsigned int rca;
34*91f16700Schasinglulu static unsigned int scr[2]__aligned(16) = { 0 };
35*91f16700Schasinglulu 
36*91f16700Schasinglulu static const unsigned char tran_speed_base[16] = {
37*91f16700Schasinglulu 	0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80
38*91f16700Schasinglulu };
39*91f16700Schasinglulu 
40*91f16700Schasinglulu static const unsigned char sd_tran_speed_base[16] = {
41*91f16700Schasinglulu 	0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80
42*91f16700Schasinglulu };
43*91f16700Schasinglulu 
44*91f16700Schasinglulu static bool is_cmd23_enabled(void)
45*91f16700Schasinglulu {
46*91f16700Schasinglulu 	return ((mmc_flags & MMC_FLAG_CMD23) != 0U);
47*91f16700Schasinglulu }
48*91f16700Schasinglulu 
49*91f16700Schasinglulu static bool is_sd_cmd6_enabled(void)
50*91f16700Schasinglulu {
51*91f16700Schasinglulu 	return ((mmc_flags & MMC_FLAG_SD_CMD6) != 0U);
52*91f16700Schasinglulu }
53*91f16700Schasinglulu 
54*91f16700Schasinglulu static int mmc_send_cmd(unsigned int idx, unsigned int arg,
55*91f16700Schasinglulu 			unsigned int r_type, unsigned int *r_data)
56*91f16700Schasinglulu {
57*91f16700Schasinglulu 	struct mmc_cmd cmd;
58*91f16700Schasinglulu 	int ret;
59*91f16700Schasinglulu 
60*91f16700Schasinglulu 	zeromem(&cmd, sizeof(struct mmc_cmd));
61*91f16700Schasinglulu 
62*91f16700Schasinglulu 	cmd.cmd_idx = idx;
63*91f16700Schasinglulu 	cmd.cmd_arg = arg;
64*91f16700Schasinglulu 	cmd.resp_type = r_type;
65*91f16700Schasinglulu 
66*91f16700Schasinglulu 	ret = ops->send_cmd(&cmd);
67*91f16700Schasinglulu 
68*91f16700Schasinglulu 	if ((ret == 0) && (r_data != NULL)) {
69*91f16700Schasinglulu 		int i;
70*91f16700Schasinglulu 
71*91f16700Schasinglulu 		for (i = 0; i < 4; i++) {
72*91f16700Schasinglulu 			r_data[i] = cmd.resp_data[i];
73*91f16700Schasinglulu 		}
74*91f16700Schasinglulu 	}
75*91f16700Schasinglulu 
76*91f16700Schasinglulu 	if (ret != 0) {
77*91f16700Schasinglulu 		VERBOSE("Send command %u error: %d\n", idx, ret);
78*91f16700Schasinglulu 	}
79*91f16700Schasinglulu 
80*91f16700Schasinglulu 	return ret;
81*91f16700Schasinglulu }
82*91f16700Schasinglulu 
83*91f16700Schasinglulu static int mmc_device_state(void)
84*91f16700Schasinglulu {
85*91f16700Schasinglulu 	int retries = MMC_DEFAULT_MAX_RETRIES;
86*91f16700Schasinglulu 	unsigned int resp_data[4] = {0};
87*91f16700Schasinglulu 
88*91f16700Schasinglulu 	do {
89*91f16700Schasinglulu 		int ret;
90*91f16700Schasinglulu 
91*91f16700Schasinglulu 		if (retries == 0) {
92*91f16700Schasinglulu 			ERROR("CMD13 failed after %d retries\n",
93*91f16700Schasinglulu 			      MMC_DEFAULT_MAX_RETRIES);
94*91f16700Schasinglulu 			return -EIO;
95*91f16700Schasinglulu 		}
96*91f16700Schasinglulu 
97*91f16700Schasinglulu 		ret = mmc_send_cmd(MMC_CMD(13), rca << RCA_SHIFT_OFFSET,
98*91f16700Schasinglulu 				   MMC_RESPONSE_R1, &resp_data[0]);
99*91f16700Schasinglulu 		if (ret != 0) {
100*91f16700Schasinglulu 			retries--;
101*91f16700Schasinglulu 			continue;
102*91f16700Schasinglulu 		}
103*91f16700Schasinglulu 
104*91f16700Schasinglulu 		if ((resp_data[0] & STATUS_SWITCH_ERROR) != 0U) {
105*91f16700Schasinglulu 			return -EIO;
106*91f16700Schasinglulu 		}
107*91f16700Schasinglulu 
108*91f16700Schasinglulu 		retries--;
109*91f16700Schasinglulu 	} while ((resp_data[0] & STATUS_READY_FOR_DATA) == 0U);
110*91f16700Schasinglulu 
111*91f16700Schasinglulu 	return MMC_GET_STATE(resp_data[0]);
112*91f16700Schasinglulu }
113*91f16700Schasinglulu 
114*91f16700Schasinglulu static int mmc_send_part_switch_cmd(unsigned char part_config)
115*91f16700Schasinglulu {
116*91f16700Schasinglulu 	int ret;
117*91f16700Schasinglulu 	unsigned int part_time = 0;
118*91f16700Schasinglulu 
119*91f16700Schasinglulu 	ret = mmc_send_cmd(MMC_CMD(6),
120*91f16700Schasinglulu 			   EXTCSD_WRITE_BYTES |
121*91f16700Schasinglulu 			   EXTCSD_CMD(CMD_EXTCSD_PARTITION_CONFIG) |
122*91f16700Schasinglulu 			   EXTCSD_VALUE(part_config) |
123*91f16700Schasinglulu 			   EXTCSD_CMD_SET_NORMAL,
124*91f16700Schasinglulu 			   MMC_RESPONSE_R1B, NULL);
125*91f16700Schasinglulu 	if (ret != 0) {
126*91f16700Schasinglulu 		return ret;
127*91f16700Schasinglulu 	}
128*91f16700Schasinglulu 
129*91f16700Schasinglulu 	/* Partition switch timing is in 10ms units */
130*91f16700Schasinglulu 	part_time = mmc_ext_csd[CMD_EXTCSD_PART_SWITCH_TIME] * 10;
131*91f16700Schasinglulu 
132*91f16700Schasinglulu 	mdelay(part_time);
133*91f16700Schasinglulu 
134*91f16700Schasinglulu 	do {
135*91f16700Schasinglulu 		ret = mmc_device_state();
136*91f16700Schasinglulu 		if (ret < 0) {
137*91f16700Schasinglulu 			return ret;
138*91f16700Schasinglulu 		}
139*91f16700Schasinglulu 	} while (ret == MMC_STATE_PRG);
140*91f16700Schasinglulu 
141*91f16700Schasinglulu 	return 0;
142*91f16700Schasinglulu }
143*91f16700Schasinglulu 
144*91f16700Schasinglulu static int mmc_set_ext_csd(unsigned int ext_cmd, unsigned int value)
145*91f16700Schasinglulu {
146*91f16700Schasinglulu 	int ret;
147*91f16700Schasinglulu 
148*91f16700Schasinglulu 	ret = mmc_send_cmd(MMC_CMD(6),
149*91f16700Schasinglulu 			   EXTCSD_WRITE_BYTES | EXTCSD_CMD(ext_cmd) |
150*91f16700Schasinglulu 			   EXTCSD_VALUE(value) | EXTCSD_CMD_SET_NORMAL,
151*91f16700Schasinglulu 			   MMC_RESPONSE_R1B, NULL);
152*91f16700Schasinglulu 	if (ret != 0) {
153*91f16700Schasinglulu 		return ret;
154*91f16700Schasinglulu 	}
155*91f16700Schasinglulu 
156*91f16700Schasinglulu 	do {
157*91f16700Schasinglulu 		ret = mmc_device_state();
158*91f16700Schasinglulu 		if (ret < 0) {
159*91f16700Schasinglulu 			return ret;
160*91f16700Schasinglulu 		}
161*91f16700Schasinglulu 	} while (ret == MMC_STATE_PRG);
162*91f16700Schasinglulu 
163*91f16700Schasinglulu 	return 0;
164*91f16700Schasinglulu }
165*91f16700Schasinglulu 
166*91f16700Schasinglulu static int mmc_sd_switch(unsigned int bus_width)
167*91f16700Schasinglulu {
168*91f16700Schasinglulu 	int ret;
169*91f16700Schasinglulu 	int retries = MMC_DEFAULT_MAX_RETRIES;
170*91f16700Schasinglulu 	unsigned int bus_width_arg = 0;
171*91f16700Schasinglulu 
172*91f16700Schasinglulu 	ret = ops->prepare(0, (uintptr_t)&scr, sizeof(scr));
173*91f16700Schasinglulu 	if (ret != 0) {
174*91f16700Schasinglulu 		return ret;
175*91f16700Schasinglulu 	}
176*91f16700Schasinglulu 
177*91f16700Schasinglulu 	/* CMD55: Application Specific Command */
178*91f16700Schasinglulu 	ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET,
179*91f16700Schasinglulu 			   MMC_RESPONSE_R5, NULL);
180*91f16700Schasinglulu 	if (ret != 0) {
181*91f16700Schasinglulu 		return ret;
182*91f16700Schasinglulu 	}
183*91f16700Schasinglulu 
184*91f16700Schasinglulu 	/* ACMD51: SEND_SCR */
185*91f16700Schasinglulu 	do {
186*91f16700Schasinglulu 		ret = mmc_send_cmd(MMC_ACMD(51), 0, MMC_RESPONSE_R1, NULL);
187*91f16700Schasinglulu 		if ((ret != 0) && (retries == 0)) {
188*91f16700Schasinglulu 			ERROR("ACMD51 failed after %d retries (ret=%d)\n",
189*91f16700Schasinglulu 			      MMC_DEFAULT_MAX_RETRIES, ret);
190*91f16700Schasinglulu 			return ret;
191*91f16700Schasinglulu 		}
192*91f16700Schasinglulu 
193*91f16700Schasinglulu 		retries--;
194*91f16700Schasinglulu 	} while (ret != 0);
195*91f16700Schasinglulu 
196*91f16700Schasinglulu 	ret = ops->read(0, (uintptr_t)&scr, sizeof(scr));
197*91f16700Schasinglulu 	if (ret != 0) {
198*91f16700Schasinglulu 		return ret;
199*91f16700Schasinglulu 	}
200*91f16700Schasinglulu 
201*91f16700Schasinglulu 	if (((scr[0] & SD_SCR_BUS_WIDTH_4) != 0U) &&
202*91f16700Schasinglulu 	    (bus_width == MMC_BUS_WIDTH_4)) {
203*91f16700Schasinglulu 		bus_width_arg = 2;
204*91f16700Schasinglulu 	}
205*91f16700Schasinglulu 
206*91f16700Schasinglulu 	/* CMD55: Application Specific Command */
207*91f16700Schasinglulu 	ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET,
208*91f16700Schasinglulu 			   MMC_RESPONSE_R5, NULL);
209*91f16700Schasinglulu 	if (ret != 0) {
210*91f16700Schasinglulu 		return ret;
211*91f16700Schasinglulu 	}
212*91f16700Schasinglulu 
213*91f16700Schasinglulu 	/* ACMD6: SET_BUS_WIDTH */
214*91f16700Schasinglulu 	ret = mmc_send_cmd(MMC_ACMD(6), bus_width_arg, MMC_RESPONSE_R1, NULL);
215*91f16700Schasinglulu 	if (ret != 0) {
216*91f16700Schasinglulu 		return ret;
217*91f16700Schasinglulu 	}
218*91f16700Schasinglulu 
219*91f16700Schasinglulu 	do {
220*91f16700Schasinglulu 		ret = mmc_device_state();
221*91f16700Schasinglulu 		if (ret < 0) {
222*91f16700Schasinglulu 			return ret;
223*91f16700Schasinglulu 		}
224*91f16700Schasinglulu 	} while (ret == MMC_STATE_PRG);
225*91f16700Schasinglulu 
226*91f16700Schasinglulu 	return 0;
227*91f16700Schasinglulu }
228*91f16700Schasinglulu 
229*91f16700Schasinglulu static int mmc_set_ios(unsigned int clk, unsigned int bus_width)
230*91f16700Schasinglulu {
231*91f16700Schasinglulu 	int ret;
232*91f16700Schasinglulu 	unsigned int width = bus_width;
233*91f16700Schasinglulu 
234*91f16700Schasinglulu 	if (mmc_dev_info->mmc_dev_type != MMC_IS_EMMC) {
235*91f16700Schasinglulu 		if (width == MMC_BUS_WIDTH_8) {
236*91f16700Schasinglulu 			WARN("Wrong bus config for SD-card, force to 4\n");
237*91f16700Schasinglulu 			width = MMC_BUS_WIDTH_4;
238*91f16700Schasinglulu 		}
239*91f16700Schasinglulu 		ret = mmc_sd_switch(width);
240*91f16700Schasinglulu 		if (ret != 0) {
241*91f16700Schasinglulu 			return ret;
242*91f16700Schasinglulu 		}
243*91f16700Schasinglulu 	} else if (mmc_csd.spec_vers == 4U) {
244*91f16700Schasinglulu 		ret = mmc_set_ext_csd(CMD_EXTCSD_BUS_WIDTH,
245*91f16700Schasinglulu 				      (unsigned int)width);
246*91f16700Schasinglulu 		if (ret != 0) {
247*91f16700Schasinglulu 			return ret;
248*91f16700Schasinglulu 		}
249*91f16700Schasinglulu 	} else {
250*91f16700Schasinglulu 		VERBOSE("Wrong MMC type or spec version\n");
251*91f16700Schasinglulu 	}
252*91f16700Schasinglulu 
253*91f16700Schasinglulu 	return ops->set_ios(clk, width);
254*91f16700Schasinglulu }
255*91f16700Schasinglulu 
256*91f16700Schasinglulu static int mmc_fill_device_info(void)
257*91f16700Schasinglulu {
258*91f16700Schasinglulu 	unsigned long long c_size;
259*91f16700Schasinglulu 	unsigned int speed_idx;
260*91f16700Schasinglulu 	unsigned int nb_blocks;
261*91f16700Schasinglulu 	unsigned int freq_unit;
262*91f16700Schasinglulu 	int ret = 0;
263*91f16700Schasinglulu 	struct mmc_csd_sd_v2 *csd_sd_v2;
264*91f16700Schasinglulu 
265*91f16700Schasinglulu 	switch (mmc_dev_info->mmc_dev_type) {
266*91f16700Schasinglulu 	case MMC_IS_EMMC:
267*91f16700Schasinglulu 		mmc_dev_info->block_size = MMC_BLOCK_SIZE;
268*91f16700Schasinglulu 
269*91f16700Schasinglulu 		ret = ops->prepare(0, (uintptr_t)&mmc_ext_csd,
270*91f16700Schasinglulu 				   sizeof(mmc_ext_csd));
271*91f16700Schasinglulu 		if (ret != 0) {
272*91f16700Schasinglulu 			return ret;
273*91f16700Schasinglulu 		}
274*91f16700Schasinglulu 
275*91f16700Schasinglulu 		/* MMC CMD8: SEND_EXT_CSD */
276*91f16700Schasinglulu 		ret = mmc_send_cmd(MMC_CMD(8), 0, MMC_RESPONSE_R1, NULL);
277*91f16700Schasinglulu 		if (ret != 0) {
278*91f16700Schasinglulu 			return ret;
279*91f16700Schasinglulu 		}
280*91f16700Schasinglulu 
281*91f16700Schasinglulu 		ret = ops->read(0, (uintptr_t)&mmc_ext_csd,
282*91f16700Schasinglulu 				sizeof(mmc_ext_csd));
283*91f16700Schasinglulu 		if (ret != 0) {
284*91f16700Schasinglulu 			return ret;
285*91f16700Schasinglulu 		}
286*91f16700Schasinglulu 
287*91f16700Schasinglulu 		do {
288*91f16700Schasinglulu 			ret = mmc_device_state();
289*91f16700Schasinglulu 			if (ret < 0) {
290*91f16700Schasinglulu 				return ret;
291*91f16700Schasinglulu 			}
292*91f16700Schasinglulu 		} while (ret != MMC_STATE_TRAN);
293*91f16700Schasinglulu 
294*91f16700Schasinglulu 		nb_blocks = (mmc_ext_csd[CMD_EXTCSD_SEC_CNT] << 0) |
295*91f16700Schasinglulu 			    (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 1] << 8) |
296*91f16700Schasinglulu 			    (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 2] << 16) |
297*91f16700Schasinglulu 			    (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 3] << 24);
298*91f16700Schasinglulu 
299*91f16700Schasinglulu 		mmc_dev_info->device_size = (unsigned long long)nb_blocks *
300*91f16700Schasinglulu 			mmc_dev_info->block_size;
301*91f16700Schasinglulu 
302*91f16700Schasinglulu 		break;
303*91f16700Schasinglulu 
304*91f16700Schasinglulu 	case MMC_IS_SD:
305*91f16700Schasinglulu 		/*
306*91f16700Schasinglulu 		 * Use the same mmc_csd struct, as required fields here
307*91f16700Schasinglulu 		 * (READ_BL_LEN, C_SIZE, CSIZE_MULT) are common with eMMC.
308*91f16700Schasinglulu 		 */
309*91f16700Schasinglulu 		mmc_dev_info->block_size = BIT_32(mmc_csd.read_bl_len);
310*91f16700Schasinglulu 
311*91f16700Schasinglulu 		c_size = ((unsigned long long)mmc_csd.c_size_high << 2U) |
312*91f16700Schasinglulu 			 (unsigned long long)mmc_csd.c_size_low;
313*91f16700Schasinglulu 		assert(c_size != 0xFFFU);
314*91f16700Schasinglulu 
315*91f16700Schasinglulu 		mmc_dev_info->device_size = (c_size + 1U) *
316*91f16700Schasinglulu 					    BIT_64(mmc_csd.c_size_mult + 2U) *
317*91f16700Schasinglulu 					    mmc_dev_info->block_size;
318*91f16700Schasinglulu 
319*91f16700Schasinglulu 		break;
320*91f16700Schasinglulu 
321*91f16700Schasinglulu 	case MMC_IS_SD_HC:
322*91f16700Schasinglulu 		assert(mmc_csd.csd_structure == 1U);
323*91f16700Schasinglulu 
324*91f16700Schasinglulu 		mmc_dev_info->block_size = MMC_BLOCK_SIZE;
325*91f16700Schasinglulu 
326*91f16700Schasinglulu 		/* Need to use mmc_csd_sd_v2 struct */
327*91f16700Schasinglulu 		csd_sd_v2 = (struct mmc_csd_sd_v2 *)&mmc_csd;
328*91f16700Schasinglulu 		c_size = ((unsigned long long)csd_sd_v2->c_size_high << 16) |
329*91f16700Schasinglulu 			 (unsigned long long)csd_sd_v2->c_size_low;
330*91f16700Schasinglulu 
331*91f16700Schasinglulu 		mmc_dev_info->device_size = (c_size + 1U) << MULT_BY_512K_SHIFT;
332*91f16700Schasinglulu 
333*91f16700Schasinglulu 		break;
334*91f16700Schasinglulu 
335*91f16700Schasinglulu 	default:
336*91f16700Schasinglulu 		ret = -EINVAL;
337*91f16700Schasinglulu 		break;
338*91f16700Schasinglulu 	}
339*91f16700Schasinglulu 
340*91f16700Schasinglulu 	if (ret < 0) {
341*91f16700Schasinglulu 		return ret;
342*91f16700Schasinglulu 	}
343*91f16700Schasinglulu 
344*91f16700Schasinglulu 	speed_idx = (mmc_csd.tran_speed & CSD_TRAN_SPEED_MULT_MASK) >>
345*91f16700Schasinglulu 			 CSD_TRAN_SPEED_MULT_SHIFT;
346*91f16700Schasinglulu 
347*91f16700Schasinglulu 	assert(speed_idx > 0U);
348*91f16700Schasinglulu 
349*91f16700Schasinglulu 	if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
350*91f16700Schasinglulu 		mmc_dev_info->max_bus_freq = tran_speed_base[speed_idx];
351*91f16700Schasinglulu 	} else {
352*91f16700Schasinglulu 		mmc_dev_info->max_bus_freq = sd_tran_speed_base[speed_idx];
353*91f16700Schasinglulu 	}
354*91f16700Schasinglulu 
355*91f16700Schasinglulu 	freq_unit = mmc_csd.tran_speed & CSD_TRAN_SPEED_UNIT_MASK;
356*91f16700Schasinglulu 	while (freq_unit != 0U) {
357*91f16700Schasinglulu 		mmc_dev_info->max_bus_freq *= 10U;
358*91f16700Schasinglulu 		--freq_unit;
359*91f16700Schasinglulu 	}
360*91f16700Schasinglulu 
361*91f16700Schasinglulu 	mmc_dev_info->max_bus_freq *= 10000U;
362*91f16700Schasinglulu 
363*91f16700Schasinglulu 	return 0;
364*91f16700Schasinglulu }
365*91f16700Schasinglulu 
366*91f16700Schasinglulu static int sd_switch(unsigned int mode, unsigned char group,
367*91f16700Schasinglulu 		     unsigned char func)
368*91f16700Schasinglulu {
369*91f16700Schasinglulu 	unsigned int group_shift = (group - 1U) * 4U;
370*91f16700Schasinglulu 	unsigned int group_mask = GENMASK(group_shift + 3U,  group_shift);
371*91f16700Schasinglulu 	unsigned int arg;
372*91f16700Schasinglulu 	int ret;
373*91f16700Schasinglulu 
374*91f16700Schasinglulu 	ret = ops->prepare(0, (uintptr_t)&sd_switch_func_status,
375*91f16700Schasinglulu 			   sizeof(sd_switch_func_status));
376*91f16700Schasinglulu 	if (ret != 0) {
377*91f16700Schasinglulu 		return ret;
378*91f16700Schasinglulu 	}
379*91f16700Schasinglulu 
380*91f16700Schasinglulu 	/* MMC CMD6: SWITCH_FUNC */
381*91f16700Schasinglulu 	arg = mode | SD_SWITCH_ALL_GROUPS_MASK;
382*91f16700Schasinglulu 	arg &= ~group_mask;
383*91f16700Schasinglulu 	arg |= func << group_shift;
384*91f16700Schasinglulu 	ret = mmc_send_cmd(MMC_CMD(6), arg, MMC_RESPONSE_R1, NULL);
385*91f16700Schasinglulu 	if (ret != 0) {
386*91f16700Schasinglulu 		return ret;
387*91f16700Schasinglulu 	}
388*91f16700Schasinglulu 
389*91f16700Schasinglulu 	return ops->read(0, (uintptr_t)&sd_switch_func_status,
390*91f16700Schasinglulu 			 sizeof(sd_switch_func_status));
391*91f16700Schasinglulu }
392*91f16700Schasinglulu 
393*91f16700Schasinglulu static int sd_send_op_cond(void)
394*91f16700Schasinglulu {
395*91f16700Schasinglulu 	int n;
396*91f16700Schasinglulu 	unsigned int resp_data[4];
397*91f16700Schasinglulu 
398*91f16700Schasinglulu 	for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) {
399*91f16700Schasinglulu 		int ret;
400*91f16700Schasinglulu 
401*91f16700Schasinglulu 		/* CMD55: Application Specific Command */
402*91f16700Schasinglulu 		ret = mmc_send_cmd(MMC_CMD(55), 0, MMC_RESPONSE_R1, NULL);
403*91f16700Schasinglulu 		if (ret != 0) {
404*91f16700Schasinglulu 			return ret;
405*91f16700Schasinglulu 		}
406*91f16700Schasinglulu 
407*91f16700Schasinglulu 		/* ACMD41: SD_SEND_OP_COND */
408*91f16700Schasinglulu 		ret = mmc_send_cmd(MMC_ACMD(41), OCR_HCS |
409*91f16700Schasinglulu 			mmc_dev_info->ocr_voltage, MMC_RESPONSE_R3,
410*91f16700Schasinglulu 			&resp_data[0]);
411*91f16700Schasinglulu 		if (ret != 0) {
412*91f16700Schasinglulu 			return ret;
413*91f16700Schasinglulu 		}
414*91f16700Schasinglulu 
415*91f16700Schasinglulu 		if ((resp_data[0] & OCR_POWERUP) != 0U) {
416*91f16700Schasinglulu 			mmc_ocr_value = resp_data[0];
417*91f16700Schasinglulu 
418*91f16700Schasinglulu 			if ((mmc_ocr_value & OCR_HCS) != 0U) {
419*91f16700Schasinglulu 				mmc_dev_info->mmc_dev_type = MMC_IS_SD_HC;
420*91f16700Schasinglulu 			} else {
421*91f16700Schasinglulu 				mmc_dev_info->mmc_dev_type = MMC_IS_SD;
422*91f16700Schasinglulu 			}
423*91f16700Schasinglulu 
424*91f16700Schasinglulu 			return 0;
425*91f16700Schasinglulu 		}
426*91f16700Schasinglulu 
427*91f16700Schasinglulu 		mdelay(10);
428*91f16700Schasinglulu 	}
429*91f16700Schasinglulu 
430*91f16700Schasinglulu 	ERROR("ACMD41 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES);
431*91f16700Schasinglulu 
432*91f16700Schasinglulu 	return -EIO;
433*91f16700Schasinglulu }
434*91f16700Schasinglulu 
435*91f16700Schasinglulu static int mmc_reset_to_idle(void)
436*91f16700Schasinglulu {
437*91f16700Schasinglulu 	int ret;
438*91f16700Schasinglulu 
439*91f16700Schasinglulu 	/* CMD0: reset to IDLE */
440*91f16700Schasinglulu 	ret = mmc_send_cmd(MMC_CMD(0), 0, 0, NULL);
441*91f16700Schasinglulu 	if (ret != 0) {
442*91f16700Schasinglulu 		return ret;
443*91f16700Schasinglulu 	}
444*91f16700Schasinglulu 
445*91f16700Schasinglulu 	mdelay(2);
446*91f16700Schasinglulu 
447*91f16700Schasinglulu 	return 0;
448*91f16700Schasinglulu }
449*91f16700Schasinglulu 
450*91f16700Schasinglulu static int mmc_send_op_cond(void)
451*91f16700Schasinglulu {
452*91f16700Schasinglulu 	int ret, n;
453*91f16700Schasinglulu 	unsigned int resp_data[4];
454*91f16700Schasinglulu 
455*91f16700Schasinglulu 	for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) {
456*91f16700Schasinglulu 		ret = mmc_send_cmd(MMC_CMD(1), OCR_SECTOR_MODE |
457*91f16700Schasinglulu 				   OCR_VDD_MIN_2V7 | OCR_VDD_MIN_1V7,
458*91f16700Schasinglulu 				   MMC_RESPONSE_R3, &resp_data[0]);
459*91f16700Schasinglulu 		if (ret != 0) {
460*91f16700Schasinglulu 			return ret;
461*91f16700Schasinglulu 		}
462*91f16700Schasinglulu 
463*91f16700Schasinglulu 		if ((resp_data[0] & OCR_POWERUP) != 0U) {
464*91f16700Schasinglulu 			mmc_ocr_value = resp_data[0];
465*91f16700Schasinglulu 			return 0;
466*91f16700Schasinglulu 		}
467*91f16700Schasinglulu 
468*91f16700Schasinglulu 		mdelay(10);
469*91f16700Schasinglulu 	}
470*91f16700Schasinglulu 
471*91f16700Schasinglulu 	ERROR("CMD1 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES);
472*91f16700Schasinglulu 
473*91f16700Schasinglulu 	return -EIO;
474*91f16700Schasinglulu }
475*91f16700Schasinglulu 
476*91f16700Schasinglulu static int mmc_enumerate(unsigned int clk, unsigned int bus_width)
477*91f16700Schasinglulu {
478*91f16700Schasinglulu 	int ret;
479*91f16700Schasinglulu 	unsigned int resp_data[4];
480*91f16700Schasinglulu 
481*91f16700Schasinglulu 	ops->init();
482*91f16700Schasinglulu 
483*91f16700Schasinglulu 	ret = mmc_reset_to_idle();
484*91f16700Schasinglulu 	if (ret != 0) {
485*91f16700Schasinglulu 		return ret;
486*91f16700Schasinglulu 	}
487*91f16700Schasinglulu 
488*91f16700Schasinglulu 	if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
489*91f16700Schasinglulu 		ret = mmc_send_op_cond();
490*91f16700Schasinglulu 	} else {
491*91f16700Schasinglulu 		/* CMD8: Send Interface Condition Command */
492*91f16700Schasinglulu 		ret = mmc_send_cmd(MMC_CMD(8), VHS_2_7_3_6_V | CMD8_CHECK_PATTERN,
493*91f16700Schasinglulu 				   MMC_RESPONSE_R5, &resp_data[0]);
494*91f16700Schasinglulu 
495*91f16700Schasinglulu 		if ((ret == 0) && ((resp_data[0] & 0xffU) == CMD8_CHECK_PATTERN)) {
496*91f16700Schasinglulu 			ret = sd_send_op_cond();
497*91f16700Schasinglulu 		}
498*91f16700Schasinglulu 	}
499*91f16700Schasinglulu 	if (ret != 0) {
500*91f16700Schasinglulu 		return ret;
501*91f16700Schasinglulu 	}
502*91f16700Schasinglulu 
503*91f16700Schasinglulu 	/* CMD2: Card Identification */
504*91f16700Schasinglulu 	ret = mmc_send_cmd(MMC_CMD(2), 0, MMC_RESPONSE_R2, NULL);
505*91f16700Schasinglulu 	if (ret != 0) {
506*91f16700Schasinglulu 		return ret;
507*91f16700Schasinglulu 	}
508*91f16700Schasinglulu 
509*91f16700Schasinglulu 	/* CMD3: Set Relative Address */
510*91f16700Schasinglulu 	if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
511*91f16700Schasinglulu 		rca = MMC_FIX_RCA;
512*91f16700Schasinglulu 		ret = mmc_send_cmd(MMC_CMD(3), rca << RCA_SHIFT_OFFSET,
513*91f16700Schasinglulu 				   MMC_RESPONSE_R1, NULL);
514*91f16700Schasinglulu 		if (ret != 0) {
515*91f16700Schasinglulu 			return ret;
516*91f16700Schasinglulu 		}
517*91f16700Schasinglulu 	} else {
518*91f16700Schasinglulu 		ret = mmc_send_cmd(MMC_CMD(3), 0,
519*91f16700Schasinglulu 				   MMC_RESPONSE_R6, &resp_data[0]);
520*91f16700Schasinglulu 		if (ret != 0) {
521*91f16700Schasinglulu 			return ret;
522*91f16700Schasinglulu 		}
523*91f16700Schasinglulu 
524*91f16700Schasinglulu 		rca = (resp_data[0] & 0xFFFF0000U) >> 16;
525*91f16700Schasinglulu 	}
526*91f16700Schasinglulu 
527*91f16700Schasinglulu 	/* CMD9: CSD Register */
528*91f16700Schasinglulu 	ret = mmc_send_cmd(MMC_CMD(9), rca << RCA_SHIFT_OFFSET,
529*91f16700Schasinglulu 			   MMC_RESPONSE_R2, &resp_data[0]);
530*91f16700Schasinglulu 	if (ret != 0) {
531*91f16700Schasinglulu 		return ret;
532*91f16700Schasinglulu 	}
533*91f16700Schasinglulu 
534*91f16700Schasinglulu 	memcpy(&mmc_csd, &resp_data, sizeof(resp_data));
535*91f16700Schasinglulu 
536*91f16700Schasinglulu 	/* CMD7: Select Card */
537*91f16700Schasinglulu 	ret = mmc_send_cmd(MMC_CMD(7), rca << RCA_SHIFT_OFFSET,
538*91f16700Schasinglulu 			   MMC_RESPONSE_R1, NULL);
539*91f16700Schasinglulu 	if (ret != 0) {
540*91f16700Schasinglulu 		return ret;
541*91f16700Schasinglulu 	}
542*91f16700Schasinglulu 
543*91f16700Schasinglulu 	do {
544*91f16700Schasinglulu 		ret = mmc_device_state();
545*91f16700Schasinglulu 		if (ret < 0) {
546*91f16700Schasinglulu 			return ret;
547*91f16700Schasinglulu 		}
548*91f16700Schasinglulu 	} while (ret != MMC_STATE_TRAN);
549*91f16700Schasinglulu 
550*91f16700Schasinglulu 	ret = mmc_set_ios(clk, bus_width);
551*91f16700Schasinglulu 	if (ret != 0) {
552*91f16700Schasinglulu 		return ret;
553*91f16700Schasinglulu 	}
554*91f16700Schasinglulu 
555*91f16700Schasinglulu 	ret = mmc_fill_device_info();
556*91f16700Schasinglulu 	if (ret != 0) {
557*91f16700Schasinglulu 		return ret;
558*91f16700Schasinglulu 	}
559*91f16700Schasinglulu 
560*91f16700Schasinglulu 	if (is_sd_cmd6_enabled() &&
561*91f16700Schasinglulu 	    (mmc_dev_info->mmc_dev_type == MMC_IS_SD_HC)) {
562*91f16700Schasinglulu 		/* Try to switch to High Speed Mode */
563*91f16700Schasinglulu 		ret = sd_switch(SD_SWITCH_FUNC_CHECK, 1U, 1U);
564*91f16700Schasinglulu 		if (ret != 0) {
565*91f16700Schasinglulu 			return ret;
566*91f16700Schasinglulu 		}
567*91f16700Schasinglulu 
568*91f16700Schasinglulu 		if ((sd_switch_func_status.support_g1 & BIT(9)) == 0U) {
569*91f16700Schasinglulu 			/* High speed not supported, keep default speed */
570*91f16700Schasinglulu 			return 0;
571*91f16700Schasinglulu 		}
572*91f16700Schasinglulu 
573*91f16700Schasinglulu 		ret = sd_switch(SD_SWITCH_FUNC_SWITCH, 1U, 1U);
574*91f16700Schasinglulu 		if (ret != 0) {
575*91f16700Schasinglulu 			return ret;
576*91f16700Schasinglulu 		}
577*91f16700Schasinglulu 
578*91f16700Schasinglulu 		if ((sd_switch_func_status.sel_g2_g1 & 0x1U) == 0U) {
579*91f16700Schasinglulu 			/* Cannot switch to high speed, keep default speed */
580*91f16700Schasinglulu 			return 0;
581*91f16700Schasinglulu 		}
582*91f16700Schasinglulu 
583*91f16700Schasinglulu 		mmc_dev_info->max_bus_freq = 50000000U;
584*91f16700Schasinglulu 		ret = ops->set_ios(clk, bus_width);
585*91f16700Schasinglulu 	}
586*91f16700Schasinglulu 
587*91f16700Schasinglulu 	return ret;
588*91f16700Schasinglulu }
589*91f16700Schasinglulu 
590*91f16700Schasinglulu size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size)
591*91f16700Schasinglulu {
592*91f16700Schasinglulu 	int ret;
593*91f16700Schasinglulu 	unsigned int cmd_idx, cmd_arg;
594*91f16700Schasinglulu 
595*91f16700Schasinglulu 	assert((ops != NULL) &&
596*91f16700Schasinglulu 	       (ops->read != NULL) &&
597*91f16700Schasinglulu 	       (size != 0U) &&
598*91f16700Schasinglulu 	       ((size & MMC_BLOCK_MASK) == 0U));
599*91f16700Schasinglulu 
600*91f16700Schasinglulu 	ret = ops->prepare(lba, buf, size);
601*91f16700Schasinglulu 	if (ret != 0) {
602*91f16700Schasinglulu 		return 0;
603*91f16700Schasinglulu 	}
604*91f16700Schasinglulu 
605*91f16700Schasinglulu 	if (is_cmd23_enabled()) {
606*91f16700Schasinglulu 		/* Set block count */
607*91f16700Schasinglulu 		ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE,
608*91f16700Schasinglulu 				   MMC_RESPONSE_R1, NULL);
609*91f16700Schasinglulu 		if (ret != 0) {
610*91f16700Schasinglulu 			return 0;
611*91f16700Schasinglulu 		}
612*91f16700Schasinglulu 
613*91f16700Schasinglulu 		cmd_idx = MMC_CMD(18);
614*91f16700Schasinglulu 	} else {
615*91f16700Schasinglulu 		if (size > MMC_BLOCK_SIZE) {
616*91f16700Schasinglulu 			cmd_idx = MMC_CMD(18);
617*91f16700Schasinglulu 		} else {
618*91f16700Schasinglulu 			cmd_idx = MMC_CMD(17);
619*91f16700Schasinglulu 		}
620*91f16700Schasinglulu 	}
621*91f16700Schasinglulu 
622*91f16700Schasinglulu 	if (((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) &&
623*91f16700Schasinglulu 	    (mmc_dev_info->mmc_dev_type != MMC_IS_SD_HC)) {
624*91f16700Schasinglulu 		cmd_arg = lba * MMC_BLOCK_SIZE;
625*91f16700Schasinglulu 	} else {
626*91f16700Schasinglulu 		cmd_arg = lba;
627*91f16700Schasinglulu 	}
628*91f16700Schasinglulu 
629*91f16700Schasinglulu 	ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL);
630*91f16700Schasinglulu 	if (ret != 0) {
631*91f16700Schasinglulu 		return 0;
632*91f16700Schasinglulu 	}
633*91f16700Schasinglulu 
634*91f16700Schasinglulu 	ret = ops->read(lba, buf, size);
635*91f16700Schasinglulu 	if (ret != 0) {
636*91f16700Schasinglulu 		return 0;
637*91f16700Schasinglulu 	}
638*91f16700Schasinglulu 
639*91f16700Schasinglulu 	/* Wait buffer empty */
640*91f16700Schasinglulu 	do {
641*91f16700Schasinglulu 		ret = mmc_device_state();
642*91f16700Schasinglulu 		if (ret < 0) {
643*91f16700Schasinglulu 			return 0;
644*91f16700Schasinglulu 		}
645*91f16700Schasinglulu 	} while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_DATA));
646*91f16700Schasinglulu 
647*91f16700Schasinglulu 	if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) {
648*91f16700Schasinglulu 		ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL);
649*91f16700Schasinglulu 		if (ret != 0) {
650*91f16700Schasinglulu 			return 0;
651*91f16700Schasinglulu 		}
652*91f16700Schasinglulu 	}
653*91f16700Schasinglulu 
654*91f16700Schasinglulu 	return size;
655*91f16700Schasinglulu }
656*91f16700Schasinglulu 
657*91f16700Schasinglulu size_t mmc_write_blocks(int lba, const uintptr_t buf, size_t size)
658*91f16700Schasinglulu {
659*91f16700Schasinglulu 	int ret;
660*91f16700Schasinglulu 	unsigned int cmd_idx, cmd_arg;
661*91f16700Schasinglulu 
662*91f16700Schasinglulu 	assert((ops != NULL) &&
663*91f16700Schasinglulu 	       (ops->write != NULL) &&
664*91f16700Schasinglulu 	       (size != 0U) &&
665*91f16700Schasinglulu 	       ((buf & MMC_BLOCK_MASK) == 0U) &&
666*91f16700Schasinglulu 	       ((size & MMC_BLOCK_MASK) == 0U));
667*91f16700Schasinglulu 
668*91f16700Schasinglulu 	ret = ops->prepare(lba, buf, size);
669*91f16700Schasinglulu 	if (ret != 0) {
670*91f16700Schasinglulu 		return 0;
671*91f16700Schasinglulu 	}
672*91f16700Schasinglulu 
673*91f16700Schasinglulu 	if (is_cmd23_enabled()) {
674*91f16700Schasinglulu 		/* Set block count */
675*91f16700Schasinglulu 		ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE,
676*91f16700Schasinglulu 				   MMC_RESPONSE_R1, NULL);
677*91f16700Schasinglulu 		if (ret != 0) {
678*91f16700Schasinglulu 			return 0;
679*91f16700Schasinglulu 		}
680*91f16700Schasinglulu 
681*91f16700Schasinglulu 		cmd_idx = MMC_CMD(25);
682*91f16700Schasinglulu 	} else {
683*91f16700Schasinglulu 		if (size > MMC_BLOCK_SIZE) {
684*91f16700Schasinglulu 			cmd_idx = MMC_CMD(25);
685*91f16700Schasinglulu 		} else {
686*91f16700Schasinglulu 			cmd_idx = MMC_CMD(24);
687*91f16700Schasinglulu 		}
688*91f16700Schasinglulu 	}
689*91f16700Schasinglulu 
690*91f16700Schasinglulu 	if ((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) {
691*91f16700Schasinglulu 		cmd_arg = lba * MMC_BLOCK_SIZE;
692*91f16700Schasinglulu 	} else {
693*91f16700Schasinglulu 		cmd_arg = lba;
694*91f16700Schasinglulu 	}
695*91f16700Schasinglulu 
696*91f16700Schasinglulu 	ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL);
697*91f16700Schasinglulu 	if (ret != 0) {
698*91f16700Schasinglulu 		return 0;
699*91f16700Schasinglulu 	}
700*91f16700Schasinglulu 
701*91f16700Schasinglulu 	ret = ops->write(lba, buf, size);
702*91f16700Schasinglulu 	if (ret != 0) {
703*91f16700Schasinglulu 		return 0;
704*91f16700Schasinglulu 	}
705*91f16700Schasinglulu 
706*91f16700Schasinglulu 	/* Wait buffer empty */
707*91f16700Schasinglulu 	do {
708*91f16700Schasinglulu 		ret = mmc_device_state();
709*91f16700Schasinglulu 		if (ret < 0) {
710*91f16700Schasinglulu 			return 0;
711*91f16700Schasinglulu 		}
712*91f16700Schasinglulu 	} while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_RCV));
713*91f16700Schasinglulu 
714*91f16700Schasinglulu 	if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) {
715*91f16700Schasinglulu 		ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL);
716*91f16700Schasinglulu 		if (ret != 0) {
717*91f16700Schasinglulu 			return 0;
718*91f16700Schasinglulu 		}
719*91f16700Schasinglulu 	}
720*91f16700Schasinglulu 
721*91f16700Schasinglulu 	return size;
722*91f16700Schasinglulu }
723*91f16700Schasinglulu 
724*91f16700Schasinglulu size_t mmc_erase_blocks(int lba, size_t size)
725*91f16700Schasinglulu {
726*91f16700Schasinglulu 	int ret;
727*91f16700Schasinglulu 
728*91f16700Schasinglulu 	assert(ops != NULL);
729*91f16700Schasinglulu 	assert((size != 0U) && ((size & MMC_BLOCK_MASK) == 0U));
730*91f16700Schasinglulu 
731*91f16700Schasinglulu 	ret = mmc_send_cmd(MMC_CMD(35), lba, MMC_RESPONSE_R1, NULL);
732*91f16700Schasinglulu 	if (ret != 0) {
733*91f16700Schasinglulu 		return 0;
734*91f16700Schasinglulu 	}
735*91f16700Schasinglulu 
736*91f16700Schasinglulu 	ret = mmc_send_cmd(MMC_CMD(36), lba + (size / MMC_BLOCK_SIZE) - 1U,
737*91f16700Schasinglulu 			   MMC_RESPONSE_R1, NULL);
738*91f16700Schasinglulu 	if (ret != 0) {
739*91f16700Schasinglulu 		return 0;
740*91f16700Schasinglulu 	}
741*91f16700Schasinglulu 
742*91f16700Schasinglulu 	ret = mmc_send_cmd(MMC_CMD(38), lba, MMC_RESPONSE_R1B, NULL);
743*91f16700Schasinglulu 	if (ret != 0) {
744*91f16700Schasinglulu 		return 0;
745*91f16700Schasinglulu 	}
746*91f16700Schasinglulu 
747*91f16700Schasinglulu 	do {
748*91f16700Schasinglulu 		ret = mmc_device_state();
749*91f16700Schasinglulu 		if (ret < 0) {
750*91f16700Schasinglulu 			return 0;
751*91f16700Schasinglulu 		}
752*91f16700Schasinglulu 	} while (ret != MMC_STATE_TRAN);
753*91f16700Schasinglulu 
754*91f16700Schasinglulu 	return size;
755*91f16700Schasinglulu }
756*91f16700Schasinglulu 
757*91f16700Schasinglulu static int mmc_part_switch(unsigned char part_type)
758*91f16700Schasinglulu {
759*91f16700Schasinglulu 	unsigned char part_config = mmc_ext_csd[CMD_EXTCSD_PARTITION_CONFIG];
760*91f16700Schasinglulu 
761*91f16700Schasinglulu 	part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
762*91f16700Schasinglulu 	part_config |= part_type;
763*91f16700Schasinglulu 
764*91f16700Schasinglulu 	return mmc_send_part_switch_cmd(part_config);
765*91f16700Schasinglulu }
766*91f16700Schasinglulu 
767*91f16700Schasinglulu static unsigned char mmc_current_boot_part(void)
768*91f16700Schasinglulu {
769*91f16700Schasinglulu 	return PART_CFG_CURRENT_BOOT_PARTITION(mmc_ext_csd[CMD_EXTCSD_PARTITION_CONFIG]);
770*91f16700Schasinglulu }
771*91f16700Schasinglulu 
772*91f16700Schasinglulu int mmc_part_switch_current_boot(void)
773*91f16700Schasinglulu {
774*91f16700Schasinglulu 	unsigned char current_boot_part = mmc_current_boot_part();
775*91f16700Schasinglulu 	int ret;
776*91f16700Schasinglulu 
777*91f16700Schasinglulu 	if ((current_boot_part != 1U) && (current_boot_part != 2U)) {
778*91f16700Schasinglulu 		ERROR("Got unexpected value for active boot partition, %u\n", current_boot_part);
779*91f16700Schasinglulu 		return -EIO;
780*91f16700Schasinglulu 	}
781*91f16700Schasinglulu 
782*91f16700Schasinglulu 	ret = mmc_part_switch(current_boot_part);
783*91f16700Schasinglulu 	if (ret < 0) {
784*91f16700Schasinglulu 		ERROR("Failed to switch to boot partition, %d\n", ret);
785*91f16700Schasinglulu 	}
786*91f16700Schasinglulu 
787*91f16700Schasinglulu 	return ret;
788*91f16700Schasinglulu }
789*91f16700Schasinglulu 
790*91f16700Schasinglulu int mmc_part_switch_user(void)
791*91f16700Schasinglulu {
792*91f16700Schasinglulu 	int ret;
793*91f16700Schasinglulu 
794*91f16700Schasinglulu 	ret = mmc_part_switch(PART_CFG_BOOT_PARTITION_NO_ACCESS);
795*91f16700Schasinglulu 	if (ret < 0) {
796*91f16700Schasinglulu 		ERROR("Failed to switch to user partition, %d\n", ret);
797*91f16700Schasinglulu 	}
798*91f16700Schasinglulu 
799*91f16700Schasinglulu 	return ret;
800*91f16700Schasinglulu }
801*91f16700Schasinglulu 
802*91f16700Schasinglulu size_t mmc_boot_part_size(void)
803*91f16700Schasinglulu {
804*91f16700Schasinglulu 	return mmc_ext_csd[CMD_EXTCSD_BOOT_SIZE_MULT] * SZ_128K;
805*91f16700Schasinglulu }
806*91f16700Schasinglulu 
807*91f16700Schasinglulu size_t mmc_boot_part_read_blocks(int lba, uintptr_t buf, size_t size)
808*91f16700Schasinglulu {
809*91f16700Schasinglulu 	size_t size_read;
810*91f16700Schasinglulu 	int ret;
811*91f16700Schasinglulu 
812*91f16700Schasinglulu 	ret = mmc_part_switch_current_boot();
813*91f16700Schasinglulu 	if (ret < 0) {
814*91f16700Schasinglulu 		return 0;
815*91f16700Schasinglulu 	}
816*91f16700Schasinglulu 
817*91f16700Schasinglulu 	size_read = mmc_read_blocks(lba, buf, size);
818*91f16700Schasinglulu 
819*91f16700Schasinglulu 	ret = mmc_part_switch_user();
820*91f16700Schasinglulu 	if (ret < 0) {
821*91f16700Schasinglulu 		return 0;
822*91f16700Schasinglulu 	}
823*91f16700Schasinglulu 
824*91f16700Schasinglulu 	return size_read;
825*91f16700Schasinglulu }
826*91f16700Schasinglulu 
827*91f16700Schasinglulu int mmc_init(const struct mmc_ops *ops_ptr, unsigned int clk,
828*91f16700Schasinglulu 	     unsigned int width, unsigned int flags,
829*91f16700Schasinglulu 	     struct mmc_device_info *device_info)
830*91f16700Schasinglulu {
831*91f16700Schasinglulu 	assert((ops_ptr != NULL) &&
832*91f16700Schasinglulu 	       (ops_ptr->init != NULL) &&
833*91f16700Schasinglulu 	       (ops_ptr->send_cmd != NULL) &&
834*91f16700Schasinglulu 	       (ops_ptr->set_ios != NULL) &&
835*91f16700Schasinglulu 	       (ops_ptr->prepare != NULL) &&
836*91f16700Schasinglulu 	       (ops_ptr->read != NULL) &&
837*91f16700Schasinglulu 	       (ops_ptr->write != NULL) &&
838*91f16700Schasinglulu 	       (device_info != NULL) &&
839*91f16700Schasinglulu 	       (clk != 0) &&
840*91f16700Schasinglulu 	       ((width == MMC_BUS_WIDTH_1) ||
841*91f16700Schasinglulu 		(width == MMC_BUS_WIDTH_4) ||
842*91f16700Schasinglulu 		(width == MMC_BUS_WIDTH_8) ||
843*91f16700Schasinglulu 		(width == MMC_BUS_WIDTH_DDR_4) ||
844*91f16700Schasinglulu 		(width == MMC_BUS_WIDTH_DDR_8)));
845*91f16700Schasinglulu 
846*91f16700Schasinglulu 	ops = ops_ptr;
847*91f16700Schasinglulu 	mmc_flags = flags;
848*91f16700Schasinglulu 	mmc_dev_info = device_info;
849*91f16700Schasinglulu 
850*91f16700Schasinglulu 	return mmc_enumerate(clk, width);
851*91f16700Schasinglulu }
852