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