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