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