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