xref: /rk3399_ARM-atf/drivers/nxp/sd/sd_mmc.c (revision 4bd8c929b4bc6e1731c2892b38d4a8c43e8e89dc)
1066ee1adSPankaj Gupta /*
2066ee1adSPankaj Gupta  * Copyright 2021 NXP
3066ee1adSPankaj Gupta  *
4066ee1adSPankaj Gupta  * SPDX-License-Identifier: BSD-3-Clause
5066ee1adSPankaj Gupta  *
6066ee1adSPankaj Gupta  *
7066ee1adSPankaj Gupta  */
8066ee1adSPankaj Gupta 
9066ee1adSPankaj Gupta #include <endian.h>
10066ee1adSPankaj Gupta #include <stdio.h>
11066ee1adSPankaj Gupta #include <stdlib.h>
12066ee1adSPankaj Gupta #include <string.h>
13066ee1adSPankaj Gupta 
14066ee1adSPankaj Gupta #include <arch_helpers.h>
15066ee1adSPankaj Gupta #include <common/debug.h>
16066ee1adSPankaj Gupta #include <drivers/io/io_block.h>
17066ee1adSPankaj Gupta #include "nxp_timer.h"
18066ee1adSPankaj Gupta #include "sd_mmc.h"
19066ee1adSPankaj Gupta #include <utils.h>
20066ee1adSPankaj Gupta #include <utils_def.h>
21066ee1adSPankaj Gupta 
22066ee1adSPankaj Gupta 
23066ee1adSPankaj Gupta /* Private structure for MMC driver data */
24066ee1adSPankaj Gupta static struct mmc mmc_drv_data;
25066ee1adSPankaj Gupta 
26066ee1adSPankaj Gupta #ifndef NXP_POLICY_OTA
27066ee1adSPankaj Gupta /*
28066ee1adSPankaj Gupta  * For NXP_POLICY_OTA, SD needs to do R/W on OCRAM. OCRAM is secure memory at
29066ee1adSPankaj Gupta  * default. SD can only do non-secure DMA. Configuring SD to work in PIO mode
30066ee1adSPankaj Gupta  * instead of DMA mode will make SD R/W on OCRAM available.
31066ee1adSPankaj Gupta  */
32066ee1adSPankaj Gupta /* To debug without dma comment this MACRO */
33066ee1adSPankaj Gupta #define NXP_SD_DMA_CAPABILITY
34066ee1adSPankaj Gupta #endif
35066ee1adSPankaj Gupta #define SD_TIMEOUT        1000 /* ms */
36066ee1adSPankaj Gupta #define SD_TIMEOUT_HIGH   20000 /* ms */
37066ee1adSPankaj Gupta #define SD_BLOCK_TIMEOUT  8 /* ms */
38066ee1adSPankaj Gupta 
39066ee1adSPankaj Gupta #define ERROR_ESDHC_CARD_DETECT_FAIL	-1
40066ee1adSPankaj Gupta #define ERROR_ESDHC_UNUSABLE_CARD	-2
41066ee1adSPankaj Gupta #define ERROR_ESDHC_COMMUNICATION_ERROR	-3
42066ee1adSPankaj Gupta #define ERROR_ESDHC_BLOCK_LENGTH	-4
43066ee1adSPankaj Gupta #define ERROR_ESDHC_DMA_ERROR		-5
44066ee1adSPankaj Gupta #define ERROR_ESDHC_BUSY		-6
45066ee1adSPankaj Gupta 
46066ee1adSPankaj Gupta /***************************************************************
47066ee1adSPankaj Gupta  * Function    :    set_speed
48066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
49066ee1adSPankaj Gupta  *                  clock - Clock Value to be set
50066ee1adSPankaj Gupta  * Return      :    void
51066ee1adSPankaj Gupta  * Description :    Calculates the value of SDCLKFS and DVS to be set
52066ee1adSPankaj Gupta  *                  for getting the required clock assuming the base_clk
53066ee1adSPankaj Gupta  *                  as a fixed value (MAX_PLATFORM_CLOCK)
54066ee1adSPankaj Gupta  *****************************************************************/
set_speed(struct mmc * mmc,uint32_t clock)55066ee1adSPankaj Gupta static void set_speed(struct mmc *mmc, uint32_t clock)
56066ee1adSPankaj Gupta {
57066ee1adSPankaj Gupta 	/* sdhc_clk = (base clock) / [(SDCLKFS × 2) × (DVS +1)] */
58066ee1adSPankaj Gupta 
59066ee1adSPankaj Gupta 	uint32_t dvs = 1U;
60066ee1adSPankaj Gupta 	uint32_t sdclkfs = 2U;
61066ee1adSPankaj Gupta 	/* TBD - Change this to actual platform clock by reading via RCW */
62066ee1adSPankaj Gupta 	uint32_t base_clk = MAX_PLATFORM_CLOCK;
63066ee1adSPankaj Gupta 
64066ee1adSPankaj Gupta 	if (base_clk / 16 > clock) {
65066ee1adSPankaj Gupta 		for (sdclkfs = 2U; sdclkfs < 256U; sdclkfs *= 2U) {
66066ee1adSPankaj Gupta 			if ((base_clk / sdclkfs) <= (clock * 16)) {
67066ee1adSPankaj Gupta 				break;
68066ee1adSPankaj Gupta 			}
69066ee1adSPankaj Gupta 		}
70066ee1adSPankaj Gupta 	}
71066ee1adSPankaj Gupta 
72066ee1adSPankaj Gupta 	for (dvs = 1U; dvs <= 16U; dvs++) {
73066ee1adSPankaj Gupta 		if ((base_clk / (dvs * sdclkfs)) <= clock) {
74066ee1adSPankaj Gupta 			break;
75066ee1adSPankaj Gupta 		}
76066ee1adSPankaj Gupta 	}
77066ee1adSPankaj Gupta 
78066ee1adSPankaj Gupta 	sdclkfs >>= 1U;
79066ee1adSPankaj Gupta 	dvs -= 1U;
80066ee1adSPankaj Gupta 
81066ee1adSPankaj Gupta 	esdhc_out32(&mmc->esdhc_regs->sysctl,
82066ee1adSPankaj Gupta 			(ESDHC_SYSCTL_DTOCV(TIMEOUT_COUNTER_SDCLK_2_27) |
83066ee1adSPankaj Gupta 			 ESDHC_SYSCTL_SDCLKFS(sdclkfs) | ESDHC_SYSCTL_DVS(dvs) |
84066ee1adSPankaj Gupta 			 ESDHC_SYSCTL_SDCLKEN));
85066ee1adSPankaj Gupta }
86066ee1adSPankaj Gupta 
87066ee1adSPankaj Gupta /***************************************************************************
88066ee1adSPankaj Gupta  * Function    :    esdhc_init
89066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
90066ee1adSPankaj Gupta  *                  card_detect - flag to indicate if card insert needs
91066ee1adSPankaj Gupta  *                  to be detected or not. For SDHC2 controller, Card detect
92066ee1adSPankaj Gupta  *                  is not present, so this field will be false
93066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
94066ee1adSPankaj Gupta  * Description :    1. Set Initial Clock Speed
95066ee1adSPankaj Gupta  *                  2. Card Detect if not eMMC
96066ee1adSPankaj Gupta  *                  3. Enable Controller Clock
97066ee1adSPankaj Gupta  *                  4. Send 80 ticks for card to power up
98066ee1adSPankaj Gupta  *                  5. Set LE mode and Bus Width as 1 bit.
99066ee1adSPankaj Gupta  ***************************************************************************/
esdhc_init(struct mmc * mmc,bool card_detect)100066ee1adSPankaj Gupta static int esdhc_init(struct mmc *mmc, bool card_detect)
101066ee1adSPankaj Gupta {
102066ee1adSPankaj Gupta 	uint32_t val;
103066ee1adSPankaj Gupta 	uint64_t start_time;
104066ee1adSPankaj Gupta 
105066ee1adSPankaj Gupta 	/* Reset the entire host controller */
106066ee1adSPankaj Gupta 	val = esdhc_in32(&mmc->esdhc_regs->sysctl) | ESDHC_SYSCTL_RSTA;
107066ee1adSPankaj Gupta 	esdhc_out32(&mmc->esdhc_regs->sysctl, val);
108066ee1adSPankaj Gupta 
109066ee1adSPankaj Gupta 	/* Wait until the controller is available */
110066ee1adSPankaj Gupta 	start_time = get_timer_val(0);
111066ee1adSPankaj Gupta 	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
112066ee1adSPankaj Gupta 		val = esdhc_in32(&mmc->esdhc_regs->sysctl) & ESDHC_SYSCTL_RSTA;
113066ee1adSPankaj Gupta 		if (val == 0U) {
114066ee1adSPankaj Gupta 			break;
115066ee1adSPankaj Gupta 		}
116066ee1adSPankaj Gupta 	}
117066ee1adSPankaj Gupta 
118066ee1adSPankaj Gupta 	val = esdhc_in32(&mmc->esdhc_regs->sysctl) &
119066ee1adSPankaj Gupta 		(ESDHC_SYSCTL_RSTA);
120066ee1adSPankaj Gupta 	if (val != 0U) {
121066ee1adSPankaj Gupta 		ERROR("SD Reset failed\n");
122066ee1adSPankaj Gupta 		return ERROR_ESDHC_BUSY;
123066ee1adSPankaj Gupta 	}
124066ee1adSPankaj Gupta 
125066ee1adSPankaj Gupta 	/* Set initial clock speed */
126066ee1adSPankaj Gupta 	set_speed(mmc, CARD_IDENTIFICATION_FREQ);
127066ee1adSPankaj Gupta 
128066ee1adSPankaj Gupta 	if (card_detect) {
129066ee1adSPankaj Gupta 		/* Check CINS in prsstat register */
130066ee1adSPankaj Gupta 		val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
131066ee1adSPankaj Gupta 			ESDHC_PRSSTAT_CINS;
132066ee1adSPankaj Gupta 		if (val == 0) {
133066ee1adSPankaj Gupta 			ERROR("CINS not set in prsstat\n");
134066ee1adSPankaj Gupta 			return ERROR_ESDHC_CARD_DETECT_FAIL;
135066ee1adSPankaj Gupta 		}
136066ee1adSPankaj Gupta 	}
137066ee1adSPankaj Gupta 
138066ee1adSPankaj Gupta 	/* Enable controller clock */
139066ee1adSPankaj Gupta 	val = esdhc_in32(&mmc->esdhc_regs->sysctl) | ESDHC_SYSCTL_SDCLKEN;
140066ee1adSPankaj Gupta 	esdhc_out32(&mmc->esdhc_regs->sysctl, val);
141066ee1adSPankaj Gupta 
142066ee1adSPankaj Gupta 	/* Send 80 clock ticks for the card to power up */
143066ee1adSPankaj Gupta 	val = esdhc_in32(&mmc->esdhc_regs->sysctl) | ESDHC_SYSCTL_INITA;
144066ee1adSPankaj Gupta 	esdhc_out32(&mmc->esdhc_regs->sysctl, val);
145066ee1adSPankaj Gupta 
146066ee1adSPankaj Gupta 	start_time = get_timer_val(0);
147066ee1adSPankaj Gupta 	while (get_timer_val(start_time) < SD_TIMEOUT) {
148066ee1adSPankaj Gupta 		val = esdhc_in32(&mmc->esdhc_regs->sysctl) & ESDHC_SYSCTL_INITA;
149066ee1adSPankaj Gupta 		if (val != 0U) {
150066ee1adSPankaj Gupta 			break;
151066ee1adSPankaj Gupta 		}
152066ee1adSPankaj Gupta 	}
153066ee1adSPankaj Gupta 
154066ee1adSPankaj Gupta 	val = esdhc_in32(&mmc->esdhc_regs->sysctl) & ESDHC_SYSCTL_INITA;
155066ee1adSPankaj Gupta 	if (val == 0U) {
156066ee1adSPankaj Gupta 		ERROR("Failed to power up the card\n");
157066ee1adSPankaj Gupta 		return ERROR_ESDHC_CARD_DETECT_FAIL;
158066ee1adSPankaj Gupta 	}
159066ee1adSPankaj Gupta 
160066ee1adSPankaj Gupta 	INFO("Card detected successfully\n");
161066ee1adSPankaj Gupta 
162066ee1adSPankaj Gupta 	val = esdhc_in32(&mmc->esdhc_regs->proctl);
163066ee1adSPankaj Gupta 	val = val | (ESDHC_PROCTL_EMODE_LE | ESDHC_PROCTL_DTW_1BIT);
164066ee1adSPankaj Gupta 
165066ee1adSPankaj Gupta 	/* Set little endian mode, set bus width as 1-bit */
166066ee1adSPankaj Gupta 	esdhc_out32(&mmc->esdhc_regs->proctl, val);
167066ee1adSPankaj Gupta 
168066ee1adSPankaj Gupta 	/* Enable cache snooping for DMA transactions */
169066ee1adSPankaj Gupta 	val = esdhc_in32(&mmc->esdhc_regs->ctl) | ESDHC_DCR_SNOOP;
170066ee1adSPankaj Gupta 	esdhc_out32(&mmc->esdhc_regs->ctl, val);
171066ee1adSPankaj Gupta 
172066ee1adSPankaj Gupta 	return 0;
173066ee1adSPankaj Gupta }
174066ee1adSPankaj Gupta 
175066ee1adSPankaj Gupta /***************************************************************************
176066ee1adSPankaj Gupta  * Function    :    esdhc_send_cmd
177066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
178066ee1adSPankaj Gupta  *                  cmd - Command Number
179066ee1adSPankaj Gupta  *                  args - Command Args
180066ee1adSPankaj Gupta  * Return      :    SUCCESS is 0, or Error Code ( < 0)
181066ee1adSPankaj Gupta  * Description :    Updates the eSDHC registers cmdargs and xfertype
182066ee1adSPankaj Gupta  ***************************************************************************/
esdhc_send_cmd(struct mmc * mmc,uint32_t cmd,uint32_t args)183066ee1adSPankaj Gupta static int esdhc_send_cmd(struct mmc *mmc, uint32_t cmd, uint32_t args)
184066ee1adSPankaj Gupta {
185066ee1adSPankaj Gupta 	uint32_t val;
186066ee1adSPankaj Gupta 	uint64_t start_time;
187066ee1adSPankaj Gupta 	uint32_t xfertyp = 0;
188066ee1adSPankaj Gupta 
189066ee1adSPankaj Gupta 	esdhc_out32(&mmc->esdhc_regs->irqstat, ESDHC_IRQSTAT_CLEAR_ALL);
190066ee1adSPankaj Gupta 
191066ee1adSPankaj Gupta 	/* Wait for the command line & data line to be free */
192066ee1adSPankaj Gupta 	/* (poll the CIHB,CDIHB bit of the present state register) */
193066ee1adSPankaj Gupta 	start_time = get_timer_val(0);
194066ee1adSPankaj Gupta 	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
195066ee1adSPankaj Gupta 		val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
196066ee1adSPankaj Gupta 			(ESDHC_PRSSTAT_CIHB | ESDHC_PRSSTAT_CDIHB);
197066ee1adSPankaj Gupta 		if (val == 0U) {
198066ee1adSPankaj Gupta 			break;
199066ee1adSPankaj Gupta 		}
200066ee1adSPankaj Gupta 	}
201066ee1adSPankaj Gupta 
202066ee1adSPankaj Gupta 	val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
203066ee1adSPankaj Gupta 		(ESDHC_PRSSTAT_CIHB | ESDHC_PRSSTAT_CDIHB);
204066ee1adSPankaj Gupta 	if (val != 0U) {
205066ee1adSPankaj Gupta 		ERROR("SD send cmd: Command Line or Data Line Busy cmd = %x\n",
206066ee1adSPankaj Gupta 				cmd);
207066ee1adSPankaj Gupta 		return ERROR_ESDHC_BUSY;
208066ee1adSPankaj Gupta 	}
209066ee1adSPankaj Gupta 
210066ee1adSPankaj Gupta 	if (cmd == CMD2 || cmd == CMD9) {
211066ee1adSPankaj Gupta 		xfertyp |= ESDHC_XFERTYP_RSPTYP_136;
212066ee1adSPankaj Gupta 	} else  if (cmd == CMD7 || (cmd == CMD6 && mmc->card.type == MMC_CARD)) {
213066ee1adSPankaj Gupta 		xfertyp |= ESDHC_XFERTYP_RSPTYP_48_BUSY;
214066ee1adSPankaj Gupta 	} else if (cmd != CMD0) {
215066ee1adSPankaj Gupta 		xfertyp |= ESDHC_XFERTYP_RSPTYP_48;
216066ee1adSPankaj Gupta 	}
217066ee1adSPankaj Gupta 
218066ee1adSPankaj Gupta 	if (cmd == CMD2 || cmd == CMD9) {
219066ee1adSPankaj Gupta 		xfertyp |= ESDHC_XFERTYP_CCCEN; /* Command index check enable */
220066ee1adSPankaj Gupta 	} else if ((cmd != CMD0) && (cmd != ACMD41) && (cmd != CMD1)) {
221066ee1adSPankaj Gupta 		xfertyp = xfertyp | ESDHC_XFERTYP_CCCEN | ESDHC_XFERTYP_CICEN;
222066ee1adSPankaj Gupta 	}
223066ee1adSPankaj Gupta 
224066ee1adSPankaj Gupta 	if ((cmd == CMD8 || cmd == CMD14 || cmd == CMD19) &&
225066ee1adSPankaj Gupta 			mmc->card.type == MMC_CARD) {
226066ee1adSPankaj Gupta 		xfertyp |=  ESDHC_XFERTYP_DPSEL;
227066ee1adSPankaj Gupta 		if (cmd != CMD19) {
228066ee1adSPankaj Gupta 			xfertyp |= ESDHC_XFERTYP_DTDSEL;
229066ee1adSPankaj Gupta 		}
230066ee1adSPankaj Gupta 	}
231066ee1adSPankaj Gupta 
232066ee1adSPankaj Gupta 	if (cmd == CMD6 || cmd == CMD17 || cmd == CMD18 || cmd == CMD24 ||
233066ee1adSPankaj Gupta 	    cmd == ACMD51) {
234066ee1adSPankaj Gupta 		if (!(mmc->card.type == MMC_CARD && cmd == CMD6)) {
235066ee1adSPankaj Gupta 			if (cmd == CMD24) {
236066ee1adSPankaj Gupta 				xfertyp |= ESDHC_XFERTYP_DPSEL;
237066ee1adSPankaj Gupta 			} else {
238066ee1adSPankaj Gupta 				xfertyp |= (ESDHC_XFERTYP_DPSEL |
239066ee1adSPankaj Gupta 					    ESDHC_XFERTYP_DTDSEL);
240066ee1adSPankaj Gupta 			}
241066ee1adSPankaj Gupta 		}
242066ee1adSPankaj Gupta 
243066ee1adSPankaj Gupta 		if (cmd == CMD18) {
244066ee1adSPankaj Gupta 			xfertyp |= ESDHC_XFERTYP_BCEN;
245066ee1adSPankaj Gupta 			if (mmc->dma_support != 0) {
246066ee1adSPankaj Gupta 				/* Set BCEN of XFERTYP */
247066ee1adSPankaj Gupta 				xfertyp |= ESDHC_XFERTYP_DMAEN;
248066ee1adSPankaj Gupta 			}
249066ee1adSPankaj Gupta 		}
250066ee1adSPankaj Gupta 
251066ee1adSPankaj Gupta 		if ((cmd == CMD17 || cmd == CMD24) && (mmc->dma_support != 0)) {
252066ee1adSPankaj Gupta 			xfertyp |= ESDHC_XFERTYP_DMAEN;
253066ee1adSPankaj Gupta 		}
254066ee1adSPankaj Gupta 	}
255066ee1adSPankaj Gupta 
256066ee1adSPankaj Gupta 	xfertyp |= ((cmd & 0x3F) << 24);
257066ee1adSPankaj Gupta 	esdhc_out32(&mmc->esdhc_regs->cmdarg, args);
258066ee1adSPankaj Gupta 	esdhc_out32(&mmc->esdhc_regs->xfertyp, xfertyp);
259066ee1adSPankaj Gupta 
260066ee1adSPankaj Gupta #ifdef NXP_SD_DEBUG
261066ee1adSPankaj Gupta 	INFO("cmd = %d\n", cmd);
262066ee1adSPankaj Gupta 	INFO("args = %x\n", args);
263066ee1adSPankaj Gupta 	INFO("xfertyp: = %x\n", xfertyp);
264066ee1adSPankaj Gupta #endif
265066ee1adSPankaj Gupta 	return 0;
266066ee1adSPankaj Gupta }
267066ee1adSPankaj Gupta 
268066ee1adSPankaj Gupta /***************************************************************************
269066ee1adSPankaj Gupta  * Function    :    esdhc_wait_response
270066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
271066ee1adSPankaj Gupta  *                  response - Value updated
272066ee1adSPankaj Gupta  * Return      :    SUCCESS - Response Received
273066ee1adSPankaj Gupta  *                  COMMUNICATION_ERROR - Command not Complete
274066ee1adSPankaj Gupta  *                  COMMAND_ERROR - CIE, CCE or CEBE  error
275066ee1adSPankaj Gupta  *                  RESP_TIMEOUT - CTOE error
276066ee1adSPankaj Gupta  * Description :    Checks for successful command completion.
277066ee1adSPankaj Gupta  *                  Clears the CC bit at the end.
278066ee1adSPankaj Gupta  ***************************************************************************/
esdhc_wait_response(struct mmc * mmc,uint32_t * response)279066ee1adSPankaj Gupta static int esdhc_wait_response(struct mmc *mmc, uint32_t *response)
280066ee1adSPankaj Gupta {
281066ee1adSPankaj Gupta 	uint32_t val;
282066ee1adSPankaj Gupta 	uint64_t start_time;
283066ee1adSPankaj Gupta 	uint32_t status = 0U;
284066ee1adSPankaj Gupta 
285066ee1adSPankaj Gupta 	/* Wait for the command to complete */
286066ee1adSPankaj Gupta 	start_time = get_timer_val(0);
287066ee1adSPankaj Gupta 	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
288066ee1adSPankaj Gupta 		val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_CC;
289066ee1adSPankaj Gupta 		if (val != 0U) {
290066ee1adSPankaj Gupta 			break;
291066ee1adSPankaj Gupta 		}
292066ee1adSPankaj Gupta 	}
293066ee1adSPankaj Gupta 
294066ee1adSPankaj Gupta 	val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_CC;
295066ee1adSPankaj Gupta 	if (val == 0U) {
296066ee1adSPankaj Gupta 		ERROR("%s:IRQSTAT Cmd not complete(CC not set)\n", __func__);
297066ee1adSPankaj Gupta 		return ERROR_ESDHC_COMMUNICATION_ERROR;
298066ee1adSPankaj Gupta 	}
299066ee1adSPankaj Gupta 
300066ee1adSPankaj Gupta 	status = esdhc_in32(&mmc->esdhc_regs->irqstat);
301066ee1adSPankaj Gupta 
302066ee1adSPankaj Gupta 	/* Check whether the interrupt is a CRC, CTOE or CIE error */
303066ee1adSPankaj Gupta 	if ((status & (ESDHC_IRQSTAT_CIE | ESDHC_IRQSTAT_CEBE |
304066ee1adSPankaj Gupta 				ESDHC_IRQSTAT_CCE)) != 0) {
305066ee1adSPankaj Gupta 		ERROR("%s: IRQSTAT CRC, CEBE or CIE error = %x\n",
306066ee1adSPankaj Gupta 							__func__, status);
307066ee1adSPankaj Gupta 		return COMMAND_ERROR;
308066ee1adSPankaj Gupta 	}
309066ee1adSPankaj Gupta 
310066ee1adSPankaj Gupta 	if ((status & ESDHC_IRQSTAT_CTOE) != 0) {
311066ee1adSPankaj Gupta 		INFO("%s: IRQSTAT CTOE set = %x\n", __func__, status);
312066ee1adSPankaj Gupta 		return RESP_TIMEOUT;
313066ee1adSPankaj Gupta 	}
314066ee1adSPankaj Gupta 
315066ee1adSPankaj Gupta 	if ((status & ESDHC_IRQSTAT_DMAE) != 0) {
316066ee1adSPankaj Gupta 		ERROR("%s: IRQSTAT DMAE set = %x\n", __func__, status);
317066ee1adSPankaj Gupta 		return ERROR_ESDHC_DMA_ERROR;
318066ee1adSPankaj Gupta 	}
319066ee1adSPankaj Gupta 
320066ee1adSPankaj Gupta 	if (response != NULL) {
321066ee1adSPankaj Gupta 		/* Get response values from eSDHC CMDRSPx registers. */
322066ee1adSPankaj Gupta 		response[0] = esdhc_in32(&mmc->esdhc_regs->cmdrsp[0]);
323066ee1adSPankaj Gupta 		response[1] = esdhc_in32(&mmc->esdhc_regs->cmdrsp[1]);
324066ee1adSPankaj Gupta 		response[2] = esdhc_in32(&mmc->esdhc_regs->cmdrsp[2]);
325066ee1adSPankaj Gupta 		response[3] = esdhc_in32(&mmc->esdhc_regs->cmdrsp[3]);
326066ee1adSPankaj Gupta #ifdef NXP_SD_DEBUG
327066ee1adSPankaj Gupta 		INFO("Resp R1 R2 R3 R4\n");
328066ee1adSPankaj Gupta 		INFO("Resp R1 = %x\n", response[0]);
329066ee1adSPankaj Gupta 		INFO("R2 = %x\n", response[1]);
330066ee1adSPankaj Gupta 		INFO("R3 = %x\n", response[2]);
331066ee1adSPankaj Gupta 		INFO("R4 = %x\n", response[3]);
332066ee1adSPankaj Gupta 		INFO("\n");
333066ee1adSPankaj Gupta #endif
334066ee1adSPankaj Gupta 	}
335066ee1adSPankaj Gupta 
336066ee1adSPankaj Gupta 	/* Clear the CC bit - w1c */
337066ee1adSPankaj Gupta 	val = esdhc_in32(&mmc->esdhc_regs->irqstat) | ESDHC_IRQSTAT_CC;
338066ee1adSPankaj Gupta 	esdhc_out32(&mmc->esdhc_regs->irqstat, val);
339066ee1adSPankaj Gupta 
340066ee1adSPankaj Gupta 	return 0;
341066ee1adSPankaj Gupta }
342066ee1adSPankaj Gupta 
343066ee1adSPankaj Gupta /***************************************************************************
344066ee1adSPankaj Gupta  * Function    :    mmc_switch_to_high_frquency
345066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
346066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
347*1b491eeaSElyes Haouas  * Description :    mmc card below ver 4.0 does not support high speed
348066ee1adSPankaj Gupta  *                  freq = 20 MHz
349066ee1adSPankaj Gupta  *                  Send CMD6 (CMD_SWITCH_FUNC) With args 0x03B90100
350066ee1adSPankaj Gupta  *                  Send CMD13 (CMD_SEND_STATUS)
351066ee1adSPankaj Gupta  *                  if SWITCH Error, freq = 26 MHz
352066ee1adSPankaj Gupta  *                  if no error, freq = 52 MHz
353066ee1adSPankaj Gupta  ***************************************************************************/
mmc_switch_to_high_frquency(struct mmc * mmc)354066ee1adSPankaj Gupta static int mmc_switch_to_high_frquency(struct mmc *mmc)
355066ee1adSPankaj Gupta {
356066ee1adSPankaj Gupta 	int error;
357066ee1adSPankaj Gupta 	uint32_t response[4];
358066ee1adSPankaj Gupta 	uint64_t start_time;
359066ee1adSPankaj Gupta 
360066ee1adSPankaj Gupta 	mmc->card.bus_freq = MMC_SS_20MHZ;
361*1b491eeaSElyes Haouas 	/* mmc card below ver 4.0 does not support high speed */
362066ee1adSPankaj Gupta 	if (mmc->card.version < MMC_CARD_VERSION_4_X) {
363066ee1adSPankaj Gupta 		return 0;
364066ee1adSPankaj Gupta 	}
365066ee1adSPankaj Gupta 
366066ee1adSPankaj Gupta 	/* send switch cmd to change the card to High speed */
367066ee1adSPankaj Gupta 	error = esdhc_send_cmd(mmc, CMD_SWITCH_FUNC, SET_EXT_CSD_HS_TIMING);
368066ee1adSPankaj Gupta 	if (error != 0) {
369066ee1adSPankaj Gupta 		return error;
370066ee1adSPankaj Gupta 	}
371066ee1adSPankaj Gupta 	error = esdhc_wait_response(mmc, response);
372066ee1adSPankaj Gupta 	if (error != 0) {
373066ee1adSPankaj Gupta 		return error;
374066ee1adSPankaj Gupta 	}
375066ee1adSPankaj Gupta 
376066ee1adSPankaj Gupta 	start_time = get_timer_val(0);
377066ee1adSPankaj Gupta 	do {
378066ee1adSPankaj Gupta 		/* check the status for which error */
379066ee1adSPankaj Gupta 		error = esdhc_send_cmd(mmc,
380066ee1adSPankaj Gupta 				CMD_SEND_STATUS, mmc->card.rca << 16);
381066ee1adSPankaj Gupta 		if (error != 0) {
382066ee1adSPankaj Gupta 			return error;
383066ee1adSPankaj Gupta 		}
384066ee1adSPankaj Gupta 
385066ee1adSPankaj Gupta 		error = esdhc_wait_response(mmc, response);
386066ee1adSPankaj Gupta 		if (error != 0) {
387066ee1adSPankaj Gupta 			return error;
388066ee1adSPankaj Gupta 		}
389066ee1adSPankaj Gupta 	} while (((response[0] & SWITCH_ERROR) != 0) &&
390066ee1adSPankaj Gupta 			(get_timer_val(start_time) < SD_TIMEOUT));
391066ee1adSPankaj Gupta 
392066ee1adSPankaj Gupta 	/* Check for the present state of card */
393066ee1adSPankaj Gupta 	if ((response[0] & SWITCH_ERROR) != 0) {
394066ee1adSPankaj Gupta 		mmc->card.bus_freq = MMC_HS_26MHZ;
395066ee1adSPankaj Gupta 	} else {
396066ee1adSPankaj Gupta 		mmc->card.bus_freq = MMC_HS_52MHZ;
397066ee1adSPankaj Gupta 	}
398066ee1adSPankaj Gupta 
399066ee1adSPankaj Gupta 	return 0;
400066ee1adSPankaj Gupta }
401066ee1adSPankaj Gupta 
402066ee1adSPankaj Gupta /***************************************************************************
403066ee1adSPankaj Gupta  * Function    :    esdhc_set_data_attributes
404066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
405066ee1adSPankaj Gupta  *                  blkcnt
406066ee1adSPankaj Gupta  *                  blklen
407066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
408066ee1adSPankaj Gupta  * Description :    Set block attributes and watermark level register
409066ee1adSPankaj Gupta  ***************************************************************************/
esdhc_set_data_attributes(struct mmc * mmc,uint32_t * dest_ptr,uint32_t blkcnt,uint32_t blklen)410066ee1adSPankaj Gupta static int esdhc_set_data_attributes(struct mmc *mmc, uint32_t *dest_ptr,
411066ee1adSPankaj Gupta 		uint32_t blkcnt, uint32_t blklen)
412066ee1adSPankaj Gupta {
413066ee1adSPankaj Gupta 	uint32_t val;
414066ee1adSPankaj Gupta 	uint64_t start_time;
415066ee1adSPankaj Gupta 	uint32_t wml;
416066ee1adSPankaj Gupta 	uint32_t wl;
417066ee1adSPankaj Gupta 	uint32_t dst = (uint32_t)((uint64_t)(dest_ptr));
418066ee1adSPankaj Gupta 
419066ee1adSPankaj Gupta 	/* set blkattr when no transactions are executing */
420066ee1adSPankaj Gupta 	start_time = get_timer_val(0);
421066ee1adSPankaj Gupta 	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
422066ee1adSPankaj Gupta 		val = esdhc_in32(&mmc->esdhc_regs->prsstat) & ESDHC_PRSSTAT_DLA;
423066ee1adSPankaj Gupta 		if (val == 0U) {
424066ee1adSPankaj Gupta 			break;
425066ee1adSPankaj Gupta 		}
426066ee1adSPankaj Gupta 	}
427066ee1adSPankaj Gupta 
428066ee1adSPankaj Gupta 	val = esdhc_in32(&mmc->esdhc_regs->prsstat) & ESDHC_PRSSTAT_DLA;
429066ee1adSPankaj Gupta 	if (val != 0U) {
430066ee1adSPankaj Gupta 		ERROR("%s: Data line active.Can't set attribute\n", __func__);
431066ee1adSPankaj Gupta 		return ERROR_ESDHC_COMMUNICATION_ERROR;
432066ee1adSPankaj Gupta 	}
433066ee1adSPankaj Gupta 
434066ee1adSPankaj Gupta 	wml = esdhc_in32(&mmc->esdhc_regs->wml);
435066ee1adSPankaj Gupta 	wml &= ~(ESDHC_WML_WR_BRST_MASK | ESDHC_WML_RD_BRST_MASK |
436066ee1adSPankaj Gupta 			ESDHC_WML_RD_WML_MASK | ESDHC_WML_WR_WML_MASK);
437066ee1adSPankaj Gupta 
438066ee1adSPankaj Gupta 	if ((mmc->dma_support != 0) && (dest_ptr != NULL)) {
439066ee1adSPankaj Gupta 		/* Set burst length to 128 bytes */
440066ee1adSPankaj Gupta 		esdhc_out32(&mmc->esdhc_regs->wml,
441066ee1adSPankaj Gupta 				wml | ESDHC_WML_WR_BRST(BURST_128_BYTES));
442066ee1adSPankaj Gupta 		esdhc_out32(&mmc->esdhc_regs->wml,
443066ee1adSPankaj Gupta 				wml | ESDHC_WML_RD_BRST(BURST_128_BYTES));
444066ee1adSPankaj Gupta 
445066ee1adSPankaj Gupta 		/* Set DMA System Destination Address */
446066ee1adSPankaj Gupta 		esdhc_out32(&mmc->esdhc_regs->dsaddr, dst);
447066ee1adSPankaj Gupta 	} else {
448066ee1adSPankaj Gupta 		wl = (blklen >= BLOCK_LEN_512) ?
449066ee1adSPankaj Gupta 			WML_512_BYTES : ((blklen + 3) / 4);
450066ee1adSPankaj Gupta 		/* Set 'Read Water Mark Level' register */
451066ee1adSPankaj Gupta 		esdhc_out32(&mmc->esdhc_regs->wml, wml | ESDHC_WML_RD_WML(wl));
452066ee1adSPankaj Gupta 	}
453066ee1adSPankaj Gupta 
454066ee1adSPankaj Gupta 	/* Configure block Attributes register */
455066ee1adSPankaj Gupta 	esdhc_out32(&mmc->esdhc_regs->blkattr,
456066ee1adSPankaj Gupta 		ESDHC_BLKATTR_BLKCNT(blkcnt) | ESDHC_BLKATTR_BLKSZE(blklen));
457066ee1adSPankaj Gupta 
458066ee1adSPankaj Gupta 	mmc->block_len = blklen;
459066ee1adSPankaj Gupta 
460066ee1adSPankaj Gupta 	return 0;
461066ee1adSPankaj Gupta }
462066ee1adSPankaj Gupta 
463066ee1adSPankaj Gupta /***************************************************************************
464066ee1adSPankaj Gupta  * Function    :    esdhc_read_data_nodma
465066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
466*1b491eeaSElyes Haouas  *                  dest_ptr - Buffer where read data is to be copied
467066ee1adSPankaj Gupta  *                  len - Length of Data to be read
468066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
469066ee1adSPankaj Gupta  * Description :    Read data from the sdhc buffer without using DMA
470066ee1adSPankaj Gupta  *                  and using polling mode
471066ee1adSPankaj Gupta  ***************************************************************************/
esdhc_read_data_nodma(struct mmc * mmc,void * dest_ptr,uint32_t len)472066ee1adSPankaj Gupta static int esdhc_read_data_nodma(struct mmc *mmc, void *dest_ptr, uint32_t len)
473066ee1adSPankaj Gupta {
474066ee1adSPankaj Gupta 	uint32_t i = 0U;
475066ee1adSPankaj Gupta 	uint32_t status;
476066ee1adSPankaj Gupta 	uint32_t num_blocks;
477066ee1adSPankaj Gupta 	uint32_t *dst = (uint32_t *)dest_ptr;
478066ee1adSPankaj Gupta 	uint32_t val;
479066ee1adSPankaj Gupta 	uint64_t start_time;
480066ee1adSPankaj Gupta 
481066ee1adSPankaj Gupta 	num_blocks = len / mmc->block_len;
482066ee1adSPankaj Gupta 
483066ee1adSPankaj Gupta 	while ((num_blocks--) != 0U) {
484066ee1adSPankaj Gupta 
485066ee1adSPankaj Gupta 		start_time = get_timer_val(0);
486066ee1adSPankaj Gupta 		while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
487066ee1adSPankaj Gupta 			val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
488066ee1adSPankaj Gupta 				ESDHC_PRSSTAT_BREN;
489066ee1adSPankaj Gupta 			if (val != 0U) {
490066ee1adSPankaj Gupta 				break;
491066ee1adSPankaj Gupta 			}
492066ee1adSPankaj Gupta 		}
493066ee1adSPankaj Gupta 
494066ee1adSPankaj Gupta 		val = esdhc_in32(&mmc->esdhc_regs->prsstat)
495066ee1adSPankaj Gupta 			& ESDHC_PRSSTAT_BREN;
496066ee1adSPankaj Gupta 		if (val == 0U) {
497066ee1adSPankaj Gupta 			return ERROR_ESDHC_COMMUNICATION_ERROR;
498066ee1adSPankaj Gupta 		}
499066ee1adSPankaj Gupta 
500066ee1adSPankaj Gupta 		for (i = 0U, status = esdhc_in32(&mmc->esdhc_regs->irqstat);
501066ee1adSPankaj Gupta 				i < mmc->block_len / 4;    i++, dst++) {
502066ee1adSPankaj Gupta 			/* get data from data port */
503066ee1adSPankaj Gupta 			val = mmio_read_32(
504066ee1adSPankaj Gupta 					(uintptr_t)&mmc->esdhc_regs->datport);
505066ee1adSPankaj Gupta 			esdhc_out32(dst, val);
506066ee1adSPankaj Gupta 			/* Increment destination pointer */
507066ee1adSPankaj Gupta 			status = esdhc_in32(&mmc->esdhc_regs->irqstat);
508066ee1adSPankaj Gupta 		}
509066ee1adSPankaj Gupta 		/* Check whether the interrupt is an DTOE/DCE/DEBE */
510066ee1adSPankaj Gupta 		if ((status & (ESDHC_IRQSTAT_DTOE | ESDHC_IRQSTAT_DCE |
511066ee1adSPankaj Gupta 					ESDHC_IRQSTAT_DEBE)) != 0) {
512066ee1adSPankaj Gupta 			ERROR("SD read error - DTOE, DCE, DEBE bit set = %x\n",
513066ee1adSPankaj Gupta 									status);
514066ee1adSPankaj Gupta 			return ERROR_ESDHC_COMMUNICATION_ERROR;
515066ee1adSPankaj Gupta 		}
516066ee1adSPankaj Gupta 	}
517066ee1adSPankaj Gupta 
518066ee1adSPankaj Gupta 	/* Wait for TC */
519066ee1adSPankaj Gupta 
520066ee1adSPankaj Gupta 	start_time = get_timer_val(0);
521066ee1adSPankaj Gupta 	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
522066ee1adSPankaj Gupta 		val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_TC;
523066ee1adSPankaj Gupta 		if (val != 0U) {
524066ee1adSPankaj Gupta 			break;
525066ee1adSPankaj Gupta 		}
526066ee1adSPankaj Gupta 	}
527066ee1adSPankaj Gupta 
528066ee1adSPankaj Gupta 	val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_TC;
529066ee1adSPankaj Gupta 	if (val == 0U) {
530066ee1adSPankaj Gupta 		ERROR("SD read timeout: Transfer bit not set in IRQSTAT\n");
531066ee1adSPankaj Gupta 		return ERROR_ESDHC_COMMUNICATION_ERROR;
532066ee1adSPankaj Gupta 	}
533066ee1adSPankaj Gupta 
534066ee1adSPankaj Gupta 	return 0;
535066ee1adSPankaj Gupta }
536066ee1adSPankaj Gupta 
537066ee1adSPankaj Gupta /***************************************************************************
538066ee1adSPankaj Gupta  * Function    :    esdhc_write_data_nodma
539066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
540066ee1adSPankaj Gupta  *                  src_ptr - Buffer where data is copied from
541066ee1adSPankaj Gupta  *                  len - Length of Data to be written
542066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
543066ee1adSPankaj Gupta  * Description :    Write data to the sdhc buffer without using DMA
544066ee1adSPankaj Gupta  *                  and using polling mode
545066ee1adSPankaj Gupta  ***************************************************************************/
esdhc_write_data_nodma(struct mmc * mmc,void * src_ptr,uint32_t len)546066ee1adSPankaj Gupta static int esdhc_write_data_nodma(struct mmc *mmc, void *src_ptr, uint32_t len)
547066ee1adSPankaj Gupta {
548066ee1adSPankaj Gupta 	uint32_t i = 0U;
549066ee1adSPankaj Gupta 	uint32_t status;
550066ee1adSPankaj Gupta 	uint32_t num_blocks;
551066ee1adSPankaj Gupta 	uint32_t *src = (uint32_t *)src_ptr;
552066ee1adSPankaj Gupta 	uint32_t val;
553066ee1adSPankaj Gupta 	uint64_t start_time;
554066ee1adSPankaj Gupta 
555066ee1adSPankaj Gupta 	num_blocks = len / mmc->block_len;
556066ee1adSPankaj Gupta 
557066ee1adSPankaj Gupta 	while ((num_blocks--) != 0U) {
558066ee1adSPankaj Gupta 		start_time = get_timer_val(0);
559066ee1adSPankaj Gupta 		while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
560066ee1adSPankaj Gupta 			val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
561066ee1adSPankaj Gupta 					 ESDHC_PRSSTAT_BWEN;
562066ee1adSPankaj Gupta 			if (val != 0U) {
563066ee1adSPankaj Gupta 				break;
564066ee1adSPankaj Gupta 			}
565066ee1adSPankaj Gupta 		}
566066ee1adSPankaj Gupta 
567066ee1adSPankaj Gupta 		val = esdhc_in32(&mmc->esdhc_regs->prsstat) &
568066ee1adSPankaj Gupta 				 ESDHC_PRSSTAT_BWEN;
569066ee1adSPankaj Gupta 		if (val == 0U) {
570066ee1adSPankaj Gupta 			return ERROR_ESDHC_COMMUNICATION_ERROR;
571066ee1adSPankaj Gupta 		}
572066ee1adSPankaj Gupta 
573066ee1adSPankaj Gupta 		for (i = 0U, status = esdhc_in32(&mmc->esdhc_regs->irqstat);
574066ee1adSPankaj Gupta 		     i < mmc->block_len / 4; i++, src++) {
575066ee1adSPankaj Gupta 			val = esdhc_in32(src);
576066ee1adSPankaj Gupta 			/* put data to data port */
577066ee1adSPankaj Gupta 			mmio_write_32((uintptr_t)&mmc->esdhc_regs->datport,
578066ee1adSPankaj Gupta 				      val);
579066ee1adSPankaj Gupta 			/* Increment source pointer */
580066ee1adSPankaj Gupta 			status = esdhc_in32(&mmc->esdhc_regs->irqstat);
581066ee1adSPankaj Gupta 		}
582066ee1adSPankaj Gupta 		/* Check whether the interrupt is an DTOE/DCE/DEBE */
583066ee1adSPankaj Gupta 		if ((status & (ESDHC_IRQSTAT_DTOE | ESDHC_IRQSTAT_DCE |
584066ee1adSPankaj Gupta 					ESDHC_IRQSTAT_DEBE)) != 0) {
585066ee1adSPankaj Gupta 			ERROR("SD write error - DTOE, DCE, DEBE bit set = %x\n",
586066ee1adSPankaj Gupta 			      status);
587066ee1adSPankaj Gupta 			return ERROR_ESDHC_COMMUNICATION_ERROR;
588066ee1adSPankaj Gupta 		}
589066ee1adSPankaj Gupta 	}
590066ee1adSPankaj Gupta 
591066ee1adSPankaj Gupta 	/* Wait for TC */
592066ee1adSPankaj Gupta 	start_time = get_timer_val(0);
593066ee1adSPankaj Gupta 	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
594066ee1adSPankaj Gupta 		val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_TC;
595066ee1adSPankaj Gupta 		if (val != 0U) {
596066ee1adSPankaj Gupta 			break;
597066ee1adSPankaj Gupta 		}
598066ee1adSPankaj Gupta 	}
599066ee1adSPankaj Gupta 
600066ee1adSPankaj Gupta 	val = esdhc_in32(&mmc->esdhc_regs->irqstat) & ESDHC_IRQSTAT_TC;
601066ee1adSPankaj Gupta 	if (val == 0U) {
602066ee1adSPankaj Gupta 		ERROR("SD write timeout: Transfer bit not set in IRQSTAT\n");
603066ee1adSPankaj Gupta 		return ERROR_ESDHC_COMMUNICATION_ERROR;
604066ee1adSPankaj Gupta 	}
605066ee1adSPankaj Gupta 
606066ee1adSPankaj Gupta 	return 0;
607066ee1adSPankaj Gupta }
608066ee1adSPankaj Gupta 
609066ee1adSPankaj Gupta /***************************************************************************
610066ee1adSPankaj Gupta  * Function    :    esdhc_read_data_dma
611066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
612066ee1adSPankaj Gupta  *                  len - Length of Data to be read
613066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
614066ee1adSPankaj Gupta  * Description :    Read data from the sd card using DMA.
615066ee1adSPankaj Gupta  ***************************************************************************/
esdhc_read_data_dma(struct mmc * mmc,uint32_t len)616066ee1adSPankaj Gupta static int esdhc_read_data_dma(struct mmc *mmc, uint32_t len)
617066ee1adSPankaj Gupta {
618066ee1adSPankaj Gupta 	uint32_t status;
619066ee1adSPankaj Gupta 	uint32_t tblk;
620066ee1adSPankaj Gupta 	uint64_t start_time;
621066ee1adSPankaj Gupta 
622066ee1adSPankaj Gupta 	tblk = SD_BLOCK_TIMEOUT * (len / mmc->block_len);
623066ee1adSPankaj Gupta 
624066ee1adSPankaj Gupta 	start_time = get_timer_val(0);
625066ee1adSPankaj Gupta 
626066ee1adSPankaj Gupta 	/* poll till TC is set */
627066ee1adSPankaj Gupta 	do {
628066ee1adSPankaj Gupta 		status = esdhc_in32(&mmc->esdhc_regs->irqstat);
629066ee1adSPankaj Gupta 
630066ee1adSPankaj Gupta 		if ((status & (ESDHC_IRQSTAT_DEBE | ESDHC_IRQSTAT_DCE
631066ee1adSPankaj Gupta 					| ESDHC_IRQSTAT_DTOE)) != 0) {
632066ee1adSPankaj Gupta 			ERROR("SD read error - DTOE, DCE, DEBE bit set = %x\n",
633066ee1adSPankaj Gupta 								 status);
634066ee1adSPankaj Gupta 			return ERROR_ESDHC_COMMUNICATION_ERROR;
635066ee1adSPankaj Gupta 		}
636066ee1adSPankaj Gupta 
637066ee1adSPankaj Gupta 		if ((status & ESDHC_IRQSTAT_DMAE) != 0) {
638066ee1adSPankaj Gupta 			ERROR("SD read error - DMA error = %x\n", status);
639066ee1adSPankaj Gupta 			return ERROR_ESDHC_DMA_ERROR;
640066ee1adSPankaj Gupta 		}
641066ee1adSPankaj Gupta 
642066ee1adSPankaj Gupta 	} while (((status & ESDHC_IRQSTAT_TC) == 0) &&
643066ee1adSPankaj Gupta 		((esdhc_in32(&mmc->esdhc_regs->prsstat) & ESDHC_PRSSTAT_DLA) != 0) &&
644066ee1adSPankaj Gupta 		(get_timer_val(start_time) < SD_TIMEOUT_HIGH + tblk));
645066ee1adSPankaj Gupta 
646066ee1adSPankaj Gupta 	if (get_timer_val(start_time) > SD_TIMEOUT_HIGH + tblk) {
647066ee1adSPankaj Gupta 		ERROR("SD read DMA timeout\n");
648066ee1adSPankaj Gupta 		return ERROR_ESDHC_COMMUNICATION_ERROR;
649066ee1adSPankaj Gupta 	}
650066ee1adSPankaj Gupta 
651066ee1adSPankaj Gupta 	return 0;
652066ee1adSPankaj Gupta }
653066ee1adSPankaj Gupta 
654066ee1adSPankaj Gupta /***************************************************************************
655066ee1adSPankaj Gupta  * Function    :    esdhc_write_data_dma
656066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
657066ee1adSPankaj Gupta  *                  len - Length of Data to be written
658066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
659066ee1adSPankaj Gupta  * Description :    Write data to the sd card using DMA.
660066ee1adSPankaj Gupta  ***************************************************************************/
esdhc_write_data_dma(struct mmc * mmc,uint32_t len)661066ee1adSPankaj Gupta static int esdhc_write_data_dma(struct mmc *mmc, uint32_t len)
662066ee1adSPankaj Gupta {
663066ee1adSPankaj Gupta 	uint32_t status;
664066ee1adSPankaj Gupta 	uint32_t tblk;
665066ee1adSPankaj Gupta 	uint64_t start_time;
666066ee1adSPankaj Gupta 
667066ee1adSPankaj Gupta 	tblk = SD_BLOCK_TIMEOUT * (len / mmc->block_len);
668066ee1adSPankaj Gupta 
669066ee1adSPankaj Gupta 	start_time = get_timer_val(0);
670066ee1adSPankaj Gupta 
671066ee1adSPankaj Gupta 	/* poll till TC is set */
672066ee1adSPankaj Gupta 	do {
673066ee1adSPankaj Gupta 		status = esdhc_in32(&mmc->esdhc_regs->irqstat);
674066ee1adSPankaj Gupta 
675066ee1adSPankaj Gupta 		if ((status & (ESDHC_IRQSTAT_DEBE | ESDHC_IRQSTAT_DCE
676066ee1adSPankaj Gupta 					| ESDHC_IRQSTAT_DTOE)) != 0) {
677066ee1adSPankaj Gupta 			ERROR("SD write error - DTOE, DCE, DEBE bit set = %x\n",
678066ee1adSPankaj Gupta 			      status);
679066ee1adSPankaj Gupta 			return ERROR_ESDHC_COMMUNICATION_ERROR;
680066ee1adSPankaj Gupta 		}
681066ee1adSPankaj Gupta 
682066ee1adSPankaj Gupta 		if ((status & ESDHC_IRQSTAT_DMAE) != 0) {
683066ee1adSPankaj Gupta 			ERROR("SD write error - DMA error = %x\n", status);
684066ee1adSPankaj Gupta 			return ERROR_ESDHC_DMA_ERROR;
685066ee1adSPankaj Gupta 		}
686066ee1adSPankaj Gupta 	} while (((status & ESDHC_IRQSTAT_TC) == 0) &&
687066ee1adSPankaj Gupta 		((esdhc_in32(&mmc->esdhc_regs->prsstat) & ESDHC_PRSSTAT_DLA) != 0) &&
688066ee1adSPankaj Gupta 		(get_timer_val(start_time) < SD_TIMEOUT_HIGH + tblk));
689066ee1adSPankaj Gupta 
690066ee1adSPankaj Gupta 	if (get_timer_val(start_time) > SD_TIMEOUT_HIGH + tblk) {
691066ee1adSPankaj Gupta 		ERROR("SD write DMA timeout\n");
692066ee1adSPankaj Gupta 		return ERROR_ESDHC_COMMUNICATION_ERROR;
693066ee1adSPankaj Gupta 	}
694066ee1adSPankaj Gupta 
695066ee1adSPankaj Gupta 	return 0;
696066ee1adSPankaj Gupta }
697066ee1adSPankaj Gupta 
698066ee1adSPankaj Gupta /***************************************************************************
699066ee1adSPankaj Gupta  * Function    :    esdhc_read_data
700066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
701*1b491eeaSElyes Haouas  *                  dest_ptr - Buffer where read data is to be copied
702066ee1adSPankaj Gupta  *                  len - Length of Data to be read
703066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
704066ee1adSPankaj Gupta  * Description :    Calls esdhc_read_data_nodma and clear interrupt status
705066ee1adSPankaj Gupta  ***************************************************************************/
esdhc_read_data(struct mmc * mmc,void * dest_ptr,uint32_t len)706066ee1adSPankaj Gupta int esdhc_read_data(struct mmc *mmc, void *dest_ptr, uint32_t len)
707066ee1adSPankaj Gupta {
708066ee1adSPankaj Gupta 	int ret;
709066ee1adSPankaj Gupta 
710066ee1adSPankaj Gupta 	if (mmc->dma_support && len > 64) {
711066ee1adSPankaj Gupta 		ret = esdhc_read_data_dma(mmc, len);
712066ee1adSPankaj Gupta 	} else {
713066ee1adSPankaj Gupta 		ret = esdhc_read_data_nodma(mmc, dest_ptr, len);
714066ee1adSPankaj Gupta 	}
715066ee1adSPankaj Gupta 
716066ee1adSPankaj Gupta 	/* clear interrupt status */
717066ee1adSPankaj Gupta 	esdhc_out32(&mmc->esdhc_regs->irqstat, ESDHC_IRQSTAT_CLEAR_ALL);
718066ee1adSPankaj Gupta 
719066ee1adSPankaj Gupta 	return ret;
720066ee1adSPankaj Gupta }
721066ee1adSPankaj Gupta 
722066ee1adSPankaj Gupta /***************************************************************************
723066ee1adSPankaj Gupta  * Function    :    esdhc_write_data
724066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
725066ee1adSPankaj Gupta  *                  src_ptr - Buffer where data is copied from
726066ee1adSPankaj Gupta  *                  len - Length of Data to be written
727066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
728066ee1adSPankaj Gupta  * Description :    Calls esdhc_write_data_nodma and clear interrupt status
729066ee1adSPankaj Gupta  ***************************************************************************/
esdhc_write_data(struct mmc * mmc,void * src_ptr,uint32_t len)730066ee1adSPankaj Gupta int esdhc_write_data(struct mmc *mmc, void *src_ptr, uint32_t len)
731066ee1adSPankaj Gupta {
732066ee1adSPankaj Gupta 	int ret;
733066ee1adSPankaj Gupta 
734066ee1adSPankaj Gupta 	if (mmc->dma_support && len > 64) {
735066ee1adSPankaj Gupta 		ret = esdhc_write_data_dma(mmc, len);
736066ee1adSPankaj Gupta 	} else {
737066ee1adSPankaj Gupta 		ret = esdhc_write_data_nodma(mmc, src_ptr, len);
738066ee1adSPankaj Gupta 	}
739066ee1adSPankaj Gupta 
740066ee1adSPankaj Gupta 	/* clear interrupt status */
741066ee1adSPankaj Gupta 	esdhc_out32(&mmc->esdhc_regs->irqstat, ESDHC_IRQSTAT_CLEAR_ALL);
742066ee1adSPankaj Gupta 
743066ee1adSPankaj Gupta 	return ret;
744066ee1adSPankaj Gupta }
745066ee1adSPankaj Gupta 
746066ee1adSPankaj Gupta /***************************************************************************
747066ee1adSPankaj Gupta  * Function    :    sd_switch_to_high_freq
748066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
749066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
750066ee1adSPankaj Gupta  * Description :    1. Send ACMD51 (CMD_SEND_SCR)
751066ee1adSPankaj Gupta  *                  2. Read the SCR to check if card supports higher freq
752066ee1adSPankaj Gupta  *                  3. check version from SCR
753066ee1adSPankaj Gupta  *                  4. If SD 1.0, return (no Switch) freq = 25 MHz.
754066ee1adSPankaj Gupta  *                  5. Send CMD6 (CMD_SWITCH_FUNC) with args 0x00FFFFF1 to
755066ee1adSPankaj Gupta  *                     check the status of switch func
756066ee1adSPankaj Gupta  *                  6. Send CMD6 (CMD_SWITCH_FUNC) With args 0x80FFFFF1 to
757066ee1adSPankaj Gupta  *                     switch to high frequency = 50 Mhz
758066ee1adSPankaj Gupta  ***************************************************************************/
sd_switch_to_high_freq(struct mmc * mmc)759066ee1adSPankaj Gupta static int sd_switch_to_high_freq(struct mmc *mmc)
760066ee1adSPankaj Gupta {
761066ee1adSPankaj Gupta 	int err;
762066ee1adSPankaj Gupta 	uint8_t scr[8];
763066ee1adSPankaj Gupta 	uint8_t status[64];
764066ee1adSPankaj Gupta 	uint32_t response[4];
765066ee1adSPankaj Gupta 	uint32_t version;
766066ee1adSPankaj Gupta 	uint32_t count;
767066ee1adSPankaj Gupta 	uint32_t sd_versions[] = {SD_CARD_VERSION_1_0, SD_CARD_VERSION_1_10,
768066ee1adSPankaj Gupta 		SD_CARD_VERSION_2_0};
769066ee1adSPankaj Gupta 
770066ee1adSPankaj Gupta 	mmc->card.bus_freq = SD_SS_25MHZ;
771066ee1adSPankaj Gupta 	/* Send Application command */
772066ee1adSPankaj Gupta 	err = esdhc_send_cmd(mmc, CMD_APP_CMD, mmc->card.rca << 16);
773066ee1adSPankaj Gupta 	if (err != 0) {
774066ee1adSPankaj Gupta 		return err;
775066ee1adSPankaj Gupta 	}
776066ee1adSPankaj Gupta 
777066ee1adSPankaj Gupta 	err = esdhc_wait_response(mmc, response);
778066ee1adSPankaj Gupta 	if (err != 0) {
779066ee1adSPankaj Gupta 		return err;
780066ee1adSPankaj Gupta 	}
781066ee1adSPankaj Gupta 
782066ee1adSPankaj Gupta 	esdhc_set_data_attributes(mmc, NULL, 1, 8);
783066ee1adSPankaj Gupta 	/* Read the SCR to find out if this card supports higher speeds */
784066ee1adSPankaj Gupta 	err = esdhc_send_cmd(mmc, CMD_SEND_SCR,  mmc->card.rca << 16);
785066ee1adSPankaj Gupta 	if (err != 0) {
786066ee1adSPankaj Gupta 		return err;
787066ee1adSPankaj Gupta 	}
788066ee1adSPankaj Gupta 	err = esdhc_wait_response(mmc, response);
789066ee1adSPankaj Gupta 	if (err != 0) {
790066ee1adSPankaj Gupta 		return err;
791066ee1adSPankaj Gupta 	}
792066ee1adSPankaj Gupta 
793066ee1adSPankaj Gupta 	/* read 8 bytes of scr data */
794066ee1adSPankaj Gupta 	err = esdhc_read_data(mmc, scr, 8U);
795066ee1adSPankaj Gupta 	if (err != 0) {
796066ee1adSPankaj Gupta 		return ERROR_ESDHC_COMMUNICATION_ERROR;
797066ee1adSPankaj Gupta 	}
798066ee1adSPankaj Gupta 
799066ee1adSPankaj Gupta 	/* check version from SCR */
800066ee1adSPankaj Gupta 	version = scr[0] & U(0xF);
801066ee1adSPankaj Gupta 	if (version <= 2U) {
802066ee1adSPankaj Gupta 		mmc->card.version = sd_versions[version];
803066ee1adSPankaj Gupta 	} else {
804066ee1adSPankaj Gupta 		mmc->card.version = SD_CARD_VERSION_2_0;
805066ee1adSPankaj Gupta 	}
806066ee1adSPankaj Gupta 
807066ee1adSPankaj Gupta 	/* does not support switch func */
808066ee1adSPankaj Gupta 	if (mmc->card.version == SD_CARD_VERSION_1_0) {
809066ee1adSPankaj Gupta 		return 0;
810066ee1adSPankaj Gupta 	}
811066ee1adSPankaj Gupta 
812066ee1adSPankaj Gupta 	/* read 64 bytes of status */
813066ee1adSPankaj Gupta 	esdhc_set_data_attributes(mmc, NULL, 1U, 64U);
814066ee1adSPankaj Gupta 
815066ee1adSPankaj Gupta 	/* check the status of switch func */
816066ee1adSPankaj Gupta 	for (count = 0U; count < 4U; count++) {
817066ee1adSPankaj Gupta 		err = esdhc_send_cmd(mmc, CMD_SWITCH_FUNC,
818066ee1adSPankaj Gupta 				SD_SWITCH_FUNC_CHECK_MODE);
819066ee1adSPankaj Gupta 		if (err != 0) {
820066ee1adSPankaj Gupta 			return err;
821066ee1adSPankaj Gupta 		}
822066ee1adSPankaj Gupta 		err = esdhc_wait_response(mmc, response);
823066ee1adSPankaj Gupta 		if (err != 0) {
824066ee1adSPankaj Gupta 			return err;
825066ee1adSPankaj Gupta 		}
826066ee1adSPankaj Gupta 		/* read 64 bytes of scr data */
827066ee1adSPankaj Gupta 		err = esdhc_read_data(mmc, status, 64U);
828066ee1adSPankaj Gupta 		if (err != 0) {
829066ee1adSPankaj Gupta 			return ERROR_ESDHC_COMMUNICATION_ERROR;
830066ee1adSPankaj Gupta 		}
831066ee1adSPankaj Gupta 
832066ee1adSPankaj Gupta 		if ((status[29] & SD_SWITCH_FUNC_HIGH_SPEED) == 0) {
833066ee1adSPankaj Gupta 			break;
834066ee1adSPankaj Gupta 		}
835066ee1adSPankaj Gupta 	}
836066ee1adSPankaj Gupta 
837066ee1adSPankaj Gupta 	if ((status[13] & SD_SWITCH_FUNC_HIGH_SPEED) == 0) {
838066ee1adSPankaj Gupta 		return 0;
839066ee1adSPankaj Gupta 	}
840066ee1adSPankaj Gupta 
841066ee1adSPankaj Gupta 	/* SWITCH */
842066ee1adSPankaj Gupta 	esdhc_set_data_attributes(mmc, NULL, 1, 64);
843066ee1adSPankaj Gupta 	err = esdhc_send_cmd(mmc, CMD_SWITCH_FUNC, SD_SWITCH_FUNC_SWITCH_MODE);
844066ee1adSPankaj Gupta 	if (err != 0) {
845066ee1adSPankaj Gupta 		return err;
846066ee1adSPankaj Gupta 	}
847066ee1adSPankaj Gupta 	err = esdhc_wait_response(mmc, response);
848066ee1adSPankaj Gupta 	if (err != 0) {
849066ee1adSPankaj Gupta 		return err;
850066ee1adSPankaj Gupta 	}
851066ee1adSPankaj Gupta 
852066ee1adSPankaj Gupta 	err = esdhc_read_data(mmc, status, 64U);
853066ee1adSPankaj Gupta 	if (err != 0) {
854066ee1adSPankaj Gupta 		return ERROR_ESDHC_COMMUNICATION_ERROR;
855066ee1adSPankaj Gupta 	}
856066ee1adSPankaj Gupta 
857066ee1adSPankaj Gupta 	if ((status[16]) == U(0x01)) {
858066ee1adSPankaj Gupta 		mmc->card.bus_freq = SD_HS_50MHZ;
859066ee1adSPankaj Gupta 	}
860066ee1adSPankaj Gupta 
861066ee1adSPankaj Gupta 	return 0;
862066ee1adSPankaj Gupta }
863066ee1adSPankaj Gupta 
864066ee1adSPankaj Gupta /***************************************************************************
865066ee1adSPankaj Gupta  * Function    :    change_state_to_transfer_state
866066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
867066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
868066ee1adSPankaj Gupta  * Description :    1. Send CMD7 (CMD_SELECT_CARD) to toggles the card
869066ee1adSPankaj Gupta  *                     between stand-by and transfer state
870066ee1adSPankaj Gupta  *                  2. Send CMD13 (CMD_SEND_STATUS) to check state as
871066ee1adSPankaj Gupta  *                     Transfer State
872066ee1adSPankaj Gupta  ***************************************************************************/
change_state_to_transfer_state(struct mmc * mmc)873066ee1adSPankaj Gupta static int change_state_to_transfer_state(struct mmc *mmc)
874066ee1adSPankaj Gupta {
875066ee1adSPankaj Gupta 	int error = 0;
876066ee1adSPankaj Gupta 	uint32_t response[4];
877066ee1adSPankaj Gupta 	uint64_t start_time;
878066ee1adSPankaj Gupta 
879066ee1adSPankaj Gupta 	/* Command CMD_SELECT_CARD/CMD7 toggles the card between stand-by
880066ee1adSPankaj Gupta 	 * and transfer states
881066ee1adSPankaj Gupta 	 */
882066ee1adSPankaj Gupta 	error = esdhc_send_cmd(mmc, CMD_SELECT_CARD, mmc->card.rca << 16);
883066ee1adSPankaj Gupta 	if (error != 0) {
884066ee1adSPankaj Gupta 		return error;
885066ee1adSPankaj Gupta 	}
886066ee1adSPankaj Gupta 	error = esdhc_wait_response(mmc, response);
887066ee1adSPankaj Gupta 	if (error != 0) {
888066ee1adSPankaj Gupta 		return error;
889066ee1adSPankaj Gupta 	}
890066ee1adSPankaj Gupta 
891066ee1adSPankaj Gupta 	start_time = get_timer_val(0);
892066ee1adSPankaj Gupta 	while (get_timer_val(start_time) < SD_TIMEOUT_HIGH) {
893066ee1adSPankaj Gupta 		/* send CMD13 to check card status */
894066ee1adSPankaj Gupta 		error = esdhc_send_cmd(mmc,
895066ee1adSPankaj Gupta 					CMD_SEND_STATUS, mmc->card.rca << 16);
896066ee1adSPankaj Gupta 		if (error != 0) {
897066ee1adSPankaj Gupta 			return error;
898066ee1adSPankaj Gupta 		}
899066ee1adSPankaj Gupta 		error = esdhc_wait_response(mmc, response);
900066ee1adSPankaj Gupta 		if ((error != 0) || ((response[0] & R1_ERROR) != 0)) {
901066ee1adSPankaj Gupta 			return error;
902066ee1adSPankaj Gupta 		}
903066ee1adSPankaj Gupta 
904066ee1adSPankaj Gupta 		/* Check for the present state of card */
905066ee1adSPankaj Gupta 		if (((response[0] >> 9U) & U(0xF)) == STATE_TRAN) {
906066ee1adSPankaj Gupta 			break;
907066ee1adSPankaj Gupta 		}
908066ee1adSPankaj Gupta 	}
909066ee1adSPankaj Gupta 	if (((response[0] >> 9U) & U(0xF)) == STATE_TRAN) {
910066ee1adSPankaj Gupta 		return 0;
911066ee1adSPankaj Gupta 	} else {
912066ee1adSPankaj Gupta 		return ERROR_ESDHC_COMMUNICATION_ERROR;
913066ee1adSPankaj Gupta 	}
914066ee1adSPankaj Gupta }
915066ee1adSPankaj Gupta 
916066ee1adSPankaj Gupta /***************************************************************************
917066ee1adSPankaj Gupta  * Function    :    get_cid_rca_csd
918066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
919066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
920066ee1adSPankaj Gupta  * Description :    1. Send CMD2 (CMD_ALL_SEND_CID)
921066ee1adSPankaj Gupta  *                  2. get RCA for SD cards, set rca for mmc cards
922066ee1adSPankaj Gupta  *                     Send CMD3 (CMD_SEND_RELATIVE_ADDR)
923066ee1adSPankaj Gupta  *                  3. Send CMD9 (CMD_SEND_CSD)
924066ee1adSPankaj Gupta  *                  4. Get MMC Version from CSD
925066ee1adSPankaj Gupta  ***************************************************************************/
get_cid_rca_csd(struct mmc * mmc)926066ee1adSPankaj Gupta static int get_cid_rca_csd(struct mmc *mmc)
927066ee1adSPankaj Gupta {
928066ee1adSPankaj Gupta 	int err;
929066ee1adSPankaj Gupta 	uint32_t version;
930066ee1adSPankaj Gupta 	uint32_t response[4];
931066ee1adSPankaj Gupta 	uint32_t mmc_version[] = {MMC_CARD_VERSION_1_2, MMC_CARD_VERSION_1_4,
932066ee1adSPankaj Gupta 		MMC_CARD_VERSION_2_X, MMC_CARD_VERSION_3_X,
933066ee1adSPankaj Gupta 		MMC_CARD_VERSION_4_X};
934066ee1adSPankaj Gupta 
935066ee1adSPankaj Gupta 	err = esdhc_send_cmd(mmc, CMD_ALL_SEND_CID, 0);
936066ee1adSPankaj Gupta 	if (err != 0) {
937066ee1adSPankaj Gupta 		return err;
938066ee1adSPankaj Gupta 	}
939066ee1adSPankaj Gupta 	err = esdhc_wait_response(mmc, response);
940066ee1adSPankaj Gupta 	if (err != 0) {
941066ee1adSPankaj Gupta 		return err;
942066ee1adSPankaj Gupta 	}
943066ee1adSPankaj Gupta 
944066ee1adSPankaj Gupta 	/* get RCA for SD cards, set rca for mmc cards */
945066ee1adSPankaj Gupta 	mmc->card.rca = SD_MMC_CARD_RCA;
946066ee1adSPankaj Gupta 
947066ee1adSPankaj Gupta 	/* send RCA cmd */
948066ee1adSPankaj Gupta 	err = esdhc_send_cmd(mmc, CMD_SEND_RELATIVE_ADDR, mmc->card.rca << 16);
949066ee1adSPankaj Gupta 	if (err != 0) {
950066ee1adSPankaj Gupta 		return err;
951066ee1adSPankaj Gupta 	}
952066ee1adSPankaj Gupta 	err = esdhc_wait_response(mmc, response);
953066ee1adSPankaj Gupta 	if (err != 0) {
954066ee1adSPankaj Gupta 		return err;
955066ee1adSPankaj Gupta 	}
956066ee1adSPankaj Gupta 
957066ee1adSPankaj Gupta 	/* for SD, get the the RCA */
958066ee1adSPankaj Gupta 	if (mmc->card.type == SD_CARD) {
959066ee1adSPankaj Gupta 		mmc->card.rca = (response[0] >> 16) & 0xFFFF;
960066ee1adSPankaj Gupta 	}
961066ee1adSPankaj Gupta 
962066ee1adSPankaj Gupta 	/* Get the CSD (card specific data) from card. */
963066ee1adSPankaj Gupta 	err = esdhc_send_cmd(mmc, CMD_SEND_CSD, mmc->card.rca << 16);
964066ee1adSPankaj Gupta 	if (err != 0) {
965066ee1adSPankaj Gupta 		return err;
966066ee1adSPankaj Gupta 	}
967066ee1adSPankaj Gupta 	err = esdhc_wait_response(mmc, response);
968066ee1adSPankaj Gupta 	if (err != 0) {
969066ee1adSPankaj Gupta 		return err;
970066ee1adSPankaj Gupta 	}
971066ee1adSPankaj Gupta 
972066ee1adSPankaj Gupta 	version = (response[3] >> 18U) & U(0xF);
973066ee1adSPankaj Gupta 	if (mmc->card.type == MMC_CARD) {
974066ee1adSPankaj Gupta 		if (version <= MMC_CARD_VERSION_4_X) {
975066ee1adSPankaj Gupta 			mmc->card.version = mmc_version[version];
976066ee1adSPankaj Gupta 		} else {
977066ee1adSPankaj Gupta 			mmc->card.version = MMC_CARD_VERSION_4_X;
978066ee1adSPankaj Gupta 		}
979066ee1adSPankaj Gupta 	}
980066ee1adSPankaj Gupta 
981066ee1adSPankaj Gupta 	mmc->card.block_len = 1 << ((response[2] >> 8) & 0xF);
982066ee1adSPankaj Gupta 
983066ee1adSPankaj Gupta 	if (mmc->card.block_len > BLOCK_LEN_512) {
984066ee1adSPankaj Gupta 		mmc->card.block_len = BLOCK_LEN_512;
985066ee1adSPankaj Gupta 	}
986066ee1adSPankaj Gupta 
987066ee1adSPankaj Gupta 	return 0;
988066ee1adSPankaj Gupta }
989066ee1adSPankaj Gupta 
990066ee1adSPankaj Gupta /***************************************************************************
991066ee1adSPankaj Gupta  * Function    :    identify_mmc_card
992066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
993066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
994066ee1adSPankaj Gupta  * Description :    1. Send Reset Command
995066ee1adSPankaj Gupta  *                  2. Send CMD1 with args to set voltage range and Sector
996066ee1adSPankaj Gupta  *                     Mode. (Voltage Args = 0xFF8)
997066ee1adSPankaj Gupta  *                  3. Check the OCR Response
998066ee1adSPankaj Gupta  ***************************************************************************/
identify_mmc_card(struct mmc * mmc)999066ee1adSPankaj Gupta static int identify_mmc_card(struct mmc *mmc)
1000066ee1adSPankaj Gupta {
1001066ee1adSPankaj Gupta 	uint64_t start_time;
1002066ee1adSPankaj Gupta 	uint32_t resp[4];
1003066ee1adSPankaj Gupta 	int ret;
1004066ee1adSPankaj Gupta 	uint32_t args;
1005066ee1adSPankaj Gupta 
1006066ee1adSPankaj Gupta 	/* card reset */
1007066ee1adSPankaj Gupta 	ret = esdhc_send_cmd(mmc, CMD_GO_IDLE_STATE, 0U);
1008066ee1adSPankaj Gupta 	if (ret != 0) {
1009066ee1adSPankaj Gupta 		return ret;
1010066ee1adSPankaj Gupta 	}
1011066ee1adSPankaj Gupta 	ret = esdhc_wait_response(mmc, resp);
1012066ee1adSPankaj Gupta 	if (ret != 0) {
1013066ee1adSPankaj Gupta 		return ret;
1014066ee1adSPankaj Gupta 	}
1015066ee1adSPankaj Gupta 
1016066ee1adSPankaj Gupta 	/* Send CMD1 to get the ocr value repeatedly till the card */
1017066ee1adSPankaj Gupta 	/* busy is clear. timeout = 20sec */
1018066ee1adSPankaj Gupta 
1019066ee1adSPankaj Gupta 	start_time = get_timer_val(0);
1020066ee1adSPankaj Gupta 	do {
1021066ee1adSPankaj Gupta 		/* set the bits for the voltage ranges supported by host */
1022066ee1adSPankaj Gupta 		args = mmc->voltages_caps | MMC_OCR_SECTOR_MODE;
1023066ee1adSPankaj Gupta 		ret = esdhc_send_cmd(mmc, CMD_MMC_SEND_OP_COND, args);
1024066ee1adSPankaj Gupta 		if (ret != 0) {
1025066ee1adSPankaj Gupta 			return ret;
1026066ee1adSPankaj Gupta 		}
1027066ee1adSPankaj Gupta 		ret = esdhc_wait_response(mmc, resp);
1028066ee1adSPankaj Gupta 		if (ret != 0) {
1029066ee1adSPankaj Gupta 			return ERROR_ESDHC_UNUSABLE_CARD;
1030066ee1adSPankaj Gupta 		}
1031066ee1adSPankaj Gupta 	} while (((resp[0] & MMC_OCR_BUSY) == 0U) &&
1032066ee1adSPankaj Gupta 			(get_timer_val(start_time) < SD_TIMEOUT_HIGH));
1033066ee1adSPankaj Gupta 
1034066ee1adSPankaj Gupta 	if (get_timer_val(start_time) > SD_TIMEOUT_HIGH) {
1035066ee1adSPankaj Gupta 		return ERROR_ESDHC_UNUSABLE_CARD;
1036066ee1adSPankaj Gupta 	}
1037066ee1adSPankaj Gupta 
1038066ee1adSPankaj Gupta 	if ((resp[0] & MMC_OCR_CCS) == MMC_OCR_CCS) {
1039066ee1adSPankaj Gupta 		mmc->card.is_high_capacity = 1;
1040066ee1adSPankaj Gupta 	}
1041066ee1adSPankaj Gupta 
1042066ee1adSPankaj Gupta 	return MMC_CARD;
1043066ee1adSPankaj Gupta }
1044066ee1adSPankaj Gupta 
1045066ee1adSPankaj Gupta /***************************************************************************
1046066ee1adSPankaj Gupta  * Function    :    check_for_sd_card
1047066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
1048066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
1049066ee1adSPankaj Gupta  * Description :    1. Send Reset Command
1050066ee1adSPankaj Gupta  *                  2. Send CMD8 with pattern 0xAA (to check for SD 2.0)
1051066ee1adSPankaj Gupta  *                  3. Send ACMD41 with args to set voltage range and HCS
1052066ee1adSPankaj Gupta  *                     HCS is set only for SD Card > 2.0
1053066ee1adSPankaj Gupta  *                     Voltage Caps = 0xFF8
1054066ee1adSPankaj Gupta  *                  4. Check the OCR Response
1055066ee1adSPankaj Gupta  ***************************************************************************/
check_for_sd_card(struct mmc * mmc)1056066ee1adSPankaj Gupta static int check_for_sd_card(struct mmc *mmc)
1057066ee1adSPankaj Gupta {
1058066ee1adSPankaj Gupta 	uint64_t start_time;
1059066ee1adSPankaj Gupta 	uint32_t args;
1060066ee1adSPankaj Gupta 	int  ret;
1061066ee1adSPankaj Gupta 	uint32_t resp[4];
1062066ee1adSPankaj Gupta 
1063066ee1adSPankaj Gupta 	/* Send reset command */
1064066ee1adSPankaj Gupta 	ret = esdhc_send_cmd(mmc, CMD_GO_IDLE_STATE, 0U);
1065066ee1adSPankaj Gupta 	if (ret != 0) {
1066066ee1adSPankaj Gupta 		return ret;
1067066ee1adSPankaj Gupta 	}
1068066ee1adSPankaj Gupta 	ret = esdhc_wait_response(mmc, resp);
1069066ee1adSPankaj Gupta 	if (ret != 0) {
1070066ee1adSPankaj Gupta 		return ret;
1071066ee1adSPankaj Gupta 	}
1072066ee1adSPankaj Gupta 
1073066ee1adSPankaj Gupta 	/* send CMD8 with  pattern 0xAA */
1074066ee1adSPankaj Gupta 	args = MMC_VDD_HIGH_VOLTAGE | 0xAA;
1075066ee1adSPankaj Gupta 	ret = esdhc_send_cmd(mmc, CMD_SEND_IF_COND, args);
1076066ee1adSPankaj Gupta 	if (ret != 0) {
1077066ee1adSPankaj Gupta 		return ret;
1078066ee1adSPankaj Gupta 	}
1079066ee1adSPankaj Gupta 	ret = esdhc_wait_response(mmc, resp);
1080066ee1adSPankaj Gupta 	if (ret == RESP_TIMEOUT) { /* sd ver 1.x or not sd */
1081066ee1adSPankaj Gupta 		mmc->card.is_high_capacity = 0;
1082066ee1adSPankaj Gupta 	} else if ((resp[0] & U(0xFF)) == U(0xAA)) { /* ver 2.0 or later */
1083066ee1adSPankaj Gupta 		mmc->card.version = SD_CARD_VERSION_2_0;
1084066ee1adSPankaj Gupta 	} else {
1085066ee1adSPankaj Gupta 		return  NOT_SD_CARD;
1086066ee1adSPankaj Gupta 	}
1087066ee1adSPankaj Gupta 	/* Send Application command-55 to get the ocr value repeatedly till
1088066ee1adSPankaj Gupta 	 * the card busy is clear. timeout = 20sec
1089066ee1adSPankaj Gupta 	 */
1090066ee1adSPankaj Gupta 
1091066ee1adSPankaj Gupta 	start_time = get_timer_val(0);
1092066ee1adSPankaj Gupta 	do {
1093066ee1adSPankaj Gupta 		ret = esdhc_send_cmd(mmc, CMD_APP_CMD, 0U);
1094066ee1adSPankaj Gupta 		if (ret != 0) {
1095066ee1adSPankaj Gupta 			return ret;
1096066ee1adSPankaj Gupta 		}
1097066ee1adSPankaj Gupta 		ret = esdhc_wait_response(mmc, resp);
1098066ee1adSPankaj Gupta 		if (ret == COMMAND_ERROR) {
1099066ee1adSPankaj Gupta 			return ERROR_ESDHC_UNUSABLE_CARD;
1100066ee1adSPankaj Gupta 		}
1101066ee1adSPankaj Gupta 
1102066ee1adSPankaj Gupta 		/* set the bits for the voltage ranges supported by host */
1103066ee1adSPankaj Gupta 		args = mmc->voltages_caps;
1104066ee1adSPankaj Gupta 		if (mmc->card.version == SD_CARD_VERSION_2_0) {
1105066ee1adSPankaj Gupta 			args |= SD_OCR_HCS;
1106066ee1adSPankaj Gupta 		}
1107066ee1adSPankaj Gupta 
1108066ee1adSPankaj Gupta 		/* Send ACMD41 to set voltage range */
1109066ee1adSPankaj Gupta 		ret = esdhc_send_cmd(mmc, CMD_SD_SEND_OP_COND, args);
1110066ee1adSPankaj Gupta 		if (ret != 0) {
1111066ee1adSPankaj Gupta 			return ret;
1112066ee1adSPankaj Gupta 		}
1113066ee1adSPankaj Gupta 		ret = esdhc_wait_response(mmc, resp);
1114066ee1adSPankaj Gupta 		if (ret == COMMAND_ERROR) {
1115066ee1adSPankaj Gupta 			return ERROR_ESDHC_UNUSABLE_CARD;
1116066ee1adSPankaj Gupta 		} else if (ret == RESP_TIMEOUT) {
1117066ee1adSPankaj Gupta 			return NOT_SD_CARD;
1118066ee1adSPankaj Gupta 		}
1119066ee1adSPankaj Gupta 	} while (((resp[0] & MMC_OCR_BUSY) == 0U) &&
1120066ee1adSPankaj Gupta 			(get_timer_val(start_time) < SD_TIMEOUT_HIGH));
1121066ee1adSPankaj Gupta 
1122066ee1adSPankaj Gupta 	if (get_timer_val(start_time) > SD_TIMEOUT_HIGH) {
1123066ee1adSPankaj Gupta 		INFO("SD_TIMEOUT_HIGH\n");
1124066ee1adSPankaj Gupta 		return ERROR_ESDHC_UNUSABLE_CARD;
1125066ee1adSPankaj Gupta 	}
1126066ee1adSPankaj Gupta 
1127066ee1adSPankaj Gupta 	/* bit set in card capacity status */
1128066ee1adSPankaj Gupta 	if ((resp[0] & MMC_OCR_CCS) == MMC_OCR_CCS) {
1129066ee1adSPankaj Gupta 		mmc->card.is_high_capacity = 1;
1130066ee1adSPankaj Gupta 	}
1131066ee1adSPankaj Gupta 
1132066ee1adSPankaj Gupta 	return SD_CARD;
1133066ee1adSPankaj Gupta }
1134066ee1adSPankaj Gupta 
1135066ee1adSPankaj Gupta /***************************************************************************
1136066ee1adSPankaj Gupta  * Function    :    esdhc_emmc_init
1137066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
1138066ee1adSPankaj Gupta  *                  src_emmc - Flag to Indicate SRC as emmc
1139066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code (< 0)
1140066ee1adSPankaj Gupta  * Description :    Base Function called from sd_mmc_init or emmc_init
1141066ee1adSPankaj Gupta  ***************************************************************************/
esdhc_emmc_init(struct mmc * mmc,bool card_detect)1142066ee1adSPankaj Gupta int esdhc_emmc_init(struct mmc *mmc, bool card_detect)
1143066ee1adSPankaj Gupta {
1144066ee1adSPankaj Gupta 	int error = 0;
1145066ee1adSPankaj Gupta 	int ret = 0;
1146066ee1adSPankaj Gupta 
1147066ee1adSPankaj Gupta 	error = esdhc_init(mmc, card_detect);
1148066ee1adSPankaj Gupta 	if (error != 0) {
1149066ee1adSPankaj Gupta 		return error;
1150066ee1adSPankaj Gupta 	}
1151066ee1adSPankaj Gupta 
1152066ee1adSPankaj Gupta 	mmc->card.bus_freq = CARD_IDENTIFICATION_FREQ;
1153066ee1adSPankaj Gupta 	mmc->card.rca = 0;
1154066ee1adSPankaj Gupta 	mmc->card.is_high_capacity = 0;
1155066ee1adSPankaj Gupta 	mmc->card.type = ERROR_ESDHC_UNUSABLE_CARD;
1156066ee1adSPankaj Gupta 
1157066ee1adSPankaj Gupta 	/* Set Voltage caps as FF8 i.e all supported */
1158066ee1adSPankaj Gupta 	/* high voltage bits 2.7 - 3.6 */
1159066ee1adSPankaj Gupta 	mmc->voltages_caps = MMC_OCR_VDD_FF8;
1160066ee1adSPankaj Gupta 
1161066ee1adSPankaj Gupta #ifdef NXP_SD_DMA_CAPABILITY
1162066ee1adSPankaj Gupta 	/* Getting host DMA capabilities. */
1163066ee1adSPankaj Gupta 	mmc->dma_support = esdhc_in32(&mmc->esdhc_regs->hostcapblt) &
1164066ee1adSPankaj Gupta 					ESDHC_HOSTCAPBLT_DMAS;
1165066ee1adSPankaj Gupta #else
1166066ee1adSPankaj Gupta 	mmc->dma_support = 0;
1167066ee1adSPankaj Gupta #endif
1168066ee1adSPankaj Gupta 
1169066ee1adSPankaj Gupta 	ret = NOT_SD_CARD;
1170066ee1adSPankaj Gupta 	/* If SRC is not EMMC, check for SD or MMC */
1171066ee1adSPankaj Gupta 	ret = check_for_sd_card(mmc);
1172066ee1adSPankaj Gupta 	switch (ret) {
1173066ee1adSPankaj Gupta 	case SD_CARD:
1174066ee1adSPankaj Gupta 		mmc->card.type = SD_CARD;
1175066ee1adSPankaj Gupta 		break;
1176066ee1adSPankaj Gupta 
1177066ee1adSPankaj Gupta 	case NOT_SD_CARD:
1178066ee1adSPankaj Gupta 		/* try for MMC card */
1179066ee1adSPankaj Gupta 		if (identify_mmc_card(mmc) == MMC_CARD) {
1180066ee1adSPankaj Gupta 			mmc->card.type = MMC_CARD;
1181066ee1adSPankaj Gupta 		} else {
1182066ee1adSPankaj Gupta 			return ERROR_ESDHC_UNUSABLE_CARD;
1183066ee1adSPankaj Gupta 		}
1184066ee1adSPankaj Gupta 		break;
1185066ee1adSPankaj Gupta 
1186066ee1adSPankaj Gupta 	default:
1187066ee1adSPankaj Gupta 		return ERROR_ESDHC_UNUSABLE_CARD;
1188066ee1adSPankaj Gupta 	}
1189066ee1adSPankaj Gupta 
1190066ee1adSPankaj Gupta 	/* get CID, RCA and CSD. For MMC, set the rca */
1191066ee1adSPankaj Gupta 	error = get_cid_rca_csd(mmc);
1192066ee1adSPankaj Gupta 	if (error != 0) {
1193066ee1adSPankaj Gupta 		return ERROR_ESDHC_COMMUNICATION_ERROR;
1194066ee1adSPankaj Gupta 	}
1195066ee1adSPankaj Gupta 
1196066ee1adSPankaj Gupta 	/* change state to Transfer mode */
1197066ee1adSPankaj Gupta 	error = change_state_to_transfer_state(mmc);
1198066ee1adSPankaj Gupta 	if (error != 0) {
1199066ee1adSPankaj Gupta 		return ERROR_ESDHC_COMMUNICATION_ERROR;
1200066ee1adSPankaj Gupta 	}
1201066ee1adSPankaj Gupta 
1202066ee1adSPankaj Gupta 	/* change to high frequency if supported */
1203066ee1adSPankaj Gupta 	if (mmc->card.type == SD_CARD) {
1204066ee1adSPankaj Gupta 		error = sd_switch_to_high_freq(mmc);
1205066ee1adSPankaj Gupta 	} else {
1206066ee1adSPankaj Gupta 		error = mmc_switch_to_high_frquency(mmc);
1207066ee1adSPankaj Gupta 	}
1208066ee1adSPankaj Gupta 	if (error != 0) {
1209066ee1adSPankaj Gupta 		return ERROR_ESDHC_COMMUNICATION_ERROR;
1210066ee1adSPankaj Gupta 	}
1211066ee1adSPankaj Gupta 
1212066ee1adSPankaj Gupta 	/* mmc: 20000000, 26000000, 52000000 */
1213066ee1adSPankaj Gupta 	/* sd: 25000000, 50000000 */
1214066ee1adSPankaj Gupta 	set_speed(mmc, mmc->card.bus_freq);
1215066ee1adSPankaj Gupta 
1216066ee1adSPankaj Gupta 	INFO("init done:\n");
1217066ee1adSPankaj Gupta 	return 0;
1218066ee1adSPankaj Gupta }
1219066ee1adSPankaj Gupta 
1220066ee1adSPankaj Gupta /***************************************************************************
1221066ee1adSPankaj Gupta  * Function    :    sd_mmc_init
1222066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
1223066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
1224066ee1adSPankaj Gupta  * Description :    Base Function called via hal_init for SD/MMC
1225066ee1adSPankaj Gupta  *                  initialization
1226066ee1adSPankaj Gupta  ***************************************************************************/
sd_mmc_init(uintptr_t nxp_esdhc_addr,bool card_detect)1227066ee1adSPankaj Gupta int sd_mmc_init(uintptr_t nxp_esdhc_addr, bool card_detect)
1228066ee1adSPankaj Gupta {
1229066ee1adSPankaj Gupta 	struct mmc *mmc = NULL;
1230066ee1adSPankaj Gupta 	int ret;
1231066ee1adSPankaj Gupta 
1232066ee1adSPankaj Gupta 	mmc = &mmc_drv_data;
1233066ee1adSPankaj Gupta 	memset(mmc, 0, sizeof(struct mmc));
1234066ee1adSPankaj Gupta 	mmc->esdhc_regs = (struct esdhc_regs *)nxp_esdhc_addr;
1235066ee1adSPankaj Gupta 
1236066ee1adSPankaj Gupta 	INFO("esdhc_emmc_init\n");
1237066ee1adSPankaj Gupta 	ret = esdhc_emmc_init(mmc, card_detect);
1238066ee1adSPankaj Gupta 	return ret;
1239066ee1adSPankaj Gupta }
1240066ee1adSPankaj Gupta 
1241066ee1adSPankaj Gupta /***************************************************************************
1242066ee1adSPankaj Gupta  * Function    :    esdhc_read_block
1243066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
1244066ee1adSPankaj Gupta  *                  dst - Destination Pointer
1245066ee1adSPankaj Gupta  *                  block - Block Number
1246066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
1247066ee1adSPankaj Gupta  * Description :    Read a Single block to Destination Pointer
1248066ee1adSPankaj Gupta  *                  1. Send CMD16 (CMD_SET_BLOCKLEN) with args as blocklen
1249066ee1adSPankaj Gupta  *                  2. Send CMD17 (CMD_READ_SINGLE_BLOCK) with args offset
1250066ee1adSPankaj Gupta  ***************************************************************************/
esdhc_read_block(struct mmc * mmc,void * dst,uint32_t block)1251066ee1adSPankaj Gupta static int esdhc_read_block(struct mmc *mmc, void *dst, uint32_t block)
1252066ee1adSPankaj Gupta {
1253066ee1adSPankaj Gupta 	uint32_t offset;
1254066ee1adSPankaj Gupta 	int err;
1255066ee1adSPankaj Gupta 
1256066ee1adSPankaj Gupta 	/* send cmd16 to set the block size. */
1257066ee1adSPankaj Gupta 	err = esdhc_send_cmd(mmc, CMD_SET_BLOCKLEN, mmc->card.block_len);
1258066ee1adSPankaj Gupta 	if (err != 0) {
1259066ee1adSPankaj Gupta 		return err;
1260066ee1adSPankaj Gupta 	}
1261066ee1adSPankaj Gupta 	err = esdhc_wait_response(mmc, NULL);
1262066ee1adSPankaj Gupta 	if (err != 0) {
1263066ee1adSPankaj Gupta 		return ERROR_ESDHC_COMMUNICATION_ERROR;
1264066ee1adSPankaj Gupta 	}
1265066ee1adSPankaj Gupta 
1266066ee1adSPankaj Gupta 	if (mmc->card.is_high_capacity != 0) {
1267066ee1adSPankaj Gupta 		offset = block;
1268066ee1adSPankaj Gupta 	} else {
1269066ee1adSPankaj Gupta 		offset = block * mmc->card.block_len;
1270066ee1adSPankaj Gupta 	}
1271066ee1adSPankaj Gupta 
1272066ee1adSPankaj Gupta 	esdhc_set_data_attributes(mmc, dst, 1, mmc->card.block_len);
1273066ee1adSPankaj Gupta 	err = esdhc_send_cmd(mmc, CMD_READ_SINGLE_BLOCK, offset);
1274066ee1adSPankaj Gupta 	if (err != 0) {
1275066ee1adSPankaj Gupta 		return err;
1276066ee1adSPankaj Gupta 	}
1277066ee1adSPankaj Gupta 	err = esdhc_wait_response(mmc, NULL);
1278066ee1adSPankaj Gupta 	if (err != 0) {
1279066ee1adSPankaj Gupta 		return err;
1280066ee1adSPankaj Gupta 	}
1281066ee1adSPankaj Gupta 
1282066ee1adSPankaj Gupta 	err = esdhc_read_data(mmc, dst, mmc->card.block_len);
1283066ee1adSPankaj Gupta 
1284066ee1adSPankaj Gupta 	return err;
1285066ee1adSPankaj Gupta }
1286066ee1adSPankaj Gupta 
1287066ee1adSPankaj Gupta /***************************************************************************
1288066ee1adSPankaj Gupta  * Function    :    esdhc_write_block
1289066ee1adSPankaj Gupta  * Arguments   :    mmc - Pointer to mmc struct
1290066ee1adSPankaj Gupta  *                  src - Source Pointer
1291066ee1adSPankaj Gupta  *                  block - Block Number
1292066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
1293066ee1adSPankaj Gupta  * Description :    Write a Single block from Source Pointer
1294066ee1adSPankaj Gupta  *                  1. Send CMD16 (CMD_SET_BLOCKLEN) with args as blocklen
1295066ee1adSPankaj Gupta  *                  2. Send CMD24 (CMD_WRITE_SINGLE_BLOCK) with args offset
1296066ee1adSPankaj Gupta  ***************************************************************************/
esdhc_write_block(struct mmc * mmc,void * src,uint32_t block)1297066ee1adSPankaj Gupta static int esdhc_write_block(struct mmc *mmc, void *src, uint32_t block)
1298066ee1adSPankaj Gupta {
1299066ee1adSPankaj Gupta 	uint32_t offset;
1300066ee1adSPankaj Gupta 	int err;
1301066ee1adSPankaj Gupta 
1302066ee1adSPankaj Gupta 	/* send cmd16 to set the block size. */
1303066ee1adSPankaj Gupta 	err = esdhc_send_cmd(mmc, CMD_SET_BLOCKLEN, mmc->card.block_len);
1304066ee1adSPankaj Gupta 	if (err != 0) {
1305066ee1adSPankaj Gupta 		return err;
1306066ee1adSPankaj Gupta 	}
1307066ee1adSPankaj Gupta 	err = esdhc_wait_response(mmc, NULL);
1308066ee1adSPankaj Gupta 	if (err != 0) {
1309066ee1adSPankaj Gupta 		return ERROR_ESDHC_COMMUNICATION_ERROR;
1310066ee1adSPankaj Gupta 	}
1311066ee1adSPankaj Gupta 
1312066ee1adSPankaj Gupta 	if (mmc->card.is_high_capacity != 0) {
1313066ee1adSPankaj Gupta 		offset = block;
1314066ee1adSPankaj Gupta 	} else {
1315066ee1adSPankaj Gupta 		offset = block * mmc->card.block_len;
1316066ee1adSPankaj Gupta 	}
1317066ee1adSPankaj Gupta 
1318066ee1adSPankaj Gupta 	esdhc_set_data_attributes(mmc, src, 1, mmc->card.block_len);
1319066ee1adSPankaj Gupta 	err = esdhc_send_cmd(mmc, CMD_WRITE_SINGLE_BLOCK, offset);
1320066ee1adSPankaj Gupta 	if (err != 0) {
1321066ee1adSPankaj Gupta 		return err;
1322066ee1adSPankaj Gupta 	}
1323066ee1adSPankaj Gupta 	err = esdhc_wait_response(mmc, NULL);
1324066ee1adSPankaj Gupta 	if (err != 0) {
1325066ee1adSPankaj Gupta 		return err;
1326066ee1adSPankaj Gupta 	}
1327066ee1adSPankaj Gupta 
1328066ee1adSPankaj Gupta 	err = esdhc_write_data(mmc, src, mmc->card.block_len);
1329066ee1adSPankaj Gupta 
1330066ee1adSPankaj Gupta 	return err;
1331066ee1adSPankaj Gupta }
1332066ee1adSPankaj Gupta 
1333066ee1adSPankaj Gupta /***************************************************************************
1334066ee1adSPankaj Gupta  * Function    :    esdhc_read
1335066ee1adSPankaj Gupta  * Arguments   :    src_offset - offset on sd/mmc to read from. Should be block
1336066ee1adSPankaj Gupta  *		    size aligned
1337066ee1adSPankaj Gupta  *                  dst - Destination Pointer
1338066ee1adSPankaj Gupta  *                  size - Length of Data ( Multiple of block size)
1339066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
1340066ee1adSPankaj Gupta  * Description :    Calls esdhc_read_block repeatedly for reading the
1341066ee1adSPankaj Gupta  *                  data.
1342066ee1adSPankaj Gupta  ***************************************************************************/
esdhc_read(struct mmc * mmc,uint32_t src_offset,uintptr_t dst,size_t size)1343066ee1adSPankaj Gupta int esdhc_read(struct mmc *mmc, uint32_t src_offset, uintptr_t dst, size_t size)
1344066ee1adSPankaj Gupta {
1345066ee1adSPankaj Gupta 	int error = 0;
1346066ee1adSPankaj Gupta 	uint32_t blk, num_blocks;
1347066ee1adSPankaj Gupta 	uint8_t *buff = (uint8_t *)dst;
1348066ee1adSPankaj Gupta 
1349066ee1adSPankaj Gupta #ifdef NXP_SD_DEBUG
1350066ee1adSPankaj Gupta 	INFO("sd mmc read\n");
1351066ee1adSPankaj Gupta 	INFO("src = %x, dst = %lxsize = %lu\n", src_offset, dst, size);
1352066ee1adSPankaj Gupta #endif
1353066ee1adSPankaj Gupta 
1354066ee1adSPankaj Gupta 	/* check for size */
1355066ee1adSPankaj Gupta 	if (size == 0) {
1356066ee1adSPankaj Gupta 		return 0;
1357066ee1adSPankaj Gupta 	}
1358066ee1adSPankaj Gupta 
1359066ee1adSPankaj Gupta 	if ((size % mmc->card.block_len) != 0) {
1360066ee1adSPankaj Gupta 		ERROR("Size is not block aligned\n");
1361066ee1adSPankaj Gupta 		return -1;
1362066ee1adSPankaj Gupta 	}
1363066ee1adSPankaj Gupta 
1364066ee1adSPankaj Gupta 	if ((src_offset % mmc->card.block_len) != 0) {
1365066ee1adSPankaj Gupta 		ERROR("Size is not block aligned\n");
1366066ee1adSPankaj Gupta 		return -1;
1367066ee1adSPankaj Gupta 	}
1368066ee1adSPankaj Gupta 
1369066ee1adSPankaj Gupta 	/* start block */
1370066ee1adSPankaj Gupta 	blk = src_offset / mmc->card.block_len;
1371066ee1adSPankaj Gupta #ifdef NXP_SD_DEBUG
1372066ee1adSPankaj Gupta 	INFO("blk = %x\n", blk);
1373066ee1adSPankaj Gupta #endif
1374066ee1adSPankaj Gupta 
1375066ee1adSPankaj Gupta 	/* Number of blocks to be read */
1376066ee1adSPankaj Gupta 	num_blocks = size / mmc->card.block_len;
1377066ee1adSPankaj Gupta 
1378066ee1adSPankaj Gupta 	while (num_blocks) {
1379066ee1adSPankaj Gupta 		error = esdhc_read_block(mmc, buff, blk);
1380066ee1adSPankaj Gupta 		if (error != 0) {
1381066ee1adSPankaj Gupta 			ERROR("Read error = %x\n", error);
1382066ee1adSPankaj Gupta 			return error;
1383066ee1adSPankaj Gupta 		}
1384066ee1adSPankaj Gupta 
1385066ee1adSPankaj Gupta 		buff = buff + mmc->card.block_len;
1386066ee1adSPankaj Gupta 		blk++;
1387066ee1adSPankaj Gupta 		num_blocks--;
1388066ee1adSPankaj Gupta 	}
1389066ee1adSPankaj Gupta 
1390066ee1adSPankaj Gupta 	INFO("sd-mmc read done.\n");
1391066ee1adSPankaj Gupta 	return error;
1392066ee1adSPankaj Gupta }
1393066ee1adSPankaj Gupta 
1394066ee1adSPankaj Gupta /***************************************************************************
1395066ee1adSPankaj Gupta  * Function    :    esdhc_write
1396066ee1adSPankaj Gupta  * Arguments   :    src - Source Pointer
1397066ee1adSPankaj Gupta  *                  dst_offset - offset on sd/mmc to write to. Should be block
1398066ee1adSPankaj Gupta  *		    size aligned
1399066ee1adSPankaj Gupta  *                  size - Length of Data (Multiple of block size)
1400066ee1adSPankaj Gupta  * Return      :    SUCCESS or Error Code
1401066ee1adSPankaj Gupta  * Description :    Calls esdhc_write_block repeatedly for writing the
1402066ee1adSPankaj Gupta  *                  data.
1403066ee1adSPankaj Gupta  ***************************************************************************/
esdhc_write(struct mmc * mmc,uintptr_t src,uint32_t dst_offset,size_t size)1404066ee1adSPankaj Gupta int esdhc_write(struct mmc *mmc, uintptr_t src, uint32_t dst_offset,
1405066ee1adSPankaj Gupta 		size_t size)
1406066ee1adSPankaj Gupta {
1407066ee1adSPankaj Gupta 	int error = 0;
1408066ee1adSPankaj Gupta 	uint32_t blk, num_blocks;
1409066ee1adSPankaj Gupta 	uint8_t *buff = (uint8_t *)src;
1410066ee1adSPankaj Gupta 
1411066ee1adSPankaj Gupta #ifdef NXP_SD_DEBUG
1412066ee1adSPankaj Gupta 	INFO("sd mmc write\n");
1413066ee1adSPankaj Gupta 	INFO("src = %x, dst = %lxsize = %lu\n", src, dst_offset, size);
1414066ee1adSPankaj Gupta #endif
1415066ee1adSPankaj Gupta 
1416066ee1adSPankaj Gupta 	/* check for size */
1417066ee1adSPankaj Gupta 	if (size == 0) {
1418066ee1adSPankaj Gupta 		return 0;
1419066ee1adSPankaj Gupta 	}
1420066ee1adSPankaj Gupta 
1421066ee1adSPankaj Gupta 	if ((size % mmc->card.block_len) != 0) {
1422066ee1adSPankaj Gupta 		ERROR("Size is not block aligned\n");
1423066ee1adSPankaj Gupta 		return -1;
1424066ee1adSPankaj Gupta 	}
1425066ee1adSPankaj Gupta 
1426066ee1adSPankaj Gupta 	if ((dst_offset % mmc->card.block_len) != 0) {
1427066ee1adSPankaj Gupta 		ERROR("Size is not block aligned\n");
1428066ee1adSPankaj Gupta 		return -1;
1429066ee1adSPankaj Gupta 	}
1430066ee1adSPankaj Gupta 
1431066ee1adSPankaj Gupta 	/* start block */
1432066ee1adSPankaj Gupta 	blk = dst_offset / mmc->card.block_len;
1433066ee1adSPankaj Gupta #ifdef NXP_SD_DEBUG
1434066ee1adSPankaj Gupta 	INFO("blk = %x\n", blk);
1435066ee1adSPankaj Gupta #endif
1436066ee1adSPankaj Gupta 
1437066ee1adSPankaj Gupta 	/* Number of blocks to be written */
1438066ee1adSPankaj Gupta 	num_blocks = size / mmc->card.block_len;
1439066ee1adSPankaj Gupta 
1440066ee1adSPankaj Gupta 	while (num_blocks != 0U) {
1441066ee1adSPankaj Gupta 		error = esdhc_write_block(mmc, buff, blk);
1442066ee1adSPankaj Gupta 		if (error != 0U) {
1443066ee1adSPankaj Gupta 			ERROR("Write error = %x\n", error);
1444066ee1adSPankaj Gupta 			return error;
1445066ee1adSPankaj Gupta 		}
1446066ee1adSPankaj Gupta 
1447066ee1adSPankaj Gupta 		buff = buff + mmc->card.block_len;
1448066ee1adSPankaj Gupta 		blk++;
1449066ee1adSPankaj Gupta 		num_blocks--;
1450066ee1adSPankaj Gupta 	}
1451066ee1adSPankaj Gupta 
1452066ee1adSPankaj Gupta 	INFO("sd-mmc write done.\n");
1453066ee1adSPankaj Gupta 	return error;
1454066ee1adSPankaj Gupta }
1455066ee1adSPankaj Gupta 
ls_sd_emmc_read(int lba,uintptr_t buf,size_t size)1456066ee1adSPankaj Gupta static size_t ls_sd_emmc_read(int lba, uintptr_t buf, size_t size)
1457066ee1adSPankaj Gupta {
1458066ee1adSPankaj Gupta 	struct mmc *mmc = NULL;
1459066ee1adSPankaj Gupta 	int ret;
1460066ee1adSPankaj Gupta 
1461066ee1adSPankaj Gupta 	mmc = &mmc_drv_data;
1462066ee1adSPankaj Gupta 	lba *= BLOCK_LEN_512;
1463066ee1adSPankaj Gupta 	ret = esdhc_read(mmc, lba, buf, size);
1464066ee1adSPankaj Gupta 	return ret ? 0 : size;
1465066ee1adSPankaj Gupta }
1466066ee1adSPankaj Gupta 
1467066ee1adSPankaj Gupta static struct io_block_dev_spec ls_emmc_dev_spec = {
1468066ee1adSPankaj Gupta 	.buffer = {
1469066ee1adSPankaj Gupta 		.offset = 0,
1470066ee1adSPankaj Gupta 		.length = 0,
1471066ee1adSPankaj Gupta 	},
1472066ee1adSPankaj Gupta 	.ops = {
1473066ee1adSPankaj Gupta 		.read = ls_sd_emmc_read,
1474066ee1adSPankaj Gupta 	},
1475066ee1adSPankaj Gupta 	.block_size = BLOCK_LEN_512,
1476066ee1adSPankaj Gupta };
1477066ee1adSPankaj Gupta 
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)1478066ee1adSPankaj Gupta int sd_emmc_init(uintptr_t *block_dev_spec,
1479066ee1adSPankaj Gupta 			uintptr_t nxp_esdhc_addr,
1480066ee1adSPankaj Gupta 			size_t nxp_sd_block_offset,
1481066ee1adSPankaj Gupta 			size_t nxp_sd_block_size,
1482066ee1adSPankaj Gupta 			bool card_detect)
1483066ee1adSPankaj Gupta {
1484066ee1adSPankaj Gupta 	int ret;
1485066ee1adSPankaj Gupta 
1486066ee1adSPankaj Gupta 	ret = sd_mmc_init(nxp_esdhc_addr, card_detect);
1487066ee1adSPankaj Gupta 	if (ret != 0) {
1488066ee1adSPankaj Gupta 		return ret;
1489066ee1adSPankaj Gupta 	}
1490066ee1adSPankaj Gupta 
1491066ee1adSPankaj Gupta 	ls_emmc_dev_spec.buffer.offset = nxp_sd_block_offset;
1492066ee1adSPankaj Gupta 	ls_emmc_dev_spec.buffer.length = nxp_sd_block_size;
1493066ee1adSPankaj Gupta 	*block_dev_spec = (uintptr_t)&ls_emmc_dev_spec;
1494066ee1adSPankaj Gupta 
1495066ee1adSPankaj Gupta 	return 0;
1496066ee1adSPankaj Gupta }
1497