xref: /arm-trusted-firmware/drivers/nxp/sd/sd_mmc.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright 2021 NXP
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  *
6*91f16700Schasinglulu  *
7*91f16700Schasinglulu  */
8*91f16700Schasinglulu 
9*91f16700Schasinglulu #include <endian.h>
10*91f16700Schasinglulu #include <stdio.h>
11*91f16700Schasinglulu #include <stdlib.h>
12*91f16700Schasinglulu #include <string.h>
13*91f16700Schasinglulu 
14*91f16700Schasinglulu #include <arch_helpers.h>
15*91f16700Schasinglulu #include <common/debug.h>
16*91f16700Schasinglulu #include <drivers/io/io_block.h>
17*91f16700Schasinglulu #include "nxp_timer.h"
18*91f16700Schasinglulu #include "sd_mmc.h"
19*91f16700Schasinglulu #include <utils.h>
20*91f16700Schasinglulu #include <utils_def.h>
21*91f16700Schasinglulu 
22*91f16700Schasinglulu 
23*91f16700Schasinglulu /* Private structure for MMC driver data */
24*91f16700Schasinglulu static struct mmc mmc_drv_data;
25*91f16700Schasinglulu 
26*91f16700Schasinglulu #ifndef NXP_POLICY_OTA
27*91f16700Schasinglulu /*
28*91f16700Schasinglulu  * For NXP_POLICY_OTA, SD needs to do R/W on OCRAM. OCRAM is secure memory at
29*91f16700Schasinglulu  * default. SD can only do non-secure DMA. Configuring SD to work in PIO mode
30*91f16700Schasinglulu  * instead of DMA mode will make SD R/W on OCRAM available.
31*91f16700Schasinglulu  */
32*91f16700Schasinglulu /* To debug without dma comment this MACRO */
33*91f16700Schasinglulu #define NXP_SD_DMA_CAPABILITY
34*91f16700Schasinglulu #endif
35*91f16700Schasinglulu #define SD_TIMEOUT        1000 /* ms */
36*91f16700Schasinglulu #define SD_TIMEOUT_HIGH   20000 /* ms */
37*91f16700Schasinglulu #define SD_BLOCK_TIMEOUT  8 /* ms */
38*91f16700Schasinglulu 
39*91f16700Schasinglulu #define ERROR_ESDHC_CARD_DETECT_FAIL	-1
40*91f16700Schasinglulu #define ERROR_ESDHC_UNUSABLE_CARD	-2
41*91f16700Schasinglulu #define ERROR_ESDHC_COMMUNICATION_ERROR	-3
42*91f16700Schasinglulu #define ERROR_ESDHC_BLOCK_LENGTH	-4
43*91f16700Schasinglulu #define ERROR_ESDHC_DMA_ERROR		-5
44*91f16700Schasinglulu #define ERROR_ESDHC_BUSY		-6
45*91f16700Schasinglulu 
46*91f16700Schasinglulu /***************************************************************
47*91f16700Schasinglulu  * Function    :    set_speed
48*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
49*91f16700Schasinglulu  *                  clock - Clock Value to be set
50*91f16700Schasinglulu  * Return      :    void
51*91f16700Schasinglulu  * Description :    Calculates the value of SDCLKFS and DVS to be set
52*91f16700Schasinglulu  *                  for getting the required clock assuming the base_clk
53*91f16700Schasinglulu  *                  as a fixed value (MAX_PLATFORM_CLOCK)
54*91f16700Schasinglulu  *****************************************************************/
55*91f16700Schasinglulu static void set_speed(struct mmc *mmc, uint32_t clock)
56*91f16700Schasinglulu {
57*91f16700Schasinglulu 	/* sdhc_clk = (base clock) / [(SDCLKFS × 2) × (DVS +1)] */
58*91f16700Schasinglulu 
59*91f16700Schasinglulu 	uint32_t dvs = 1U;
60*91f16700Schasinglulu 	uint32_t sdclkfs = 2U;
61*91f16700Schasinglulu 	/* TBD - Change this to actual platform clock by reading via RCW */
62*91f16700Schasinglulu 	uint32_t base_clk = MAX_PLATFORM_CLOCK;
63*91f16700Schasinglulu 
64*91f16700Schasinglulu 	if (base_clk / 16 > clock) {
65*91f16700Schasinglulu 		for (sdclkfs = 2U; sdclkfs < 256U; sdclkfs *= 2U) {
66*91f16700Schasinglulu 			if ((base_clk / sdclkfs) <= (clock * 16)) {
67*91f16700Schasinglulu 				break;
68*91f16700Schasinglulu 			}
69*91f16700Schasinglulu 		}
70*91f16700Schasinglulu 	}
71*91f16700Schasinglulu 
72*91f16700Schasinglulu 	for (dvs = 1U; dvs <= 16U; dvs++) {
73*91f16700Schasinglulu 		if ((base_clk / (dvs * sdclkfs)) <= clock) {
74*91f16700Schasinglulu 			break;
75*91f16700Schasinglulu 		}
76*91f16700Schasinglulu 	}
77*91f16700Schasinglulu 
78*91f16700Schasinglulu 	sdclkfs >>= 1U;
79*91f16700Schasinglulu 	dvs -= 1U;
80*91f16700Schasinglulu 
81*91f16700Schasinglulu 	esdhc_out32(&mmc->esdhc_regs->sysctl,
82*91f16700Schasinglulu 			(ESDHC_SYSCTL_DTOCV(TIMEOUT_COUNTER_SDCLK_2_27) |
83*91f16700Schasinglulu 			 ESDHC_SYSCTL_SDCLKFS(sdclkfs) | ESDHC_SYSCTL_DVS(dvs) |
84*91f16700Schasinglulu 			 ESDHC_SYSCTL_SDCLKEN));
85*91f16700Schasinglulu }
86*91f16700Schasinglulu 
87*91f16700Schasinglulu /***************************************************************************
88*91f16700Schasinglulu  * Function    :    esdhc_init
89*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
90*91f16700Schasinglulu  *                  card_detect - flag to indicate if card insert needs
91*91f16700Schasinglulu  *                  to be detected or not. For SDHC2 controller, Card detect
92*91f16700Schasinglulu  *                  is not present, so this field will be false
93*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
94*91f16700Schasinglulu  * Description :    1. Set Initial Clock Speed
95*91f16700Schasinglulu  *                  2. Card Detect if not eMMC
96*91f16700Schasinglulu  *                  3. Enable Controller Clock
97*91f16700Schasinglulu  *                  4. Send 80 ticks for card to power up
98*91f16700Schasinglulu  *                  5. Set LE mode and Bus Width as 1 bit.
99*91f16700Schasinglulu  ***************************************************************************/
100*91f16700Schasinglulu static int esdhc_init(struct mmc *mmc, bool card_detect)
101*91f16700Schasinglulu {
102*91f16700Schasinglulu 	uint32_t val;
103*91f16700Schasinglulu 	uint64_t start_time;
104*91f16700Schasinglulu 
105*91f16700Schasinglulu 	/* Reset the entire host controller */
106*91f16700Schasinglulu 	val = esdhc_in32(&mmc->esdhc_regs->sysctl) | ESDHC_SYSCTL_RSTA;
107*91f16700Schasinglulu 	esdhc_out32(&mmc->esdhc_regs->sysctl, val);
108*91f16700Schasinglulu 
109*91f16700Schasinglulu 	/* Wait until the controller is available */
110*91f16700Schasinglulu 	start_time = get_timer_val(0);
111*91f16700Schasinglulu 	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
112*91f16700Schasinglulu 		val = esdhc_in32(&mmc->esdhc_regs->sysctl) & ESDHC_SYSCTL_RSTA;
113*91f16700Schasinglulu 		if (val == 0U) {
114*91f16700Schasinglulu 			break;
115*91f16700Schasinglulu 		}
116*91f16700Schasinglulu 	}
117*91f16700Schasinglulu 
118*91f16700Schasinglulu 	val = esdhc_in32(&mmc->esdhc_regs->sysctl) &
119*91f16700Schasinglulu 		(ESDHC_SYSCTL_RSTA);
120*91f16700Schasinglulu 	if (val != 0U) {
121*91f16700Schasinglulu 		ERROR("SD Reset failed\n");
122*91f16700Schasinglulu 		return ERROR_ESDHC_BUSY;
123*91f16700Schasinglulu 	}
124*91f16700Schasinglulu 
125*91f16700Schasinglulu 	/* Set initial clock speed */
126*91f16700Schasinglulu 	set_speed(mmc, CARD_IDENTIFICATION_FREQ);
127*91f16700Schasinglulu 
128*91f16700Schasinglulu 	if (card_detect) {
129*91f16700Schasinglulu 		/* Check CINS in prsstat register */
130*91f16700Schasinglulu 		val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
131*91f16700Schasinglulu 			ESDHC_PRSSTAT_CINS;
132*91f16700Schasinglulu 		if (val == 0) {
133*91f16700Schasinglulu 			ERROR("CINS not set in prsstat\n");
134*91f16700Schasinglulu 			return ERROR_ESDHC_CARD_DETECT_FAIL;
135*91f16700Schasinglulu 		}
136*91f16700Schasinglulu 	}
137*91f16700Schasinglulu 
138*91f16700Schasinglulu 	/* Enable controller clock */
139*91f16700Schasinglulu 	val = esdhc_in32(&mmc->esdhc_regs->sysctl) | ESDHC_SYSCTL_SDCLKEN;
140*91f16700Schasinglulu 	esdhc_out32(&mmc->esdhc_regs->sysctl, val);
141*91f16700Schasinglulu 
142*91f16700Schasinglulu 	/* Send 80 clock ticks for the card to power up */
143*91f16700Schasinglulu 	val = esdhc_in32(&mmc->esdhc_regs->sysctl) | ESDHC_SYSCTL_INITA;
144*91f16700Schasinglulu 	esdhc_out32(&mmc->esdhc_regs->sysctl, val);
145*91f16700Schasinglulu 
146*91f16700Schasinglulu 	start_time = get_timer_val(0);
147*91f16700Schasinglulu 	while (get_timer_val(start_time) < SD_TIMEOUT) {
148*91f16700Schasinglulu 		val = esdhc_in32(&mmc->esdhc_regs->sysctl) & ESDHC_SYSCTL_INITA;
149*91f16700Schasinglulu 		if (val != 0U) {
150*91f16700Schasinglulu 			break;
151*91f16700Schasinglulu 		}
152*91f16700Schasinglulu 	}
153*91f16700Schasinglulu 
154*91f16700Schasinglulu 	val = esdhc_in32(&mmc->esdhc_regs->sysctl) & ESDHC_SYSCTL_INITA;
155*91f16700Schasinglulu 	if (val == 0U) {
156*91f16700Schasinglulu 		ERROR("Failed to power up the card\n");
157*91f16700Schasinglulu 		return ERROR_ESDHC_CARD_DETECT_FAIL;
158*91f16700Schasinglulu 	}
159*91f16700Schasinglulu 
160*91f16700Schasinglulu 	INFO("Card detected successfully\n");
161*91f16700Schasinglulu 
162*91f16700Schasinglulu 	val = esdhc_in32(&mmc->esdhc_regs->proctl);
163*91f16700Schasinglulu 	val = val | (ESDHC_PROCTL_EMODE_LE | ESDHC_PROCTL_DTW_1BIT);
164*91f16700Schasinglulu 
165*91f16700Schasinglulu 	/* Set little endian mode, set bus width as 1-bit */
166*91f16700Schasinglulu 	esdhc_out32(&mmc->esdhc_regs->proctl, val);
167*91f16700Schasinglulu 
168*91f16700Schasinglulu 	/* Enable cache snooping for DMA transactions */
169*91f16700Schasinglulu 	val = esdhc_in32(&mmc->esdhc_regs->ctl) | ESDHC_DCR_SNOOP;
170*91f16700Schasinglulu 	esdhc_out32(&mmc->esdhc_regs->ctl, val);
171*91f16700Schasinglulu 
172*91f16700Schasinglulu 	return 0;
173*91f16700Schasinglulu }
174*91f16700Schasinglulu 
175*91f16700Schasinglulu /***************************************************************************
176*91f16700Schasinglulu  * Function    :    esdhc_send_cmd
177*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
178*91f16700Schasinglulu  *                  cmd - Command Number
179*91f16700Schasinglulu  *                  args - Command Args
180*91f16700Schasinglulu  * Return      :    SUCCESS is 0, or Error Code ( < 0)
181*91f16700Schasinglulu  * Description :    Updates the eSDHC registers cmdargs and xfertype
182*91f16700Schasinglulu  ***************************************************************************/
183*91f16700Schasinglulu static int esdhc_send_cmd(struct mmc *mmc, uint32_t cmd, uint32_t args)
184*91f16700Schasinglulu {
185*91f16700Schasinglulu 	uint32_t val;
186*91f16700Schasinglulu 	uint64_t start_time;
187*91f16700Schasinglulu 	uint32_t xfertyp = 0;
188*91f16700Schasinglulu 
189*91f16700Schasinglulu 	esdhc_out32(&mmc->esdhc_regs->irqstat, ESDHC_IRQSTAT_CLEAR_ALL);
190*91f16700Schasinglulu 
191*91f16700Schasinglulu 	/* Wait for the command line & data line to be free */
192*91f16700Schasinglulu 	/* (poll the CIHB,CDIHB bit of the present state register) */
193*91f16700Schasinglulu 	start_time = get_timer_val(0);
194*91f16700Schasinglulu 	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
195*91f16700Schasinglulu 		val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
196*91f16700Schasinglulu 			(ESDHC_PRSSTAT_CIHB | ESDHC_PRSSTAT_CDIHB);
197*91f16700Schasinglulu 		if (val == 0U) {
198*91f16700Schasinglulu 			break;
199*91f16700Schasinglulu 		}
200*91f16700Schasinglulu 	}
201*91f16700Schasinglulu 
202*91f16700Schasinglulu 	val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
203*91f16700Schasinglulu 		(ESDHC_PRSSTAT_CIHB | ESDHC_PRSSTAT_CDIHB);
204*91f16700Schasinglulu 	if (val != 0U) {
205*91f16700Schasinglulu 		ERROR("SD send cmd: Command Line or Data Line Busy cmd = %x\n",
206*91f16700Schasinglulu 				cmd);
207*91f16700Schasinglulu 		return ERROR_ESDHC_BUSY;
208*91f16700Schasinglulu 	}
209*91f16700Schasinglulu 
210*91f16700Schasinglulu 	if (cmd == CMD2 || cmd == CMD9) {
211*91f16700Schasinglulu 		xfertyp |= ESDHC_XFERTYP_RSPTYP_136;
212*91f16700Schasinglulu 	} else  if (cmd == CMD7 || (cmd == CMD6 && mmc->card.type == MMC_CARD)) {
213*91f16700Schasinglulu 		xfertyp |= ESDHC_XFERTYP_RSPTYP_48_BUSY;
214*91f16700Schasinglulu 	} else if (cmd != CMD0) {
215*91f16700Schasinglulu 		xfertyp |= ESDHC_XFERTYP_RSPTYP_48;
216*91f16700Schasinglulu 	}
217*91f16700Schasinglulu 
218*91f16700Schasinglulu 	if (cmd == CMD2 || cmd == CMD9) {
219*91f16700Schasinglulu 		xfertyp |= ESDHC_XFERTYP_CCCEN; /* Command index check enable */
220*91f16700Schasinglulu 	} else if ((cmd != CMD0) && (cmd != ACMD41) && (cmd != CMD1)) {
221*91f16700Schasinglulu 		xfertyp = xfertyp | ESDHC_XFERTYP_CCCEN | ESDHC_XFERTYP_CICEN;
222*91f16700Schasinglulu 	}
223*91f16700Schasinglulu 
224*91f16700Schasinglulu 	if ((cmd == CMD8 || cmd == CMD14 || cmd == CMD19) &&
225*91f16700Schasinglulu 			mmc->card.type == MMC_CARD) {
226*91f16700Schasinglulu 		xfertyp |=  ESDHC_XFERTYP_DPSEL;
227*91f16700Schasinglulu 		if (cmd != CMD19) {
228*91f16700Schasinglulu 			xfertyp |= ESDHC_XFERTYP_DTDSEL;
229*91f16700Schasinglulu 		}
230*91f16700Schasinglulu 	}
231*91f16700Schasinglulu 
232*91f16700Schasinglulu 	if (cmd == CMD6 || cmd == CMD17 || cmd == CMD18 || cmd == CMD24 ||
233*91f16700Schasinglulu 	    cmd == ACMD51) {
234*91f16700Schasinglulu 		if (!(mmc->card.type == MMC_CARD && cmd == CMD6)) {
235*91f16700Schasinglulu 			if (cmd == CMD24) {
236*91f16700Schasinglulu 				xfertyp |= ESDHC_XFERTYP_DPSEL;
237*91f16700Schasinglulu 			} else {
238*91f16700Schasinglulu 				xfertyp |= (ESDHC_XFERTYP_DPSEL |
239*91f16700Schasinglulu 					    ESDHC_XFERTYP_DTDSEL);
240*91f16700Schasinglulu 			}
241*91f16700Schasinglulu 		}
242*91f16700Schasinglulu 
243*91f16700Schasinglulu 		if (cmd == CMD18) {
244*91f16700Schasinglulu 			xfertyp |= ESDHC_XFERTYP_BCEN;
245*91f16700Schasinglulu 			if (mmc->dma_support != 0) {
246*91f16700Schasinglulu 				/* Set BCEN of XFERTYP */
247*91f16700Schasinglulu 				xfertyp |= ESDHC_XFERTYP_DMAEN;
248*91f16700Schasinglulu 			}
249*91f16700Schasinglulu 		}
250*91f16700Schasinglulu 
251*91f16700Schasinglulu 		if ((cmd == CMD17 || cmd == CMD24) && (mmc->dma_support != 0)) {
252*91f16700Schasinglulu 			xfertyp |= ESDHC_XFERTYP_DMAEN;
253*91f16700Schasinglulu 		}
254*91f16700Schasinglulu 	}
255*91f16700Schasinglulu 
256*91f16700Schasinglulu 	xfertyp |= ((cmd & 0x3F) << 24);
257*91f16700Schasinglulu 	esdhc_out32(&mmc->esdhc_regs->cmdarg, args);
258*91f16700Schasinglulu 	esdhc_out32(&mmc->esdhc_regs->xfertyp, xfertyp);
259*91f16700Schasinglulu 
260*91f16700Schasinglulu #ifdef NXP_SD_DEBUG
261*91f16700Schasinglulu 	INFO("cmd = %d\n", cmd);
262*91f16700Schasinglulu 	INFO("args = %x\n", args);
263*91f16700Schasinglulu 	INFO("xfertyp: = %x\n", xfertyp);
264*91f16700Schasinglulu #endif
265*91f16700Schasinglulu 	return 0;
266*91f16700Schasinglulu }
267*91f16700Schasinglulu 
268*91f16700Schasinglulu /***************************************************************************
269*91f16700Schasinglulu  * Function    :    esdhc_wait_response
270*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
271*91f16700Schasinglulu  *                  response - Value updated
272*91f16700Schasinglulu  * Return      :    SUCCESS - Response Received
273*91f16700Schasinglulu  *                  COMMUNICATION_ERROR - Command not Complete
274*91f16700Schasinglulu  *                  COMMAND_ERROR - CIE, CCE or CEBE  error
275*91f16700Schasinglulu  *                  RESP_TIMEOUT - CTOE error
276*91f16700Schasinglulu  * Description :    Checks for successful command completion.
277*91f16700Schasinglulu  *                  Clears the CC bit at the end.
278*91f16700Schasinglulu  ***************************************************************************/
279*91f16700Schasinglulu static int esdhc_wait_response(struct mmc *mmc, uint32_t *response)
280*91f16700Schasinglulu {
281*91f16700Schasinglulu 	uint32_t val;
282*91f16700Schasinglulu 	uint64_t start_time;
283*91f16700Schasinglulu 	uint32_t status = 0U;
284*91f16700Schasinglulu 
285*91f16700Schasinglulu 	/* Wait for the command to complete */
286*91f16700Schasinglulu 	start_time = get_timer_val(0);
287*91f16700Schasinglulu 	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
288*91f16700Schasinglulu 		val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_CC;
289*91f16700Schasinglulu 		if (val != 0U) {
290*91f16700Schasinglulu 			break;
291*91f16700Schasinglulu 		}
292*91f16700Schasinglulu 	}
293*91f16700Schasinglulu 
294*91f16700Schasinglulu 	val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_CC;
295*91f16700Schasinglulu 	if (val == 0U) {
296*91f16700Schasinglulu 		ERROR("%s:IRQSTAT Cmd not complete(CC not set)\n", __func__);
297*91f16700Schasinglulu 		return ERROR_ESDHC_COMMUNICATION_ERROR;
298*91f16700Schasinglulu 	}
299*91f16700Schasinglulu 
300*91f16700Schasinglulu 	status = esdhc_in32(&mmc->esdhc_regs->irqstat);
301*91f16700Schasinglulu 
302*91f16700Schasinglulu 	/* Check whether the interrupt is a CRC, CTOE or CIE error */
303*91f16700Schasinglulu 	if ((status & (ESDHC_IRQSTAT_CIE | ESDHC_IRQSTAT_CEBE |
304*91f16700Schasinglulu 				ESDHC_IRQSTAT_CCE)) != 0) {
305*91f16700Schasinglulu 		ERROR("%s: IRQSTAT CRC, CEBE or CIE error = %x\n",
306*91f16700Schasinglulu 							__func__, status);
307*91f16700Schasinglulu 		return COMMAND_ERROR;
308*91f16700Schasinglulu 	}
309*91f16700Schasinglulu 
310*91f16700Schasinglulu 	if ((status & ESDHC_IRQSTAT_CTOE) != 0) {
311*91f16700Schasinglulu 		INFO("%s: IRQSTAT CTOE set = %x\n", __func__, status);
312*91f16700Schasinglulu 		return RESP_TIMEOUT;
313*91f16700Schasinglulu 	}
314*91f16700Schasinglulu 
315*91f16700Schasinglulu 	if ((status & ESDHC_IRQSTAT_DMAE) != 0) {
316*91f16700Schasinglulu 		ERROR("%s: IRQSTAT DMAE set = %x\n", __func__, status);
317*91f16700Schasinglulu 		return ERROR_ESDHC_DMA_ERROR;
318*91f16700Schasinglulu 	}
319*91f16700Schasinglulu 
320*91f16700Schasinglulu 	if (response != NULL) {
321*91f16700Schasinglulu 		/* Get response values from eSDHC CMDRSPx registers. */
322*91f16700Schasinglulu 		response[0] = esdhc_in32(&mmc->esdhc_regs->cmdrsp[0]);
323*91f16700Schasinglulu 		response[1] = esdhc_in32(&mmc->esdhc_regs->cmdrsp[1]);
324*91f16700Schasinglulu 		response[2] = esdhc_in32(&mmc->esdhc_regs->cmdrsp[2]);
325*91f16700Schasinglulu 		response[3] = esdhc_in32(&mmc->esdhc_regs->cmdrsp[3]);
326*91f16700Schasinglulu #ifdef NXP_SD_DEBUG
327*91f16700Schasinglulu 		INFO("Resp R1 R2 R3 R4\n");
328*91f16700Schasinglulu 		INFO("Resp R1 = %x\n", response[0]);
329*91f16700Schasinglulu 		INFO("R2 = %x\n", response[1]);
330*91f16700Schasinglulu 		INFO("R3 = %x\n", response[2]);
331*91f16700Schasinglulu 		INFO("R4 = %x\n", response[3]);
332*91f16700Schasinglulu 		INFO("\n");
333*91f16700Schasinglulu #endif
334*91f16700Schasinglulu 	}
335*91f16700Schasinglulu 
336*91f16700Schasinglulu 	/* Clear the CC bit - w1c */
337*91f16700Schasinglulu 	val = esdhc_in32(&mmc->esdhc_regs->irqstat) | ESDHC_IRQSTAT_CC;
338*91f16700Schasinglulu 	esdhc_out32(&mmc->esdhc_regs->irqstat, val);
339*91f16700Schasinglulu 
340*91f16700Schasinglulu 	return 0;
341*91f16700Schasinglulu }
342*91f16700Schasinglulu 
343*91f16700Schasinglulu /***************************************************************************
344*91f16700Schasinglulu  * Function    :    mmc_switch_to_high_frquency
345*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
346*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
347*91f16700Schasinglulu  * Description :    mmc card below ver 4.0 does not support high speed
348*91f16700Schasinglulu  *                  freq = 20 MHz
349*91f16700Schasinglulu  *                  Send CMD6 (CMD_SWITCH_FUNC) With args 0x03B90100
350*91f16700Schasinglulu  *                  Send CMD13 (CMD_SEND_STATUS)
351*91f16700Schasinglulu  *                  if SWITCH Error, freq = 26 MHz
352*91f16700Schasinglulu  *                  if no error, freq = 52 MHz
353*91f16700Schasinglulu  ***************************************************************************/
354*91f16700Schasinglulu static int mmc_switch_to_high_frquency(struct mmc *mmc)
355*91f16700Schasinglulu {
356*91f16700Schasinglulu 	int error;
357*91f16700Schasinglulu 	uint32_t response[4];
358*91f16700Schasinglulu 	uint64_t start_time;
359*91f16700Schasinglulu 
360*91f16700Schasinglulu 	mmc->card.bus_freq = MMC_SS_20MHZ;
361*91f16700Schasinglulu 	/* mmc card below ver 4.0 does not support high speed */
362*91f16700Schasinglulu 	if (mmc->card.version < MMC_CARD_VERSION_4_X) {
363*91f16700Schasinglulu 		return 0;
364*91f16700Schasinglulu 	}
365*91f16700Schasinglulu 
366*91f16700Schasinglulu 	/* send switch cmd to change the card to High speed */
367*91f16700Schasinglulu 	error = esdhc_send_cmd(mmc, CMD_SWITCH_FUNC, SET_EXT_CSD_HS_TIMING);
368*91f16700Schasinglulu 	if (error != 0) {
369*91f16700Schasinglulu 		return error;
370*91f16700Schasinglulu 	}
371*91f16700Schasinglulu 	error = esdhc_wait_response(mmc, response);
372*91f16700Schasinglulu 	if (error != 0) {
373*91f16700Schasinglulu 		return error;
374*91f16700Schasinglulu 	}
375*91f16700Schasinglulu 
376*91f16700Schasinglulu 	start_time = get_timer_val(0);
377*91f16700Schasinglulu 	do {
378*91f16700Schasinglulu 		/* check the status for which error */
379*91f16700Schasinglulu 		error = esdhc_send_cmd(mmc,
380*91f16700Schasinglulu 				CMD_SEND_STATUS, mmc->card.rca << 16);
381*91f16700Schasinglulu 		if (error != 0) {
382*91f16700Schasinglulu 			return error;
383*91f16700Schasinglulu 		}
384*91f16700Schasinglulu 
385*91f16700Schasinglulu 		error = esdhc_wait_response(mmc, response);
386*91f16700Schasinglulu 		if (error != 0) {
387*91f16700Schasinglulu 			return error;
388*91f16700Schasinglulu 		}
389*91f16700Schasinglulu 	} while (((response[0] & SWITCH_ERROR) != 0) &&
390*91f16700Schasinglulu 			(get_timer_val(start_time) < SD_TIMEOUT));
391*91f16700Schasinglulu 
392*91f16700Schasinglulu 	/* Check for the present state of card */
393*91f16700Schasinglulu 	if ((response[0] & SWITCH_ERROR) != 0) {
394*91f16700Schasinglulu 		mmc->card.bus_freq = MMC_HS_26MHZ;
395*91f16700Schasinglulu 	} else {
396*91f16700Schasinglulu 		mmc->card.bus_freq = MMC_HS_52MHZ;
397*91f16700Schasinglulu 	}
398*91f16700Schasinglulu 
399*91f16700Schasinglulu 	return 0;
400*91f16700Schasinglulu }
401*91f16700Schasinglulu 
402*91f16700Schasinglulu /***************************************************************************
403*91f16700Schasinglulu  * Function    :    esdhc_set_data_attributes
404*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
405*91f16700Schasinglulu  *                  blkcnt
406*91f16700Schasinglulu  *                  blklen
407*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
408*91f16700Schasinglulu  * Description :    Set block attributes and watermark level register
409*91f16700Schasinglulu  ***************************************************************************/
410*91f16700Schasinglulu static int esdhc_set_data_attributes(struct mmc *mmc, uint32_t *dest_ptr,
411*91f16700Schasinglulu 		uint32_t blkcnt, uint32_t blklen)
412*91f16700Schasinglulu {
413*91f16700Schasinglulu 	uint32_t val;
414*91f16700Schasinglulu 	uint64_t start_time;
415*91f16700Schasinglulu 	uint32_t wml;
416*91f16700Schasinglulu 	uint32_t wl;
417*91f16700Schasinglulu 	uint32_t dst = (uint32_t)((uint64_t)(dest_ptr));
418*91f16700Schasinglulu 
419*91f16700Schasinglulu 	/* set blkattr when no transactions are executing */
420*91f16700Schasinglulu 	start_time = get_timer_val(0);
421*91f16700Schasinglulu 	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
422*91f16700Schasinglulu 		val = esdhc_in32(&mmc->esdhc_regs->prsstat) & ESDHC_PRSSTAT_DLA;
423*91f16700Schasinglulu 		if (val == 0U) {
424*91f16700Schasinglulu 			break;
425*91f16700Schasinglulu 		}
426*91f16700Schasinglulu 	}
427*91f16700Schasinglulu 
428*91f16700Schasinglulu 	val = esdhc_in32(&mmc->esdhc_regs->prsstat) & ESDHC_PRSSTAT_DLA;
429*91f16700Schasinglulu 	if (val != 0U) {
430*91f16700Schasinglulu 		ERROR("%s: Data line active.Can't set attribute\n", __func__);
431*91f16700Schasinglulu 		return ERROR_ESDHC_COMMUNICATION_ERROR;
432*91f16700Schasinglulu 	}
433*91f16700Schasinglulu 
434*91f16700Schasinglulu 	wml = esdhc_in32(&mmc->esdhc_regs->wml);
435*91f16700Schasinglulu 	wml &= ~(ESDHC_WML_WR_BRST_MASK | ESDHC_WML_RD_BRST_MASK |
436*91f16700Schasinglulu 			ESDHC_WML_RD_WML_MASK | ESDHC_WML_WR_WML_MASK);
437*91f16700Schasinglulu 
438*91f16700Schasinglulu 	if ((mmc->dma_support != 0) && (dest_ptr != NULL)) {
439*91f16700Schasinglulu 		/* Set burst length to 128 bytes */
440*91f16700Schasinglulu 		esdhc_out32(&mmc->esdhc_regs->wml,
441*91f16700Schasinglulu 				wml | ESDHC_WML_WR_BRST(BURST_128_BYTES));
442*91f16700Schasinglulu 		esdhc_out32(&mmc->esdhc_regs->wml,
443*91f16700Schasinglulu 				wml | ESDHC_WML_RD_BRST(BURST_128_BYTES));
444*91f16700Schasinglulu 
445*91f16700Schasinglulu 		/* Set DMA System Destination Address */
446*91f16700Schasinglulu 		esdhc_out32(&mmc->esdhc_regs->dsaddr, dst);
447*91f16700Schasinglulu 	} else {
448*91f16700Schasinglulu 		wl = (blklen >= BLOCK_LEN_512) ?
449*91f16700Schasinglulu 			WML_512_BYTES : ((blklen + 3) / 4);
450*91f16700Schasinglulu 		/* Set 'Read Water Mark Level' register */
451*91f16700Schasinglulu 		esdhc_out32(&mmc->esdhc_regs->wml, wml | ESDHC_WML_RD_WML(wl));
452*91f16700Schasinglulu 	}
453*91f16700Schasinglulu 
454*91f16700Schasinglulu 	/* Configure block Attributes register */
455*91f16700Schasinglulu 	esdhc_out32(&mmc->esdhc_regs->blkattr,
456*91f16700Schasinglulu 		ESDHC_BLKATTR_BLKCNT(blkcnt) | ESDHC_BLKATTR_BLKSZE(blklen));
457*91f16700Schasinglulu 
458*91f16700Schasinglulu 	mmc->block_len = blklen;
459*91f16700Schasinglulu 
460*91f16700Schasinglulu 	return 0;
461*91f16700Schasinglulu }
462*91f16700Schasinglulu 
463*91f16700Schasinglulu /***************************************************************************
464*91f16700Schasinglulu  * Function    :    esdhc_read_data_nodma
465*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
466*91f16700Schasinglulu  *                  dest_ptr - Buffer where read data is to be copied
467*91f16700Schasinglulu  *                  len - Length of Data to be read
468*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
469*91f16700Schasinglulu  * Description :    Read data from the sdhc buffer without using DMA
470*91f16700Schasinglulu  *                  and using polling mode
471*91f16700Schasinglulu  ***************************************************************************/
472*91f16700Schasinglulu static int esdhc_read_data_nodma(struct mmc *mmc, void *dest_ptr, uint32_t len)
473*91f16700Schasinglulu {
474*91f16700Schasinglulu 	uint32_t i = 0U;
475*91f16700Schasinglulu 	uint32_t status;
476*91f16700Schasinglulu 	uint32_t num_blocks;
477*91f16700Schasinglulu 	uint32_t *dst = (uint32_t *)dest_ptr;
478*91f16700Schasinglulu 	uint32_t val;
479*91f16700Schasinglulu 	uint64_t start_time;
480*91f16700Schasinglulu 
481*91f16700Schasinglulu 	num_blocks = len / mmc->block_len;
482*91f16700Schasinglulu 
483*91f16700Schasinglulu 	while ((num_blocks--) != 0U) {
484*91f16700Schasinglulu 
485*91f16700Schasinglulu 		start_time = get_timer_val(0);
486*91f16700Schasinglulu 		while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
487*91f16700Schasinglulu 			val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
488*91f16700Schasinglulu 				ESDHC_PRSSTAT_BREN;
489*91f16700Schasinglulu 			if (val != 0U) {
490*91f16700Schasinglulu 				break;
491*91f16700Schasinglulu 			}
492*91f16700Schasinglulu 		}
493*91f16700Schasinglulu 
494*91f16700Schasinglulu 		val = esdhc_in32(&mmc->esdhc_regs->prsstat)
495*91f16700Schasinglulu 			& ESDHC_PRSSTAT_BREN;
496*91f16700Schasinglulu 		if (val == 0U) {
497*91f16700Schasinglulu 			return ERROR_ESDHC_COMMUNICATION_ERROR;
498*91f16700Schasinglulu 		}
499*91f16700Schasinglulu 
500*91f16700Schasinglulu 		for (i = 0U, status = esdhc_in32(&mmc->esdhc_regs->irqstat);
501*91f16700Schasinglulu 				i < mmc->block_len / 4;    i++, dst++) {
502*91f16700Schasinglulu 			/* get data from data port */
503*91f16700Schasinglulu 			val = mmio_read_32(
504*91f16700Schasinglulu 					(uintptr_t)&mmc->esdhc_regs->datport);
505*91f16700Schasinglulu 			esdhc_out32(dst, val);
506*91f16700Schasinglulu 			/* Increment destination pointer */
507*91f16700Schasinglulu 			status = esdhc_in32(&mmc->esdhc_regs->irqstat);
508*91f16700Schasinglulu 		}
509*91f16700Schasinglulu 		/* Check whether the interrupt is an DTOE/DCE/DEBE */
510*91f16700Schasinglulu 		if ((status & (ESDHC_IRQSTAT_DTOE | ESDHC_IRQSTAT_DCE |
511*91f16700Schasinglulu 					ESDHC_IRQSTAT_DEBE)) != 0) {
512*91f16700Schasinglulu 			ERROR("SD read error - DTOE, DCE, DEBE bit set = %x\n",
513*91f16700Schasinglulu 									status);
514*91f16700Schasinglulu 			return ERROR_ESDHC_COMMUNICATION_ERROR;
515*91f16700Schasinglulu 		}
516*91f16700Schasinglulu 	}
517*91f16700Schasinglulu 
518*91f16700Schasinglulu 	/* Wait for TC */
519*91f16700Schasinglulu 
520*91f16700Schasinglulu 	start_time = get_timer_val(0);
521*91f16700Schasinglulu 	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
522*91f16700Schasinglulu 		val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_TC;
523*91f16700Schasinglulu 		if (val != 0U) {
524*91f16700Schasinglulu 			break;
525*91f16700Schasinglulu 		}
526*91f16700Schasinglulu 	}
527*91f16700Schasinglulu 
528*91f16700Schasinglulu 	val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_TC;
529*91f16700Schasinglulu 	if (val == 0U) {
530*91f16700Schasinglulu 		ERROR("SD read timeout: Transfer bit not set in IRQSTAT\n");
531*91f16700Schasinglulu 		return ERROR_ESDHC_COMMUNICATION_ERROR;
532*91f16700Schasinglulu 	}
533*91f16700Schasinglulu 
534*91f16700Schasinglulu 	return 0;
535*91f16700Schasinglulu }
536*91f16700Schasinglulu 
537*91f16700Schasinglulu /***************************************************************************
538*91f16700Schasinglulu  * Function    :    esdhc_write_data_nodma
539*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
540*91f16700Schasinglulu  *                  src_ptr - Buffer where data is copied from
541*91f16700Schasinglulu  *                  len - Length of Data to be written
542*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
543*91f16700Schasinglulu  * Description :    Write data to the sdhc buffer without using DMA
544*91f16700Schasinglulu  *                  and using polling mode
545*91f16700Schasinglulu  ***************************************************************************/
546*91f16700Schasinglulu static int esdhc_write_data_nodma(struct mmc *mmc, void *src_ptr, uint32_t len)
547*91f16700Schasinglulu {
548*91f16700Schasinglulu 	uint32_t i = 0U;
549*91f16700Schasinglulu 	uint32_t status;
550*91f16700Schasinglulu 	uint32_t num_blocks;
551*91f16700Schasinglulu 	uint32_t *src = (uint32_t *)src_ptr;
552*91f16700Schasinglulu 	uint32_t val;
553*91f16700Schasinglulu 	uint64_t start_time;
554*91f16700Schasinglulu 
555*91f16700Schasinglulu 	num_blocks = len / mmc->block_len;
556*91f16700Schasinglulu 
557*91f16700Schasinglulu 	while ((num_blocks--) != 0U) {
558*91f16700Schasinglulu 		start_time = get_timer_val(0);
559*91f16700Schasinglulu 		while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
560*91f16700Schasinglulu 			val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
561*91f16700Schasinglulu 					 ESDHC_PRSSTAT_BWEN;
562*91f16700Schasinglulu 			if (val != 0U) {
563*91f16700Schasinglulu 				break;
564*91f16700Schasinglulu 			}
565*91f16700Schasinglulu 		}
566*91f16700Schasinglulu 
567*91f16700Schasinglulu 		val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
568*91f16700Schasinglulu 				 ESDHC_PRSSTAT_BWEN;
569*91f16700Schasinglulu 		if (val == 0U) {
570*91f16700Schasinglulu 			return ERROR_ESDHC_COMMUNICATION_ERROR;
571*91f16700Schasinglulu 		}
572*91f16700Schasinglulu 
573*91f16700Schasinglulu 		for (i = 0U, status = esdhc_in32(&mmc->esdhc_regs->irqstat);
574*91f16700Schasinglulu 		     i < mmc->block_len / 4; i++, src++) {
575*91f16700Schasinglulu 			val = esdhc_in32(src);
576*91f16700Schasinglulu 			/* put data to data port */
577*91f16700Schasinglulu 			mmio_write_32((uintptr_t)&mmc->esdhc_regs->datport,
578*91f16700Schasinglulu 				      val);
579*91f16700Schasinglulu 			/* Increment source pointer */
580*91f16700Schasinglulu 			status = esdhc_in32(&mmc->esdhc_regs->irqstat);
581*91f16700Schasinglulu 		}
582*91f16700Schasinglulu 		/* Check whether the interrupt is an DTOE/DCE/DEBE */
583*91f16700Schasinglulu 		if ((status & (ESDHC_IRQSTAT_DTOE | ESDHC_IRQSTAT_DCE |
584*91f16700Schasinglulu 					ESDHC_IRQSTAT_DEBE)) != 0) {
585*91f16700Schasinglulu 			ERROR("SD write error - DTOE, DCE, DEBE bit set = %x\n",
586*91f16700Schasinglulu 			      status);
587*91f16700Schasinglulu 			return ERROR_ESDHC_COMMUNICATION_ERROR;
588*91f16700Schasinglulu 		}
589*91f16700Schasinglulu 	}
590*91f16700Schasinglulu 
591*91f16700Schasinglulu 	/* Wait for TC */
592*91f16700Schasinglulu 	start_time = get_timer_val(0);
593*91f16700Schasinglulu 	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
594*91f16700Schasinglulu 		val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_TC;
595*91f16700Schasinglulu 		if (val != 0U) {
596*91f16700Schasinglulu 			break;
597*91f16700Schasinglulu 		}
598*91f16700Schasinglulu 	}
599*91f16700Schasinglulu 
600*91f16700Schasinglulu 	val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_TC;
601*91f16700Schasinglulu 	if (val == 0U) {
602*91f16700Schasinglulu 		ERROR("SD write timeout: Transfer bit not set in IRQSTAT\n");
603*91f16700Schasinglulu 		return ERROR_ESDHC_COMMUNICATION_ERROR;
604*91f16700Schasinglulu 	}
605*91f16700Schasinglulu 
606*91f16700Schasinglulu 	return 0;
607*91f16700Schasinglulu }
608*91f16700Schasinglulu 
609*91f16700Schasinglulu /***************************************************************************
610*91f16700Schasinglulu  * Function    :    esdhc_read_data_dma
611*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
612*91f16700Schasinglulu  *                  len - Length of Data to be read
613*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
614*91f16700Schasinglulu  * Description :    Read data from the sd card using DMA.
615*91f16700Schasinglulu  ***************************************************************************/
616*91f16700Schasinglulu static int esdhc_read_data_dma(struct mmc *mmc, uint32_t len)
617*91f16700Schasinglulu {
618*91f16700Schasinglulu 	uint32_t status;
619*91f16700Schasinglulu 	uint32_t tblk;
620*91f16700Schasinglulu 	uint64_t start_time;
621*91f16700Schasinglulu 
622*91f16700Schasinglulu 	tblk = SD_BLOCK_TIMEOUT * (len / mmc->block_len);
623*91f16700Schasinglulu 
624*91f16700Schasinglulu 	start_time = get_timer_val(0);
625*91f16700Schasinglulu 
626*91f16700Schasinglulu 	/* poll till TC is set */
627*91f16700Schasinglulu 	do {
628*91f16700Schasinglulu 		status = esdhc_in32(&mmc->esdhc_regs->irqstat);
629*91f16700Schasinglulu 
630*91f16700Schasinglulu 		if ((status & (ESDHC_IRQSTAT_DEBE | ESDHC_IRQSTAT_DCE
631*91f16700Schasinglulu 					| ESDHC_IRQSTAT_DTOE)) != 0) {
632*91f16700Schasinglulu 			ERROR("SD read error - DTOE, DCE, DEBE bit set = %x\n",
633*91f16700Schasinglulu 								 status);
634*91f16700Schasinglulu 			return ERROR_ESDHC_COMMUNICATION_ERROR;
635*91f16700Schasinglulu 		}
636*91f16700Schasinglulu 
637*91f16700Schasinglulu 		if ((status & ESDHC_IRQSTAT_DMAE) != 0) {
638*91f16700Schasinglulu 			ERROR("SD read error - DMA error = %x\n", status);
639*91f16700Schasinglulu 			return ERROR_ESDHC_DMA_ERROR;
640*91f16700Schasinglulu 		}
641*91f16700Schasinglulu 
642*91f16700Schasinglulu 	} while (((status & ESDHC_IRQSTAT_TC) == 0) &&
643*91f16700Schasinglulu 		((esdhc_in32(&mmc->esdhc_regs->prsstat) & ESDHC_PRSSTAT_DLA) != 0) &&
644*91f16700Schasinglulu 		(get_timer_val(start_time) < SD_TIMEOUT_HIGH + tblk));
645*91f16700Schasinglulu 
646*91f16700Schasinglulu 	if (get_timer_val(start_time) > SD_TIMEOUT_HIGH + tblk) {
647*91f16700Schasinglulu 		ERROR("SD read DMA timeout\n");
648*91f16700Schasinglulu 		return ERROR_ESDHC_COMMUNICATION_ERROR;
649*91f16700Schasinglulu 	}
650*91f16700Schasinglulu 
651*91f16700Schasinglulu 	return 0;
652*91f16700Schasinglulu }
653*91f16700Schasinglulu 
654*91f16700Schasinglulu /***************************************************************************
655*91f16700Schasinglulu  * Function    :    esdhc_write_data_dma
656*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
657*91f16700Schasinglulu  *                  len - Length of Data to be written
658*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
659*91f16700Schasinglulu  * Description :    Write data to the sd card using DMA.
660*91f16700Schasinglulu  ***************************************************************************/
661*91f16700Schasinglulu static int esdhc_write_data_dma(struct mmc *mmc, uint32_t len)
662*91f16700Schasinglulu {
663*91f16700Schasinglulu 	uint32_t status;
664*91f16700Schasinglulu 	uint32_t tblk;
665*91f16700Schasinglulu 	uint64_t start_time;
666*91f16700Schasinglulu 
667*91f16700Schasinglulu 	tblk = SD_BLOCK_TIMEOUT * (len / mmc->block_len);
668*91f16700Schasinglulu 
669*91f16700Schasinglulu 	start_time = get_timer_val(0);
670*91f16700Schasinglulu 
671*91f16700Schasinglulu 	/* poll till TC is set */
672*91f16700Schasinglulu 	do {
673*91f16700Schasinglulu 		status = esdhc_in32(&mmc->esdhc_regs->irqstat);
674*91f16700Schasinglulu 
675*91f16700Schasinglulu 		if ((status & (ESDHC_IRQSTAT_DEBE | ESDHC_IRQSTAT_DCE
676*91f16700Schasinglulu 					| ESDHC_IRQSTAT_DTOE)) != 0) {
677*91f16700Schasinglulu 			ERROR("SD write error - DTOE, DCE, DEBE bit set = %x\n",
678*91f16700Schasinglulu 			      status);
679*91f16700Schasinglulu 			return ERROR_ESDHC_COMMUNICATION_ERROR;
680*91f16700Schasinglulu 		}
681*91f16700Schasinglulu 
682*91f16700Schasinglulu 		if ((status & ESDHC_IRQSTAT_DMAE) != 0) {
683*91f16700Schasinglulu 			ERROR("SD write error - DMA error = %x\n", status);
684*91f16700Schasinglulu 			return ERROR_ESDHC_DMA_ERROR;
685*91f16700Schasinglulu 		}
686*91f16700Schasinglulu 	} while (((status & ESDHC_IRQSTAT_TC) == 0) &&
687*91f16700Schasinglulu 		((esdhc_in32(&mmc->esdhc_regs->prsstat) & ESDHC_PRSSTAT_DLA) != 0) &&
688*91f16700Schasinglulu 		(get_timer_val(start_time) < SD_TIMEOUT_HIGH + tblk));
689*91f16700Schasinglulu 
690*91f16700Schasinglulu 	if (get_timer_val(start_time) > SD_TIMEOUT_HIGH + tblk) {
691*91f16700Schasinglulu 		ERROR("SD write DMA timeout\n");
692*91f16700Schasinglulu 		return ERROR_ESDHC_COMMUNICATION_ERROR;
693*91f16700Schasinglulu 	}
694*91f16700Schasinglulu 
695*91f16700Schasinglulu 	return 0;
696*91f16700Schasinglulu }
697*91f16700Schasinglulu 
698*91f16700Schasinglulu /***************************************************************************
699*91f16700Schasinglulu  * Function    :    esdhc_read_data
700*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
701*91f16700Schasinglulu  *                  dest_ptr - Buffer where read data is to be copied
702*91f16700Schasinglulu  *                  len - Length of Data to be read
703*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
704*91f16700Schasinglulu  * Description :    Calls esdhc_read_data_nodma and clear interrupt status
705*91f16700Schasinglulu  ***************************************************************************/
706*91f16700Schasinglulu int esdhc_read_data(struct mmc *mmc, void *dest_ptr, uint32_t len)
707*91f16700Schasinglulu {
708*91f16700Schasinglulu 	int ret;
709*91f16700Schasinglulu 
710*91f16700Schasinglulu 	if (mmc->dma_support && len > 64) {
711*91f16700Schasinglulu 		ret = esdhc_read_data_dma(mmc, len);
712*91f16700Schasinglulu 	} else {
713*91f16700Schasinglulu 		ret = esdhc_read_data_nodma(mmc, dest_ptr, len);
714*91f16700Schasinglulu 	}
715*91f16700Schasinglulu 
716*91f16700Schasinglulu 	/* clear interrupt status */
717*91f16700Schasinglulu 	esdhc_out32(&mmc->esdhc_regs->irqstat, ESDHC_IRQSTAT_CLEAR_ALL);
718*91f16700Schasinglulu 
719*91f16700Schasinglulu 	return ret;
720*91f16700Schasinglulu }
721*91f16700Schasinglulu 
722*91f16700Schasinglulu /***************************************************************************
723*91f16700Schasinglulu  * Function    :    esdhc_write_data
724*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
725*91f16700Schasinglulu  *                  src_ptr - Buffer where data is copied from
726*91f16700Schasinglulu  *                  len - Length of Data to be written
727*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
728*91f16700Schasinglulu  * Description :    Calls esdhc_write_data_nodma and clear interrupt status
729*91f16700Schasinglulu  ***************************************************************************/
730*91f16700Schasinglulu int esdhc_write_data(struct mmc *mmc, void *src_ptr, uint32_t len)
731*91f16700Schasinglulu {
732*91f16700Schasinglulu 	int ret;
733*91f16700Schasinglulu 
734*91f16700Schasinglulu 	if (mmc->dma_support && len > 64) {
735*91f16700Schasinglulu 		ret = esdhc_write_data_dma(mmc, len);
736*91f16700Schasinglulu 	} else {
737*91f16700Schasinglulu 		ret = esdhc_write_data_nodma(mmc, src_ptr, len);
738*91f16700Schasinglulu 	}
739*91f16700Schasinglulu 
740*91f16700Schasinglulu 	/* clear interrupt status */
741*91f16700Schasinglulu 	esdhc_out32(&mmc->esdhc_regs->irqstat, ESDHC_IRQSTAT_CLEAR_ALL);
742*91f16700Schasinglulu 
743*91f16700Schasinglulu 	return ret;
744*91f16700Schasinglulu }
745*91f16700Schasinglulu 
746*91f16700Schasinglulu /***************************************************************************
747*91f16700Schasinglulu  * Function    :    sd_switch_to_high_freq
748*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
749*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
750*91f16700Schasinglulu  * Description :    1. Send ACMD51 (CMD_SEND_SCR)
751*91f16700Schasinglulu  *                  2. Read the SCR to check if card supports higher freq
752*91f16700Schasinglulu  *                  3. check version from SCR
753*91f16700Schasinglulu  *                  4. If SD 1.0, return (no Switch) freq = 25 MHz.
754*91f16700Schasinglulu  *                  5. Send CMD6 (CMD_SWITCH_FUNC) with args 0x00FFFFF1 to
755*91f16700Schasinglulu  *                     check the status of switch func
756*91f16700Schasinglulu  *                  6. Send CMD6 (CMD_SWITCH_FUNC) With args 0x80FFFFF1 to
757*91f16700Schasinglulu  *                     switch to high frequency = 50 Mhz
758*91f16700Schasinglulu  ***************************************************************************/
759*91f16700Schasinglulu static int sd_switch_to_high_freq(struct mmc *mmc)
760*91f16700Schasinglulu {
761*91f16700Schasinglulu 	int err;
762*91f16700Schasinglulu 	uint8_t scr[8];
763*91f16700Schasinglulu 	uint8_t status[64];
764*91f16700Schasinglulu 	uint32_t response[4];
765*91f16700Schasinglulu 	uint32_t version;
766*91f16700Schasinglulu 	uint32_t count;
767*91f16700Schasinglulu 	uint32_t sd_versions[] = {SD_CARD_VERSION_1_0, SD_CARD_VERSION_1_10,
768*91f16700Schasinglulu 		SD_CARD_VERSION_2_0};
769*91f16700Schasinglulu 
770*91f16700Schasinglulu 	mmc->card.bus_freq = SD_SS_25MHZ;
771*91f16700Schasinglulu 	/* Send Application command */
772*91f16700Schasinglulu 	err = esdhc_send_cmd(mmc, CMD_APP_CMD, mmc->card.rca << 16);
773*91f16700Schasinglulu 	if (err != 0) {
774*91f16700Schasinglulu 		return err;
775*91f16700Schasinglulu 	}
776*91f16700Schasinglulu 
777*91f16700Schasinglulu 	err = esdhc_wait_response(mmc, response);
778*91f16700Schasinglulu 	if (err != 0) {
779*91f16700Schasinglulu 		return err;
780*91f16700Schasinglulu 	}
781*91f16700Schasinglulu 
782*91f16700Schasinglulu 	esdhc_set_data_attributes(mmc, NULL, 1, 8);
783*91f16700Schasinglulu 	/* Read the SCR to find out if this card supports higher speeds */
784*91f16700Schasinglulu 	err = esdhc_send_cmd(mmc, CMD_SEND_SCR,  mmc->card.rca << 16);
785*91f16700Schasinglulu 	if (err != 0) {
786*91f16700Schasinglulu 		return err;
787*91f16700Schasinglulu 	}
788*91f16700Schasinglulu 	err = esdhc_wait_response(mmc, response);
789*91f16700Schasinglulu 	if (err != 0) {
790*91f16700Schasinglulu 		return err;
791*91f16700Schasinglulu 	}
792*91f16700Schasinglulu 
793*91f16700Schasinglulu 	/* read 8 bytes of scr data */
794*91f16700Schasinglulu 	err = esdhc_read_data(mmc, scr, 8U);
795*91f16700Schasinglulu 	if (err != 0) {
796*91f16700Schasinglulu 		return ERROR_ESDHC_COMMUNICATION_ERROR;
797*91f16700Schasinglulu 	}
798*91f16700Schasinglulu 
799*91f16700Schasinglulu 	/* check version from SCR */
800*91f16700Schasinglulu 	version = scr[0] & U(0xF);
801*91f16700Schasinglulu 	if (version <= 2U) {
802*91f16700Schasinglulu 		mmc->card.version = sd_versions[version];
803*91f16700Schasinglulu 	} else {
804*91f16700Schasinglulu 		mmc->card.version = SD_CARD_VERSION_2_0;
805*91f16700Schasinglulu 	}
806*91f16700Schasinglulu 
807*91f16700Schasinglulu 	/* does not support switch func */
808*91f16700Schasinglulu 	if (mmc->card.version == SD_CARD_VERSION_1_0) {
809*91f16700Schasinglulu 		return 0;
810*91f16700Schasinglulu 	}
811*91f16700Schasinglulu 
812*91f16700Schasinglulu 	/* read 64 bytes of status */
813*91f16700Schasinglulu 	esdhc_set_data_attributes(mmc, NULL, 1U, 64U);
814*91f16700Schasinglulu 
815*91f16700Schasinglulu 	/* check the status of switch func */
816*91f16700Schasinglulu 	for (count = 0U; count < 4U; count++) {
817*91f16700Schasinglulu 		err = esdhc_send_cmd(mmc, CMD_SWITCH_FUNC,
818*91f16700Schasinglulu 				SD_SWITCH_FUNC_CHECK_MODE);
819*91f16700Schasinglulu 		if (err != 0) {
820*91f16700Schasinglulu 			return err;
821*91f16700Schasinglulu 		}
822*91f16700Schasinglulu 		err = esdhc_wait_response(mmc, response);
823*91f16700Schasinglulu 		if (err != 0) {
824*91f16700Schasinglulu 			return err;
825*91f16700Schasinglulu 		}
826*91f16700Schasinglulu 		/* read 64 bytes of scr data */
827*91f16700Schasinglulu 		err = esdhc_read_data(mmc, status, 64U);
828*91f16700Schasinglulu 		if (err != 0) {
829*91f16700Schasinglulu 			return ERROR_ESDHC_COMMUNICATION_ERROR;
830*91f16700Schasinglulu 		}
831*91f16700Schasinglulu 
832*91f16700Schasinglulu 		if ((status[29] & SD_SWITCH_FUNC_HIGH_SPEED) == 0) {
833*91f16700Schasinglulu 			break;
834*91f16700Schasinglulu 		}
835*91f16700Schasinglulu 	}
836*91f16700Schasinglulu 
837*91f16700Schasinglulu 	if ((status[13] & SD_SWITCH_FUNC_HIGH_SPEED) == 0) {
838*91f16700Schasinglulu 		return 0;
839*91f16700Schasinglulu 	}
840*91f16700Schasinglulu 
841*91f16700Schasinglulu 	/* SWITCH */
842*91f16700Schasinglulu 	esdhc_set_data_attributes(mmc, NULL, 1, 64);
843*91f16700Schasinglulu 	err = esdhc_send_cmd(mmc, CMD_SWITCH_FUNC, SD_SWITCH_FUNC_SWITCH_MODE);
844*91f16700Schasinglulu 	if (err != 0) {
845*91f16700Schasinglulu 		return err;
846*91f16700Schasinglulu 	}
847*91f16700Schasinglulu 	err = esdhc_wait_response(mmc, response);
848*91f16700Schasinglulu 	if (err != 0) {
849*91f16700Schasinglulu 		return err;
850*91f16700Schasinglulu 	}
851*91f16700Schasinglulu 
852*91f16700Schasinglulu 	err = esdhc_read_data(mmc, status, 64U);
853*91f16700Schasinglulu 	if (err != 0) {
854*91f16700Schasinglulu 		return ERROR_ESDHC_COMMUNICATION_ERROR;
855*91f16700Schasinglulu 	}
856*91f16700Schasinglulu 
857*91f16700Schasinglulu 	if ((status[16]) == U(0x01)) {
858*91f16700Schasinglulu 		mmc->card.bus_freq = SD_HS_50MHZ;
859*91f16700Schasinglulu 	}
860*91f16700Schasinglulu 
861*91f16700Schasinglulu 	return 0;
862*91f16700Schasinglulu }
863*91f16700Schasinglulu 
864*91f16700Schasinglulu /***************************************************************************
865*91f16700Schasinglulu  * Function    :    change_state_to_transfer_state
866*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
867*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
868*91f16700Schasinglulu  * Description :    1. Send CMD7 (CMD_SELECT_CARD) to toggles the card
869*91f16700Schasinglulu  *                     between stand-by and transfer state
870*91f16700Schasinglulu  *                  2. Send CMD13 (CMD_SEND_STATUS) to check state as
871*91f16700Schasinglulu  *                     Transfer State
872*91f16700Schasinglulu  ***************************************************************************/
873*91f16700Schasinglulu static int change_state_to_transfer_state(struct mmc *mmc)
874*91f16700Schasinglulu {
875*91f16700Schasinglulu 	int error = 0;
876*91f16700Schasinglulu 	uint32_t response[4];
877*91f16700Schasinglulu 	uint64_t start_time;
878*91f16700Schasinglulu 
879*91f16700Schasinglulu 	/* Command CMD_SELECT_CARD/CMD7 toggles the card between stand-by
880*91f16700Schasinglulu 	 * and transfer states
881*91f16700Schasinglulu 	 */
882*91f16700Schasinglulu 	error = esdhc_send_cmd(mmc, CMD_SELECT_CARD, mmc->card.rca << 16);
883*91f16700Schasinglulu 	if (error != 0) {
884*91f16700Schasinglulu 		return error;
885*91f16700Schasinglulu 	}
886*91f16700Schasinglulu 	error = esdhc_wait_response(mmc, response);
887*91f16700Schasinglulu 	if (error != 0) {
888*91f16700Schasinglulu 		return error;
889*91f16700Schasinglulu 	}
890*91f16700Schasinglulu 
891*91f16700Schasinglulu 	start_time = get_timer_val(0);
892*91f16700Schasinglulu 	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
893*91f16700Schasinglulu 		/* send CMD13 to check card status */
894*91f16700Schasinglulu 		error = esdhc_send_cmd(mmc,
895*91f16700Schasinglulu 					CMD_SEND_STATUS, mmc->card.rca << 16);
896*91f16700Schasinglulu 		if (error != 0) {
897*91f16700Schasinglulu 			return error;
898*91f16700Schasinglulu 		}
899*91f16700Schasinglulu 		error = esdhc_wait_response(mmc, response);
900*91f16700Schasinglulu 		if ((error != 0) || ((response[0] & R1_ERROR) != 0)) {
901*91f16700Schasinglulu 			return error;
902*91f16700Schasinglulu 		}
903*91f16700Schasinglulu 
904*91f16700Schasinglulu 		/* Check for the present state of card */
905*91f16700Schasinglulu 		if (((response[0] >> 9U) & U(0xF)) == STATE_TRAN) {
906*91f16700Schasinglulu 			break;
907*91f16700Schasinglulu 		}
908*91f16700Schasinglulu 	}
909*91f16700Schasinglulu 	if (((response[0] >> 9U) & U(0xF)) == STATE_TRAN) {
910*91f16700Schasinglulu 		return 0;
911*91f16700Schasinglulu 	} else {
912*91f16700Schasinglulu 		return ERROR_ESDHC_COMMUNICATION_ERROR;
913*91f16700Schasinglulu 	}
914*91f16700Schasinglulu }
915*91f16700Schasinglulu 
916*91f16700Schasinglulu /***************************************************************************
917*91f16700Schasinglulu  * Function    :    get_cid_rca_csd
918*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
919*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
920*91f16700Schasinglulu  * Description :    1. Send CMD2 (CMD_ALL_SEND_CID)
921*91f16700Schasinglulu  *                  2. get RCA for SD cards, set rca for mmc cards
922*91f16700Schasinglulu  *                     Send CMD3 (CMD_SEND_RELATIVE_ADDR)
923*91f16700Schasinglulu  *                  3. Send CMD9 (CMD_SEND_CSD)
924*91f16700Schasinglulu  *                  4. Get MMC Version from CSD
925*91f16700Schasinglulu  ***************************************************************************/
926*91f16700Schasinglulu static int get_cid_rca_csd(struct mmc *mmc)
927*91f16700Schasinglulu {
928*91f16700Schasinglulu 	int err;
929*91f16700Schasinglulu 	uint32_t version;
930*91f16700Schasinglulu 	uint32_t response[4];
931*91f16700Schasinglulu 	uint32_t mmc_version[] = {MMC_CARD_VERSION_1_2, MMC_CARD_VERSION_1_4,
932*91f16700Schasinglulu 		MMC_CARD_VERSION_2_X, MMC_CARD_VERSION_3_X,
933*91f16700Schasinglulu 		MMC_CARD_VERSION_4_X};
934*91f16700Schasinglulu 
935*91f16700Schasinglulu 	err = esdhc_send_cmd(mmc, CMD_ALL_SEND_CID, 0);
936*91f16700Schasinglulu 	if (err != 0) {
937*91f16700Schasinglulu 		return err;
938*91f16700Schasinglulu 	}
939*91f16700Schasinglulu 	err = esdhc_wait_response(mmc, response);
940*91f16700Schasinglulu 	if (err != 0) {
941*91f16700Schasinglulu 		return err;
942*91f16700Schasinglulu 	}
943*91f16700Schasinglulu 
944*91f16700Schasinglulu 	/* get RCA for SD cards, set rca for mmc cards */
945*91f16700Schasinglulu 	mmc->card.rca = SD_MMC_CARD_RCA;
946*91f16700Schasinglulu 
947*91f16700Schasinglulu 	/* send RCA cmd */
948*91f16700Schasinglulu 	err = esdhc_send_cmd(mmc, CMD_SEND_RELATIVE_ADDR, mmc->card.rca << 16);
949*91f16700Schasinglulu 	if (err != 0) {
950*91f16700Schasinglulu 		return err;
951*91f16700Schasinglulu 	}
952*91f16700Schasinglulu 	err = esdhc_wait_response(mmc, response);
953*91f16700Schasinglulu 	if (err != 0) {
954*91f16700Schasinglulu 		return err;
955*91f16700Schasinglulu 	}
956*91f16700Schasinglulu 
957*91f16700Schasinglulu 	/* for SD, get the the RCA */
958*91f16700Schasinglulu 	if (mmc->card.type == SD_CARD) {
959*91f16700Schasinglulu 		mmc->card.rca = (response[0] >> 16) & 0xFFFF;
960*91f16700Schasinglulu 	}
961*91f16700Schasinglulu 
962*91f16700Schasinglulu 	/* Get the CSD (card specific data) from card. */
963*91f16700Schasinglulu 	err = esdhc_send_cmd(mmc, CMD_SEND_CSD, mmc->card.rca << 16);
964*91f16700Schasinglulu 	if (err != 0) {
965*91f16700Schasinglulu 		return err;
966*91f16700Schasinglulu 	}
967*91f16700Schasinglulu 	err = esdhc_wait_response(mmc, response);
968*91f16700Schasinglulu 	if (err != 0) {
969*91f16700Schasinglulu 		return err;
970*91f16700Schasinglulu 	}
971*91f16700Schasinglulu 
972*91f16700Schasinglulu 	version = (response[3] >> 18U) & U(0xF);
973*91f16700Schasinglulu 	if (mmc->card.type == MMC_CARD) {
974*91f16700Schasinglulu 		if (version <= MMC_CARD_VERSION_4_X) {
975*91f16700Schasinglulu 			mmc->card.version = mmc_version[version];
976*91f16700Schasinglulu 		} else {
977*91f16700Schasinglulu 			mmc->card.version = MMC_CARD_VERSION_4_X;
978*91f16700Schasinglulu 		}
979*91f16700Schasinglulu 	}
980*91f16700Schasinglulu 
981*91f16700Schasinglulu 	mmc->card.block_len = 1 << ((response[2] >> 8) & 0xF);
982*91f16700Schasinglulu 
983*91f16700Schasinglulu 	if (mmc->card.block_len > BLOCK_LEN_512) {
984*91f16700Schasinglulu 		mmc->card.block_len = BLOCK_LEN_512;
985*91f16700Schasinglulu 	}
986*91f16700Schasinglulu 
987*91f16700Schasinglulu 	return 0;
988*91f16700Schasinglulu }
989*91f16700Schasinglulu 
990*91f16700Schasinglulu /***************************************************************************
991*91f16700Schasinglulu  * Function    :    identify_mmc_card
992*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
993*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
994*91f16700Schasinglulu  * Description :    1. Send Reset Command
995*91f16700Schasinglulu  *                  2. Send CMD1 with args to set voltage range and Sector
996*91f16700Schasinglulu  *                     Mode. (Voltage Args = 0xFF8)
997*91f16700Schasinglulu  *                  3. Check the OCR Response
998*91f16700Schasinglulu  ***************************************************************************/
999*91f16700Schasinglulu static int identify_mmc_card(struct mmc *mmc)
1000*91f16700Schasinglulu {
1001*91f16700Schasinglulu 	uint64_t start_time;
1002*91f16700Schasinglulu 	uint32_t resp[4];
1003*91f16700Schasinglulu 	int ret;
1004*91f16700Schasinglulu 	uint32_t args;
1005*91f16700Schasinglulu 
1006*91f16700Schasinglulu 	/* card reset */
1007*91f16700Schasinglulu 	ret = esdhc_send_cmd(mmc, CMD_GO_IDLE_STATE, 0U);
1008*91f16700Schasinglulu 	if (ret != 0) {
1009*91f16700Schasinglulu 		return ret;
1010*91f16700Schasinglulu 	}
1011*91f16700Schasinglulu 	ret = esdhc_wait_response(mmc, resp);
1012*91f16700Schasinglulu 	if (ret != 0) {
1013*91f16700Schasinglulu 		return ret;
1014*91f16700Schasinglulu 	}
1015*91f16700Schasinglulu 
1016*91f16700Schasinglulu 	/* Send CMD1 to get the ocr value repeatedly till the card */
1017*91f16700Schasinglulu 	/* busy is clear. timeout = 20sec */
1018*91f16700Schasinglulu 
1019*91f16700Schasinglulu 	start_time = get_timer_val(0);
1020*91f16700Schasinglulu 	do {
1021*91f16700Schasinglulu 		/* set the bits for the voltage ranges supported by host */
1022*91f16700Schasinglulu 		args = mmc->voltages_caps | MMC_OCR_SECTOR_MODE;
1023*91f16700Schasinglulu 		ret = esdhc_send_cmd(mmc, CMD_MMC_SEND_OP_COND, args);
1024*91f16700Schasinglulu 		if (ret != 0) {
1025*91f16700Schasinglulu 			return ret;
1026*91f16700Schasinglulu 		}
1027*91f16700Schasinglulu 		ret = esdhc_wait_response(mmc, resp);
1028*91f16700Schasinglulu 		if (ret != 0) {
1029*91f16700Schasinglulu 			return ERROR_ESDHC_UNUSABLE_CARD;
1030*91f16700Schasinglulu 		}
1031*91f16700Schasinglulu 	} while (((resp[0] & MMC_OCR_BUSY) == 0U) &&
1032*91f16700Schasinglulu 			(get_timer_val(start_time) < SD_TIMEOUT_HIGH));
1033*91f16700Schasinglulu 
1034*91f16700Schasinglulu 	if (get_timer_val(start_time) > SD_TIMEOUT_HIGH) {
1035*91f16700Schasinglulu 		return ERROR_ESDHC_UNUSABLE_CARD;
1036*91f16700Schasinglulu 	}
1037*91f16700Schasinglulu 
1038*91f16700Schasinglulu 	if ((resp[0] & MMC_OCR_CCS) == MMC_OCR_CCS) {
1039*91f16700Schasinglulu 		mmc->card.is_high_capacity = 1;
1040*91f16700Schasinglulu 	}
1041*91f16700Schasinglulu 
1042*91f16700Schasinglulu 	return MMC_CARD;
1043*91f16700Schasinglulu }
1044*91f16700Schasinglulu 
1045*91f16700Schasinglulu /***************************************************************************
1046*91f16700Schasinglulu  * Function    :    check_for_sd_card
1047*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
1048*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
1049*91f16700Schasinglulu  * Description :    1. Send Reset Command
1050*91f16700Schasinglulu  *                  2. Send CMD8 with pattern 0xAA (to check for SD 2.0)
1051*91f16700Schasinglulu  *                  3. Send ACMD41 with args to set voltage range and HCS
1052*91f16700Schasinglulu  *                     HCS is set only for SD Card > 2.0
1053*91f16700Schasinglulu  *                     Voltage Caps = 0xFF8
1054*91f16700Schasinglulu  *                  4. Check the OCR Response
1055*91f16700Schasinglulu  ***************************************************************************/
1056*91f16700Schasinglulu static int check_for_sd_card(struct mmc *mmc)
1057*91f16700Schasinglulu {
1058*91f16700Schasinglulu 	uint64_t start_time;
1059*91f16700Schasinglulu 	uint32_t args;
1060*91f16700Schasinglulu 	int  ret;
1061*91f16700Schasinglulu 	uint32_t resp[4];
1062*91f16700Schasinglulu 
1063*91f16700Schasinglulu 	/* Send reset command */
1064*91f16700Schasinglulu 	ret = esdhc_send_cmd(mmc, CMD_GO_IDLE_STATE, 0U);
1065*91f16700Schasinglulu 	if (ret != 0) {
1066*91f16700Schasinglulu 		return ret;
1067*91f16700Schasinglulu 	}
1068*91f16700Schasinglulu 	ret = esdhc_wait_response(mmc, resp);
1069*91f16700Schasinglulu 	if (ret != 0) {
1070*91f16700Schasinglulu 		return ret;
1071*91f16700Schasinglulu 	}
1072*91f16700Schasinglulu 
1073*91f16700Schasinglulu 	/* send CMD8 with  pattern 0xAA */
1074*91f16700Schasinglulu 	args = MMC_VDD_HIGH_VOLTAGE | 0xAA;
1075*91f16700Schasinglulu 	ret = esdhc_send_cmd(mmc, CMD_SEND_IF_COND, args);
1076*91f16700Schasinglulu 	if (ret != 0) {
1077*91f16700Schasinglulu 		return ret;
1078*91f16700Schasinglulu 	}
1079*91f16700Schasinglulu 	ret = esdhc_wait_response(mmc, resp);
1080*91f16700Schasinglulu 	if (ret == RESP_TIMEOUT) { /* sd ver 1.x or not sd */
1081*91f16700Schasinglulu 		mmc->card.is_high_capacity = 0;
1082*91f16700Schasinglulu 	} else if ((resp[0] & U(0xFF)) == U(0xAA)) { /* ver 2.0 or later */
1083*91f16700Schasinglulu 		mmc->card.version = SD_CARD_VERSION_2_0;
1084*91f16700Schasinglulu 	} else {
1085*91f16700Schasinglulu 		return  NOT_SD_CARD;
1086*91f16700Schasinglulu 	}
1087*91f16700Schasinglulu 	/* Send Application command-55 to get the ocr value repeatedly till
1088*91f16700Schasinglulu 	 * the card busy is clear. timeout = 20sec
1089*91f16700Schasinglulu 	 */
1090*91f16700Schasinglulu 
1091*91f16700Schasinglulu 	start_time = get_timer_val(0);
1092*91f16700Schasinglulu 	do {
1093*91f16700Schasinglulu 		ret = esdhc_send_cmd(mmc, CMD_APP_CMD, 0U);
1094*91f16700Schasinglulu 		if (ret != 0) {
1095*91f16700Schasinglulu 			return ret;
1096*91f16700Schasinglulu 		}
1097*91f16700Schasinglulu 		ret = esdhc_wait_response(mmc, resp);
1098*91f16700Schasinglulu 		if (ret == COMMAND_ERROR) {
1099*91f16700Schasinglulu 			return ERROR_ESDHC_UNUSABLE_CARD;
1100*91f16700Schasinglulu 		}
1101*91f16700Schasinglulu 
1102*91f16700Schasinglulu 		/* set the bits for the voltage ranges supported by host */
1103*91f16700Schasinglulu 		args = mmc->voltages_caps;
1104*91f16700Schasinglulu 		if (mmc->card.version == SD_CARD_VERSION_2_0) {
1105*91f16700Schasinglulu 			args |= SD_OCR_HCS;
1106*91f16700Schasinglulu 		}
1107*91f16700Schasinglulu 
1108*91f16700Schasinglulu 		/* Send ACMD41 to set voltage range */
1109*91f16700Schasinglulu 		ret = esdhc_send_cmd(mmc, CMD_SD_SEND_OP_COND, args);
1110*91f16700Schasinglulu 		if (ret != 0) {
1111*91f16700Schasinglulu 			return ret;
1112*91f16700Schasinglulu 		}
1113*91f16700Schasinglulu 		ret = esdhc_wait_response(mmc, resp);
1114*91f16700Schasinglulu 		if (ret == COMMAND_ERROR) {
1115*91f16700Schasinglulu 			return ERROR_ESDHC_UNUSABLE_CARD;
1116*91f16700Schasinglulu 		} else if (ret == RESP_TIMEOUT) {
1117*91f16700Schasinglulu 			return NOT_SD_CARD;
1118*91f16700Schasinglulu 		}
1119*91f16700Schasinglulu 	} while (((resp[0] & MMC_OCR_BUSY) == 0U) &&
1120*91f16700Schasinglulu 			(get_timer_val(start_time) < SD_TIMEOUT_HIGH));
1121*91f16700Schasinglulu 
1122*91f16700Schasinglulu 	if (get_timer_val(start_time) > SD_TIMEOUT_HIGH) {
1123*91f16700Schasinglulu 		INFO("SD_TIMEOUT_HIGH\n");
1124*91f16700Schasinglulu 		return ERROR_ESDHC_UNUSABLE_CARD;
1125*91f16700Schasinglulu 	}
1126*91f16700Schasinglulu 
1127*91f16700Schasinglulu 	/* bit set in card capacity status */
1128*91f16700Schasinglulu 	if ((resp[0] & MMC_OCR_CCS) == MMC_OCR_CCS) {
1129*91f16700Schasinglulu 		mmc->card.is_high_capacity = 1;
1130*91f16700Schasinglulu 	}
1131*91f16700Schasinglulu 
1132*91f16700Schasinglulu 	return SD_CARD;
1133*91f16700Schasinglulu }
1134*91f16700Schasinglulu 
1135*91f16700Schasinglulu /***************************************************************************
1136*91f16700Schasinglulu  * Function    :    esdhc_emmc_init
1137*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
1138*91f16700Schasinglulu  *                  src_emmc - Flag to Indicate SRC as emmc
1139*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code (< 0)
1140*91f16700Schasinglulu  * Description :    Base Function called from sd_mmc_init or emmc_init
1141*91f16700Schasinglulu  ***************************************************************************/
1142*91f16700Schasinglulu int esdhc_emmc_init(struct mmc *mmc, bool card_detect)
1143*91f16700Schasinglulu {
1144*91f16700Schasinglulu 	int error = 0;
1145*91f16700Schasinglulu 	int ret = 0;
1146*91f16700Schasinglulu 
1147*91f16700Schasinglulu 	error = esdhc_init(mmc, card_detect);
1148*91f16700Schasinglulu 	if (error != 0) {
1149*91f16700Schasinglulu 		return error;
1150*91f16700Schasinglulu 	}
1151*91f16700Schasinglulu 
1152*91f16700Schasinglulu 	mmc->card.bus_freq = CARD_IDENTIFICATION_FREQ;
1153*91f16700Schasinglulu 	mmc->card.rca = 0;
1154*91f16700Schasinglulu 	mmc->card.is_high_capacity = 0;
1155*91f16700Schasinglulu 	mmc->card.type = ERROR_ESDHC_UNUSABLE_CARD;
1156*91f16700Schasinglulu 
1157*91f16700Schasinglulu 	/* Set Voltage caps as FF8 i.e all supported */
1158*91f16700Schasinglulu 	/* high voltage bits 2.7 - 3.6 */
1159*91f16700Schasinglulu 	mmc->voltages_caps = MMC_OCR_VDD_FF8;
1160*91f16700Schasinglulu 
1161*91f16700Schasinglulu #ifdef NXP_SD_DMA_CAPABILITY
1162*91f16700Schasinglulu 	/* Getting host DMA capabilities. */
1163*91f16700Schasinglulu 	mmc->dma_support = esdhc_in32(&mmc->esdhc_regs->hostcapblt) &
1164*91f16700Schasinglulu 					ESDHC_HOSTCAPBLT_DMAS;
1165*91f16700Schasinglulu #else
1166*91f16700Schasinglulu 	mmc->dma_support = 0;
1167*91f16700Schasinglulu #endif
1168*91f16700Schasinglulu 
1169*91f16700Schasinglulu 	ret = NOT_SD_CARD;
1170*91f16700Schasinglulu 	/* If SRC is not EMMC, check for SD or MMC */
1171*91f16700Schasinglulu 	ret = check_for_sd_card(mmc);
1172*91f16700Schasinglulu 	switch (ret) {
1173*91f16700Schasinglulu 	case SD_CARD:
1174*91f16700Schasinglulu 		mmc->card.type = SD_CARD;
1175*91f16700Schasinglulu 		break;
1176*91f16700Schasinglulu 
1177*91f16700Schasinglulu 	case NOT_SD_CARD:
1178*91f16700Schasinglulu 		/* try for MMC card */
1179*91f16700Schasinglulu 		if (identify_mmc_card(mmc) == MMC_CARD) {
1180*91f16700Schasinglulu 			mmc->card.type = MMC_CARD;
1181*91f16700Schasinglulu 		} else {
1182*91f16700Schasinglulu 			return ERROR_ESDHC_UNUSABLE_CARD;
1183*91f16700Schasinglulu 		}
1184*91f16700Schasinglulu 		break;
1185*91f16700Schasinglulu 
1186*91f16700Schasinglulu 	default:
1187*91f16700Schasinglulu 		return ERROR_ESDHC_UNUSABLE_CARD;
1188*91f16700Schasinglulu 	}
1189*91f16700Schasinglulu 
1190*91f16700Schasinglulu 	/* get CID, RCA and CSD. For MMC, set the rca */
1191*91f16700Schasinglulu 	error = get_cid_rca_csd(mmc);
1192*91f16700Schasinglulu 	if (error != 0) {
1193*91f16700Schasinglulu 		return ERROR_ESDHC_COMMUNICATION_ERROR;
1194*91f16700Schasinglulu 	}
1195*91f16700Schasinglulu 
1196*91f16700Schasinglulu 	/* change state to Transfer mode */
1197*91f16700Schasinglulu 	error = change_state_to_transfer_state(mmc);
1198*91f16700Schasinglulu 	if (error != 0) {
1199*91f16700Schasinglulu 		return ERROR_ESDHC_COMMUNICATION_ERROR;
1200*91f16700Schasinglulu 	}
1201*91f16700Schasinglulu 
1202*91f16700Schasinglulu 	/* change to high frequency if supported */
1203*91f16700Schasinglulu 	if (mmc->card.type == SD_CARD) {
1204*91f16700Schasinglulu 		error = sd_switch_to_high_freq(mmc);
1205*91f16700Schasinglulu 	} else {
1206*91f16700Schasinglulu 		error = mmc_switch_to_high_frquency(mmc);
1207*91f16700Schasinglulu 	}
1208*91f16700Schasinglulu 	if (error != 0) {
1209*91f16700Schasinglulu 		return ERROR_ESDHC_COMMUNICATION_ERROR;
1210*91f16700Schasinglulu 	}
1211*91f16700Schasinglulu 
1212*91f16700Schasinglulu 	/* mmc: 20000000, 26000000, 52000000 */
1213*91f16700Schasinglulu 	/* sd: 25000000, 50000000 */
1214*91f16700Schasinglulu 	set_speed(mmc, mmc->card.bus_freq);
1215*91f16700Schasinglulu 
1216*91f16700Schasinglulu 	INFO("init done:\n");
1217*91f16700Schasinglulu 	return 0;
1218*91f16700Schasinglulu }
1219*91f16700Schasinglulu 
1220*91f16700Schasinglulu /***************************************************************************
1221*91f16700Schasinglulu  * Function    :    sd_mmc_init
1222*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
1223*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
1224*91f16700Schasinglulu  * Description :    Base Function called via hal_init for SD/MMC
1225*91f16700Schasinglulu  *                  initialization
1226*91f16700Schasinglulu  ***************************************************************************/
1227*91f16700Schasinglulu int sd_mmc_init(uintptr_t nxp_esdhc_addr, bool card_detect)
1228*91f16700Schasinglulu {
1229*91f16700Schasinglulu 	struct mmc *mmc = NULL;
1230*91f16700Schasinglulu 	int ret;
1231*91f16700Schasinglulu 
1232*91f16700Schasinglulu 	mmc = &mmc_drv_data;
1233*91f16700Schasinglulu 	memset(mmc, 0, sizeof(struct mmc));
1234*91f16700Schasinglulu 	mmc->esdhc_regs = (struct esdhc_regs *)nxp_esdhc_addr;
1235*91f16700Schasinglulu 
1236*91f16700Schasinglulu 	INFO("esdhc_emmc_init\n");
1237*91f16700Schasinglulu 	ret = esdhc_emmc_init(mmc, card_detect);
1238*91f16700Schasinglulu 	return ret;
1239*91f16700Schasinglulu }
1240*91f16700Schasinglulu 
1241*91f16700Schasinglulu /***************************************************************************
1242*91f16700Schasinglulu  * Function    :    esdhc_read_block
1243*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
1244*91f16700Schasinglulu  *                  dst - Destination Pointer
1245*91f16700Schasinglulu  *                  block - Block Number
1246*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
1247*91f16700Schasinglulu  * Description :    Read a Single block to Destination Pointer
1248*91f16700Schasinglulu  *                  1. Send CMD16 (CMD_SET_BLOCKLEN) with args as blocklen
1249*91f16700Schasinglulu  *                  2. Send CMD17 (CMD_READ_SINGLE_BLOCK) with args offset
1250*91f16700Schasinglulu  ***************************************************************************/
1251*91f16700Schasinglulu static int esdhc_read_block(struct mmc *mmc, void *dst, uint32_t block)
1252*91f16700Schasinglulu {
1253*91f16700Schasinglulu 	uint32_t offset;
1254*91f16700Schasinglulu 	int err;
1255*91f16700Schasinglulu 
1256*91f16700Schasinglulu 	/* send cmd16 to set the block size. */
1257*91f16700Schasinglulu 	err = esdhc_send_cmd(mmc, CMD_SET_BLOCKLEN, mmc->card.block_len);
1258*91f16700Schasinglulu 	if (err != 0) {
1259*91f16700Schasinglulu 		return err;
1260*91f16700Schasinglulu 	}
1261*91f16700Schasinglulu 	err = esdhc_wait_response(mmc, NULL);
1262*91f16700Schasinglulu 	if (err != 0) {
1263*91f16700Schasinglulu 		return ERROR_ESDHC_COMMUNICATION_ERROR;
1264*91f16700Schasinglulu 	}
1265*91f16700Schasinglulu 
1266*91f16700Schasinglulu 	if (mmc->card.is_high_capacity != 0) {
1267*91f16700Schasinglulu 		offset = block;
1268*91f16700Schasinglulu 	} else {
1269*91f16700Schasinglulu 		offset = block * mmc->card.block_len;
1270*91f16700Schasinglulu 	}
1271*91f16700Schasinglulu 
1272*91f16700Schasinglulu 	esdhc_set_data_attributes(mmc, dst, 1, mmc->card.block_len);
1273*91f16700Schasinglulu 	err = esdhc_send_cmd(mmc, CMD_READ_SINGLE_BLOCK, offset);
1274*91f16700Schasinglulu 	if (err != 0) {
1275*91f16700Schasinglulu 		return err;
1276*91f16700Schasinglulu 	}
1277*91f16700Schasinglulu 	err = esdhc_wait_response(mmc, NULL);
1278*91f16700Schasinglulu 	if (err != 0) {
1279*91f16700Schasinglulu 		return err;
1280*91f16700Schasinglulu 	}
1281*91f16700Schasinglulu 
1282*91f16700Schasinglulu 	err = esdhc_read_data(mmc, dst, mmc->card.block_len);
1283*91f16700Schasinglulu 
1284*91f16700Schasinglulu 	return err;
1285*91f16700Schasinglulu }
1286*91f16700Schasinglulu 
1287*91f16700Schasinglulu /***************************************************************************
1288*91f16700Schasinglulu  * Function    :    esdhc_write_block
1289*91f16700Schasinglulu  * Arguments   :    mmc - Pointer to mmc struct
1290*91f16700Schasinglulu  *                  src - Source Pointer
1291*91f16700Schasinglulu  *                  block - Block Number
1292*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
1293*91f16700Schasinglulu  * Description :    Write a Single block from Source Pointer
1294*91f16700Schasinglulu  *                  1. Send CMD16 (CMD_SET_BLOCKLEN) with args as blocklen
1295*91f16700Schasinglulu  *                  2. Send CMD24 (CMD_WRITE_SINGLE_BLOCK) with args offset
1296*91f16700Schasinglulu  ***************************************************************************/
1297*91f16700Schasinglulu static int esdhc_write_block(struct mmc *mmc, void *src, uint32_t block)
1298*91f16700Schasinglulu {
1299*91f16700Schasinglulu 	uint32_t offset;
1300*91f16700Schasinglulu 	int err;
1301*91f16700Schasinglulu 
1302*91f16700Schasinglulu 	/* send cmd16 to set the block size. */
1303*91f16700Schasinglulu 	err = esdhc_send_cmd(mmc, CMD_SET_BLOCKLEN, mmc->card.block_len);
1304*91f16700Schasinglulu 	if (err != 0) {
1305*91f16700Schasinglulu 		return err;
1306*91f16700Schasinglulu 	}
1307*91f16700Schasinglulu 	err = esdhc_wait_response(mmc, NULL);
1308*91f16700Schasinglulu 	if (err != 0) {
1309*91f16700Schasinglulu 		return ERROR_ESDHC_COMMUNICATION_ERROR;
1310*91f16700Schasinglulu 	}
1311*91f16700Schasinglulu 
1312*91f16700Schasinglulu 	if (mmc->card.is_high_capacity != 0) {
1313*91f16700Schasinglulu 		offset = block;
1314*91f16700Schasinglulu 	} else {
1315*91f16700Schasinglulu 		offset = block * mmc->card.block_len;
1316*91f16700Schasinglulu 	}
1317*91f16700Schasinglulu 
1318*91f16700Schasinglulu 	esdhc_set_data_attributes(mmc, src, 1, mmc->card.block_len);
1319*91f16700Schasinglulu 	err = esdhc_send_cmd(mmc, CMD_WRITE_SINGLE_BLOCK, offset);
1320*91f16700Schasinglulu 	if (err != 0) {
1321*91f16700Schasinglulu 		return err;
1322*91f16700Schasinglulu 	}
1323*91f16700Schasinglulu 	err = esdhc_wait_response(mmc, NULL);
1324*91f16700Schasinglulu 	if (err != 0) {
1325*91f16700Schasinglulu 		return err;
1326*91f16700Schasinglulu 	}
1327*91f16700Schasinglulu 
1328*91f16700Schasinglulu 	err = esdhc_write_data(mmc, src, mmc->card.block_len);
1329*91f16700Schasinglulu 
1330*91f16700Schasinglulu 	return err;
1331*91f16700Schasinglulu }
1332*91f16700Schasinglulu 
1333*91f16700Schasinglulu /***************************************************************************
1334*91f16700Schasinglulu  * Function    :    esdhc_read
1335*91f16700Schasinglulu  * Arguments   :    src_offset - offset on sd/mmc to read from. Should be block
1336*91f16700Schasinglulu  *		    size aligned
1337*91f16700Schasinglulu  *                  dst - Destination Pointer
1338*91f16700Schasinglulu  *                  size - Length of Data ( Multiple of block size)
1339*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
1340*91f16700Schasinglulu  * Description :    Calls esdhc_read_block repeatedly for reading the
1341*91f16700Schasinglulu  *                  data.
1342*91f16700Schasinglulu  ***************************************************************************/
1343*91f16700Schasinglulu int esdhc_read(struct mmc *mmc, uint32_t src_offset, uintptr_t dst, size_t size)
1344*91f16700Schasinglulu {
1345*91f16700Schasinglulu 	int error = 0;
1346*91f16700Schasinglulu 	uint32_t blk, num_blocks;
1347*91f16700Schasinglulu 	uint8_t *buff = (uint8_t *)dst;
1348*91f16700Schasinglulu 
1349*91f16700Schasinglulu #ifdef NXP_SD_DEBUG
1350*91f16700Schasinglulu 	INFO("sd mmc read\n");
1351*91f16700Schasinglulu 	INFO("src = %x, dst = %lxsize = %lu\n", src_offset, dst, size);
1352*91f16700Schasinglulu #endif
1353*91f16700Schasinglulu 
1354*91f16700Schasinglulu 	/* check for size */
1355*91f16700Schasinglulu 	if (size == 0) {
1356*91f16700Schasinglulu 		return 0;
1357*91f16700Schasinglulu 	}
1358*91f16700Schasinglulu 
1359*91f16700Schasinglulu 	if ((size % mmc->card.block_len) != 0) {
1360*91f16700Schasinglulu 		ERROR("Size is not block aligned\n");
1361*91f16700Schasinglulu 		return -1;
1362*91f16700Schasinglulu 	}
1363*91f16700Schasinglulu 
1364*91f16700Schasinglulu 	if ((src_offset % mmc->card.block_len) != 0) {
1365*91f16700Schasinglulu 		ERROR("Size is not block aligned\n");
1366*91f16700Schasinglulu 		return -1;
1367*91f16700Schasinglulu 	}
1368*91f16700Schasinglulu 
1369*91f16700Schasinglulu 	/* start block */
1370*91f16700Schasinglulu 	blk = src_offset / mmc->card.block_len;
1371*91f16700Schasinglulu #ifdef NXP_SD_DEBUG
1372*91f16700Schasinglulu 	INFO("blk = %x\n", blk);
1373*91f16700Schasinglulu #endif
1374*91f16700Schasinglulu 
1375*91f16700Schasinglulu 	/* Number of blocks to be read */
1376*91f16700Schasinglulu 	num_blocks = size / mmc->card.block_len;
1377*91f16700Schasinglulu 
1378*91f16700Schasinglulu 	while (num_blocks) {
1379*91f16700Schasinglulu 		error = esdhc_read_block(mmc, buff, blk);
1380*91f16700Schasinglulu 		if (error != 0) {
1381*91f16700Schasinglulu 			ERROR("Read error = %x\n", error);
1382*91f16700Schasinglulu 			return error;
1383*91f16700Schasinglulu 		}
1384*91f16700Schasinglulu 
1385*91f16700Schasinglulu 		buff = buff + mmc->card.block_len;
1386*91f16700Schasinglulu 		blk++;
1387*91f16700Schasinglulu 		num_blocks--;
1388*91f16700Schasinglulu 	}
1389*91f16700Schasinglulu 
1390*91f16700Schasinglulu 	INFO("sd-mmc read done.\n");
1391*91f16700Schasinglulu 	return error;
1392*91f16700Schasinglulu }
1393*91f16700Schasinglulu 
1394*91f16700Schasinglulu /***************************************************************************
1395*91f16700Schasinglulu  * Function    :    esdhc_write
1396*91f16700Schasinglulu  * Arguments   :    src - Source Pointer
1397*91f16700Schasinglulu  *                  dst_offset - offset on sd/mmc to write to. Should be block
1398*91f16700Schasinglulu  *		    size aligned
1399*91f16700Schasinglulu  *                  size - Length of Data (Multiple of block size)
1400*91f16700Schasinglulu  * Return      :    SUCCESS or Error Code
1401*91f16700Schasinglulu  * Description :    Calls esdhc_write_block repeatedly for writing the
1402*91f16700Schasinglulu  *                  data.
1403*91f16700Schasinglulu  ***************************************************************************/
1404*91f16700Schasinglulu int esdhc_write(struct mmc *mmc, uintptr_t src, uint32_t dst_offset,
1405*91f16700Schasinglulu 		size_t size)
1406*91f16700Schasinglulu {
1407*91f16700Schasinglulu 	int error = 0;
1408*91f16700Schasinglulu 	uint32_t blk, num_blocks;
1409*91f16700Schasinglulu 	uint8_t *buff = (uint8_t *)src;
1410*91f16700Schasinglulu 
1411*91f16700Schasinglulu #ifdef NXP_SD_DEBUG
1412*91f16700Schasinglulu 	INFO("sd mmc write\n");
1413*91f16700Schasinglulu 	INFO("src = %x, dst = %lxsize = %lu\n", src, dst_offset, size);
1414*91f16700Schasinglulu #endif
1415*91f16700Schasinglulu 
1416*91f16700Schasinglulu 	/* check for size */
1417*91f16700Schasinglulu 	if (size == 0) {
1418*91f16700Schasinglulu 		return 0;
1419*91f16700Schasinglulu 	}
1420*91f16700Schasinglulu 
1421*91f16700Schasinglulu 	if ((size % mmc->card.block_len) != 0) {
1422*91f16700Schasinglulu 		ERROR("Size is not block aligned\n");
1423*91f16700Schasinglulu 		return -1;
1424*91f16700Schasinglulu 	}
1425*91f16700Schasinglulu 
1426*91f16700Schasinglulu 	if ((dst_offset % mmc->card.block_len) != 0) {
1427*91f16700Schasinglulu 		ERROR("Size is not block aligned\n");
1428*91f16700Schasinglulu 		return -1;
1429*91f16700Schasinglulu 	}
1430*91f16700Schasinglulu 
1431*91f16700Schasinglulu 	/* start block */
1432*91f16700Schasinglulu 	blk = dst_offset / mmc->card.block_len;
1433*91f16700Schasinglulu #ifdef NXP_SD_DEBUG
1434*91f16700Schasinglulu 	INFO("blk = %x\n", blk);
1435*91f16700Schasinglulu #endif
1436*91f16700Schasinglulu 
1437*91f16700Schasinglulu 	/* Number of blocks to be written */
1438*91f16700Schasinglulu 	num_blocks = size / mmc->card.block_len;
1439*91f16700Schasinglulu 
1440*91f16700Schasinglulu 	while (num_blocks != 0U) {
1441*91f16700Schasinglulu 		error = esdhc_write_block(mmc, buff, blk);
1442*91f16700Schasinglulu 		if (error != 0U) {
1443*91f16700Schasinglulu 			ERROR("Write error = %x\n", error);
1444*91f16700Schasinglulu 			return error;
1445*91f16700Schasinglulu 		}
1446*91f16700Schasinglulu 
1447*91f16700Schasinglulu 		buff = buff + mmc->card.block_len;
1448*91f16700Schasinglulu 		blk++;
1449*91f16700Schasinglulu 		num_blocks--;
1450*91f16700Schasinglulu 	}
1451*91f16700Schasinglulu 
1452*91f16700Schasinglulu 	INFO("sd-mmc write done.\n");
1453*91f16700Schasinglulu 	return error;
1454*91f16700Schasinglulu }
1455*91f16700Schasinglulu 
1456*91f16700Schasinglulu static size_t ls_sd_emmc_read(int lba, uintptr_t buf, size_t size)
1457*91f16700Schasinglulu {
1458*91f16700Schasinglulu 	struct mmc *mmc = NULL;
1459*91f16700Schasinglulu 	int ret;
1460*91f16700Schasinglulu 
1461*91f16700Schasinglulu 	mmc = &mmc_drv_data;
1462*91f16700Schasinglulu 	lba *= BLOCK_LEN_512;
1463*91f16700Schasinglulu 	ret = esdhc_read(mmc, lba, buf, size);
1464*91f16700Schasinglulu 	return ret ? 0 : size;
1465*91f16700Schasinglulu }
1466*91f16700Schasinglulu 
1467*91f16700Schasinglulu static struct io_block_dev_spec ls_emmc_dev_spec = {
1468*91f16700Schasinglulu 	.buffer = {
1469*91f16700Schasinglulu 		.offset = 0,
1470*91f16700Schasinglulu 		.length = 0,
1471*91f16700Schasinglulu 	},
1472*91f16700Schasinglulu 	.ops = {
1473*91f16700Schasinglulu 		.read = ls_sd_emmc_read,
1474*91f16700Schasinglulu 	},
1475*91f16700Schasinglulu 	.block_size = BLOCK_LEN_512,
1476*91f16700Schasinglulu };
1477*91f16700Schasinglulu 
1478*91f16700Schasinglulu int sd_emmc_init(uintptr_t *block_dev_spec,
1479*91f16700Schasinglulu 			uintptr_t nxp_esdhc_addr,
1480*91f16700Schasinglulu 			size_t nxp_sd_block_offset,
1481*91f16700Schasinglulu 			size_t nxp_sd_block_size,
1482*91f16700Schasinglulu 			bool card_detect)
1483*91f16700Schasinglulu {
1484*91f16700Schasinglulu 	int ret;
1485*91f16700Schasinglulu 
1486*91f16700Schasinglulu 	ret = sd_mmc_init(nxp_esdhc_addr, card_detect);
1487*91f16700Schasinglulu 	if (ret != 0) {
1488*91f16700Schasinglulu 		return ret;
1489*91f16700Schasinglulu 	}
1490*91f16700Schasinglulu 
1491*91f16700Schasinglulu 	ls_emmc_dev_spec.buffer.offset = nxp_sd_block_offset;
1492*91f16700Schasinglulu 	ls_emmc_dev_spec.buffer.length = nxp_sd_block_size;
1493*91f16700Schasinglulu 	*block_dev_spec = (uintptr_t)&ls_emmc_dev_spec;
1494*91f16700Schasinglulu 
1495*91f16700Schasinglulu 	return 0;
1496*91f16700Schasinglulu }
1497