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