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 *****************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 ***************************************************************************/ 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 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 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