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