/**************************************************************************//** * @file sd.c * @version V3.00 * @brief N9H20 series SIC driver source file * * SPDX-License-Identifier: Apache-2.0 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. *****************************************************************************/ #ifdef ECOS #include "drv_api.h" #include "diag.h" #include "wbtypes.h" #include "wbio.h" #else #include "wblib.h" #endif #include "N9H20_SIC.h" #include "fmi.h" #include "N9H20_NVTFAT.h" // define DATE CODE and show it when running to make maintaining easy. #define SD_DATE_CODE FMI_DATE_CODE #define SD_BLOCK_SIZE 512 #define FMI_SD_INITCOUNT 2000 #define FMI_TICKCOUNT 1000 #define FMI_TYPE_UNKNOWN 0 #define FMI_TYPE_SD_HIGH 1 #define FMI_TYPE_SD_LOW 2 #define FMI_TYPE_MMC 3 // global variables // For response R3 (such as ACMD41, CRC-7 is invalid; but SD controller will still // calculate CRC-7 and get an error result, software should ignore this error and clear SDISR [CRC_IF] flag // _fmi_uR3_CMD is the flag for it. 1 means software should ignore CRC-7 error UINT32 _fmi_uR3_CMD=0; UINT32 _fmi_uR7_CMD=0; #if defined (__GNUC__) UCHAR _fmi_ucSDHCBuffer[512] __attribute__((aligned (4096))); #else __align(4096) UCHAR _fmi_ucSDHCBuffer[512]; #endif UINT8 *_fmi_pSDHCBuffer; //--- 2014/3/27, check the sector number is valid or not for current SD card. unsigned int g_max_valid_sector; // The max valid sector number for current SD card. INT fmiSDCheckSector(UINT32 uSector, UINT32 uBufcnt) { if ((uSector + uBufcnt - 1) > g_max_valid_sector) { sysprintf("ERROR: Fail to access invalid sector number %d from SD card !!\n", uSector+uBufcnt-1); sysprintf(" The max valid sector number for current SD card is %d.\n", g_max_valid_sector); return FMI_SD_SELECT_ERROR; // invalid sector } return 0; // valid sector } void fmiCheckRB() { while(1) { outpw(REG_SDCR, inpw(REG_SDCR)|SDCR_8CLK_OE); while(inpw(REG_SDCR) & SDCR_8CLK_OE); if (inpw(REG_SDISR) & SDISR_SD_DATA0) break; } } INT fmiSDCommand(FMI_SD_INFO_T *pSD, UINT8 ucCmd, UINT32 uArg) { outpw(REG_SDARG, uArg); outpw(REG_SDCR, (inpw(REG_SDCR)&(~SDCR_CMD_CODE))|(ucCmd << 8)|(SDCR_CO_EN)); while(inpw(REG_SDCR) & SDCR_CO_EN) { if (pSD == pSD0) fmiSD_CardStatus(); if (pSD->bIsCardInsert == FALSE) return FMI_NO_SD_CARD; } return Successful; } INT fmiSDCmdAndRsp(FMI_SD_INFO_T *pSD, UINT8 ucCmd, UINT32 uArg, INT ntickCount) { outpw(REG_SDARG, uArg); outpw(REG_SDCR, (inpw(REG_SDCR)&(~SDCR_CMD_CODE))|(ucCmd << 8)|(SDCR_CO_EN | SDCR_RI_EN)); if (ntickCount > 0) { while(inpw(REG_SDCR) & SDCR_RI_EN) { if(ntickCount-- == 0) { outpw(REG_SDCR, inpw(REG_SDCR)|SDCR_SWRST); // reset SD engine return FMI_SD_INIT_TIMEOUT; } if (pSD == pSD0) fmiSD_CardStatus(); if (pSD->bIsCardInsert == FALSE) return FMI_NO_SD_CARD; } } else { while(inpw(REG_SDCR) & SDCR_RI_EN) { if (pSD == pSD0) fmiSD_CardStatus(); if (pSD->bIsCardInsert == FALSE) return FMI_NO_SD_CARD; } } if (_fmi_uR7_CMD) { if (((inpw(REG_SDRSP1) & 0xff) != 0x55) && ((inpw(REG_SDRSP0) & 0xf) != 0x01)) { _fmi_uR7_CMD = 0; return FMI_SD_CMD8_ERROR; } } if (!_fmi_uR3_CMD) { if (inpw(REG_SDISR) & SDISR_CRC_7) // check CRC7 return Successful; else { #ifdef DEBUG sysprintf("response error [%d]!\n", ucCmd); #endif return FMI_SD_CRC7_ERROR; } } else // ignore CRC error for R3 case { _fmi_uR3_CMD = 0; outpw(REG_SDISR, SDISR_CRC_IF); return Successful; } } // Get 16 bytes CID or CSD INT fmiSDCmdAndRsp2(FMI_SD_INFO_T *pSD, UINT8 ucCmd, UINT32 uArg, UINT *puR2ptr) { unsigned int i; unsigned int tmpBuf[5]; outpw(REG_SDARG, uArg); outpw(REG_SDCR, (inpw(REG_SDCR)&(~SDCR_CMD_CODE))|(ucCmd << 8)|(SDCR_CO_EN | SDCR_R2_EN)); while(inpw(REG_SDCR) & SDCR_R2_EN) { if (pSD == pSD0) fmiSD_CardStatus(); if (pSD->bIsCardInsert == FALSE) return FMI_NO_SD_CARD; } if (inpw(REG_SDISR) & SDISR_CRC_7) { for (i=0; i<5; i++) tmpBuf[i] = Swap32(inpw(REG_FB_0+i*4)); for (i=0; i<4; i++) *puR2ptr++ = ((tmpBuf[i] & 0x00ffffff)<<8) | ((tmpBuf[i+1] & 0xff000000)>>24); return Successful; } else return FMI_SD_CRC7_ERROR; } INT fmiSDCmdAndRspDataIn(FMI_SD_INFO_T *pSD, UINT8 ucCmd, UINT32 uArg) { outpw(REG_SDARG, uArg); outpw(REG_SDCR, (inpw(REG_SDCR)&(~SDCR_CMD_CODE))|(ucCmd << 8)|(SDCR_CO_EN | SDCR_RI_EN | SDCR_DI_EN)); while (inpw(REG_SDCR) & SDCR_RI_EN) { if (pSD == pSD0) fmiSD_CardStatus(); if (pSD->bIsCardInsert == FALSE) return FMI_NO_SD_CARD; } while (inpw(REG_SDCR) & SDCR_DI_EN) { if (pSD == pSD0) fmiSD_CardStatus(); if (pSD->bIsCardInsert == FALSE) return FMI_NO_SD_CARD; } if (!(inpw(REG_SDISR) & SDISR_CRC_7)) // check CRC7 { #ifdef DEBUG sysprintf("fmiSDCmdAndRspDataIn: response error [%d]!\n", ucCmd); #endif return FMI_SD_CRC7_ERROR; } if (!(inpw(REG_SDISR) & SDISR_CRC_16)) // check CRC16 { #ifdef DEBUG sysprintf("fmiSDCmdAndRspDataIn: read data CRC16 error!\n"); #endif return FMI_SD_CRC16_ERROR; } return Successful; } // Initial INT fmiSD_Init(FMI_SD_INFO_T *pSD) { int volatile i, status, rate; unsigned int resp; unsigned int CIDBuffer[4]; unsigned int volatile u32CmdTimeOut; int sdport; if (pSD == pSD0) sdport = 0; else if (pSD == pSD1) sdport = 1; else if (pSD == pSD2) sdport = 2; else return FMI_SD_INIT_ERROR; sysprintf("Initial SD NonOS Driver (%s) for SD port %d\n", SD_DATE_CODE, sdport); #if 1 // set the clock to 200KHz /* divider */ rate = _fmi_uFMIReferenceClock / 200; if ((_fmi_uFMIReferenceClock % 200) == 0) rate = rate - 1; #else // set the clock to 400KHz /* divider */ rate = _fmi_uFMIReferenceClock / 400; if ((_fmi_uFMIReferenceClock % 400) == 0) rate = rate - 1; #endif for(i=0; i<100; i++); outpw(REG_CLKDIV2, (inpw(REG_CLKDIV2) & ~SD_S) | (0x03 << 19)); // SD clock from UPLL outpw(REG_CLKDIV2, (inpw(REG_CLKDIV2) & ~SD_N0) | (0x07 << 16)); // SD clock divided by 8 rate /= 8; rate &= 0xFF; if (rate) rate--; outpw(REG_CLKDIV2, (inpw(REG_CLKDIV2) & ~SD_N1) | (rate << 24)); // SD clock divider for(i=0; i<1000; i++); // power ON 74 clock outpw(REG_SDCR, inpw(REG_SDCR) | SDCR_74CLK_OE); while(inpw(REG_SDCR) & SDCR_74CLK_OE) { if (pSD == pSD0) fmiSD_CardStatus(); if (pSD->bIsCardInsert == FALSE) return FMI_NO_SD_CARD; } fmiSDCommand(pSD, 0, 0); // reset all cards for (i=0x100; i>0; i--); // initial SDHC _fmi_uR7_CMD = 1; u32CmdTimeOut = 5000; i = fmiSDCmdAndRsp(pSD, 8, 0x00000155, u32CmdTimeOut); _fmi_uR7_CMD = 0; // Disable R7 checking for commands that are not CMD8 if (i == Successful) { // SD 2.0 fmiSDCmdAndRsp(pSD, 55, 0x00, u32CmdTimeOut); _fmi_uR3_CMD = 1; fmiSDCmdAndRsp(pSD, 41, 0x40ff8000, u32CmdTimeOut); // 2.7v-3.6v resp = inpw(REG_SDRSP0); while (!(resp & 0x00800000)) // check if card is ready { fmiSDCmdAndRsp(pSD, 55, 0x00, u32CmdTimeOut); _fmi_uR3_CMD = 1; fmiSDCmdAndRsp(pSD, 41, 0x40ff8000, u32CmdTimeOut); // 3.0v-3.4v resp = inpw(REG_SDRSP0); } if (resp & 0x00400000) pSD->uCardType = FMI_TYPE_SD_HIGH; else pSD->uCardType = FMI_TYPE_SD_LOW; } else { // SD 1.1 or MMC fmiSDCommand(pSD, 0, 0); // reset all cards for (i=0x100; i>0; i--); i = fmiSDCmdAndRsp(pSD, 55, 0x00, u32CmdTimeOut); if (i == FMI_SD_INIT_TIMEOUT) // MMC memory { fmiSDCommand(pSD, 0, 0); // reset for (i=0x100; i>0; i--); _fmi_uR3_CMD = 1; // 2014/8/6, to support eMMC v4.4, the argument of CMD1 should be 0x40ff8000 to support both MMC plus and eMMC cards. if (fmiSDCmdAndRsp(pSD, 1, 0x40ff8000, u32CmdTimeOut) != FMI_SD_INIT_TIMEOUT) // MMC memory { resp = inpw(REG_SDRSP0); while (!(resp & 0x00800000)) // check if card is ready { _fmi_uR3_CMD = 1; fmiSDCmdAndRsp(pSD, 1, 0x40ff8000, u32CmdTimeOut); // high voltage resp = inpw(REG_SDRSP0); } // MMC card is ready. Check the access mode of MMC card. if (resp & 0x00400000) pSD->uCardType = FMI_TYPE_MMC_SECTOR_MODE; else pSD->uCardType = FMI_TYPE_MMC; } else { pSD->uCardType = FMI_TYPE_UNKNOWN; return FMI_ERR_DEVICE; } } else if (i == Successful) // SD Memory { _fmi_uR3_CMD = 1; fmiSDCmdAndRsp(pSD, 41, 0x00ff8000, u32CmdTimeOut); // 3.0v-3.4v resp = inpw(REG_SDRSP0); while (!(resp & 0x00800000)) // check if card is ready { fmiSDCmdAndRsp(pSD, 55, 0x00,u32CmdTimeOut); _fmi_uR3_CMD = 1; fmiSDCmdAndRsp(pSD, 41, 0x00ff8000, u32CmdTimeOut); // 3.0v-3.4v resp = inpw(REG_SDRSP0); } pSD->uCardType = FMI_TYPE_SD_LOW; } else { pSD->uCardType = FMI_TYPE_UNKNOWN; #ifdef DEBUG sysprintf("CMD55 CRC error !!\n"); #endif return FMI_SD_INIT_ERROR; } } // CMD2, CMD3 if (pSD->uCardType != FMI_TYPE_UNKNOWN) { fmiSDCmdAndRsp2(pSD, 2, 0x00, CIDBuffer); if ((pSD->uCardType == FMI_TYPE_MMC) || (pSD->uCardType == FMI_TYPE_MMC_SECTOR_MODE)) { // Increase RCA for next MMC card. // The RCA value 0 is reserved to set all cards with CMD7. // The default value is 1. pSD->uRCA = (pSD->uRCA + 0x10000) & 0xFFFF0000; // RCA is 16-bit value at MSB if (pSD->uRCA == 0) pSD->uRCA = 0x10000; if ((status = fmiSDCmdAndRsp(pSD, 3, pSD->uRCA, 0)) != Successful) // set RCA for MMC return status; } else { if ((status = fmiSDCmdAndRsp(pSD, 3, 0x00, 0)) != Successful) // get RCA for SD return status; else pSD->uRCA = (inpw(REG_SDRSP0) << 8) & 0xffff0000; } } #ifdef DEBUG switch (pSD->uCardType) { case FMI_TYPE_SD_HIGH: DBG_PRINTF("This is high capacity SD memory card\n"); break; case FMI_TYPE_SD_LOW: DBG_PRINTF("This is standard capacity SD memory card\n"); break; case FMI_TYPE_MMC: DBG_PRINTF("This is standard capacity MMC memory card\n"); break; case FMI_TYPE_MMC_SECTOR_MODE: DBG_PRINTF("This is high capacity MMC memory card\n"); break; } #endif // set data transfer clock return Successful; } INT fmiSwitchToHighSpeed(FMI_SD_INFO_T *pSD) { int volatile status=0; UINT16 current_comsumption, busy_status0, busy_status1; // UINT16 fun1_info, switch_status; outpw(REG_DMACSAR, (UINT32)_fmi_pSDHCBuffer); // set DMA transfer starting address outpw(REG_SDBLEN, 63); // 512 bit if ((status = fmiSDCmdAndRspDataIn(pSD, 6, 0x00ffff01)) != Successful) return Fail; current_comsumption = _fmi_pSDHCBuffer[0]<<8 | _fmi_pSDHCBuffer[1]; if (!current_comsumption) return Fail; // fun1_info = _fmi_pSDHCBuffer[12]<<8 | _fmi_pSDHCBuffer[13]; // switch_status = _fmi_pSDHCBuffer[16] & 0xf; busy_status0 = _fmi_pSDHCBuffer[28]<<8 | _fmi_pSDHCBuffer[29]; if (!busy_status0) // function ready { outpw(REG_DMACSAR, (UINT32)_fmi_pSDHCBuffer); // set DMA transfer starting address outpw(REG_SDBLEN, 63); // 512 bit if ((status = fmiSDCmdAndRspDataIn(pSD, 6, 0x80ffff01)) != Successful) return Fail; // function change timing: 8 clocks outpw(REG_SDCR, inpw(REG_SDCR)|SDCR_8CLK_OE); while(inpw(REG_SDCR) & SDCR_8CLK_OE); current_comsumption = _fmi_pSDHCBuffer[0]<<8 | _fmi_pSDHCBuffer[1]; if (!current_comsumption) return Fail; busy_status1 = _fmi_pSDHCBuffer[28]<<8 | _fmi_pSDHCBuffer[29]; if (!busy_status1) sysprintf("switch into high speed mode !!!\n"); return Successful; } else return Fail; } INT fmiSelectCard(FMI_SD_INFO_T *pSD) { int volatile status=0, i; int rate; UINT32 arg; if ((status = fmiSDCmdAndRsp(pSD, 7, pSD->uRCA, 0)) != Successful) return status; fmiCheckRB(); // if SD card set 4bit if (pSD->uCardType == FMI_TYPE_SD_HIGH) { _fmi_pSDHCBuffer = (UINT8 *)((UINT32)_fmi_ucSDHCBuffer | 0x80000000); outpw(REG_DMACSAR, (UINT32)_fmi_pSDHCBuffer); // set DMA transfer starting address outpw(REG_SDBLEN, 7); // 64 bit if ((status = fmiSDCmdAndRsp(pSD, 55, pSD->uRCA, 0)) != Successful) return status; if ((status = fmiSDCmdAndRspDataIn(pSD, 51, 0x00)) != Successful) return status; if ((_fmi_ucSDHCBuffer[0] & 0xf) == 0x2) { // support SD spec v2.0 status = fmiSwitchToHighSpeed(pSD); if (status == Successful) { /* divider */ rate = _fmi_uFMIReferenceClock / SDHC_FREQ; if ((_fmi_uFMIReferenceClock % SDHC_FREQ) > 0) rate ++; for(i=0; i<100; i++); outpw(REG_CLKDIV2, (inpw(REG_CLKDIV2) & ~SD_S) | (0x03 << 19)); // SD clock from UPLL outpw(REG_CLKDIV2, (inpw(REG_CLKDIV2) & ~SD_N0) | (0x01 << 16)); // SD clock divided by 8 if (rate % 2) { rate /= 2; rate &= 0xFF; } else { rate /= 2; rate &= 0xFF; rate--; } outpw(REG_CLKDIV2, (inpw(REG_CLKDIV2) & ~SD_N1) | (rate << 24)); // SD clock divider for(i=0; i<1000; i++); } } if ((status = fmiSDCmdAndRsp(pSD, 55, pSD->uRCA, 0)) != Successful) return status; if ((status = fmiSDCmdAndRsp(pSD, 6, 0x02, 0)) != Successful) // set bus width to 4-bit mode for SD card return status; outpw(REG_SDCR, inpw(REG_SDCR)|SDCR_DBW); // set bus width to 4-bit mode for SD host controller } else if (pSD->uCardType == FMI_TYPE_SD_LOW) { #if 0 _fmi_pSDHCBuffer = (UINT8 *)((UINT32)_fmi_ucSDHCBuffer | 0x80000000); outpw(REG_DMACSAR, (UINT32)_fmi_pSDHCBuffer); // set DMA transfer starting address outpw(REG_SDBLEN, 7); // 64 bit if ((status = fmiSDCmdAndRsp(pSD, 55, pSD->uRCA, 0)) != Successful) return status; if ((status = fmiSDCmdAndRspDataIn(pSD, 51, 0x00)) != Successful) return status; #endif if ((status = fmiSDCmdAndRsp(pSD, 55, pSD->uRCA, 0)) != Successful) return status; if ((status = fmiSDCmdAndRsp(pSD, 6, 0x02, 0)) != Successful) // set bus width to 4-bit mode for SD card return status; outpw(REG_SDCR, inpw(REG_SDCR)|SDCR_DBW); // set bus width to 4-bit mode for SD host controller } else if ((pSD->uCardType == FMI_TYPE_MMC) || (pSD->uCardType == FMI_TYPE_MMC_SECTOR_MODE)) { //--- sent CMD6 to MMC card to set bus width to 4 bits mode // set CMD6 argument Access field to 3, Index to 183, Value to 1 (4-bit mode) arg = (3 << 24) | (183 << 16) | (1 << 8); if ((status = fmiSDCmdAndRsp(pSD, 6, arg, 0)) != Successful) return status; fmiCheckRB(); outpw(REG_SDCR, inpw(REG_SDCR)|SDCR_DBW); // set bus width to 4-bit mode for SD host controller } if ((status = fmiSDCmdAndRsp(pSD, 16, SD_BLOCK_SIZE, 0)) != Successful) // set block length return status; fmiSDCommand(pSD, 7, 0); // According to SD spec v2.0 chapter 4.4, // "After the last SD Memory Card bus transaction, the host is required, // to provide 8 (eight) clock cycles for the card to complete the // operation before shutting down the clock." outpw(REG_SDCR, inpw(REG_SDCR)|SDCR_8CLK_OE); #ifdef _SIC_USE_INT_ outpw(REG_SDIER, inpw(REG_SDIER)|SDIER_BLKD_IEN); #endif //_SIC_USE_INT_ return Successful; } /*----------------------------------------------------------------------------- * fmiSD_Read_in(), To read data with default black size SD_BLOCK_SIZE *---------------------------------------------------------------------------*/ INT fmiSD_Read_in(FMI_SD_INFO_T *pSD, UINT32 uSector, UINT32 uBufcnt, UINT32 uDAddr) { BOOL volatile bIsSendCmd=FALSE; unsigned int volatile reg; int volatile i, loop, status; //--- check input parameters status = fmiSDCheckSector(uSector, uBufcnt); if (status < 0) return status; // invalid sector if (uBufcnt == 0) { sysprintf("ERROR: fmiSD_Read_in(): uBufcnt cannot be 0!!\n"); return FMI_SD_SELECT_ERROR; } if ((status = fmiSDCmdAndRsp(pSD, 7, pSD->uRCA, 0)) != Successful) return status; fmiCheckRB(); outpw(REG_SDBLEN, SD_BLOCK_SIZE - 1); if ((pSD->uCardType == FMI_TYPE_SD_HIGH) || (pSD->uCardType == FMI_TYPE_MMC_SECTOR_MODE)) outpw(REG_SDARG, uSector); else outpw(REG_SDARG, uSector * SD_BLOCK_SIZE); outpw(REG_DMACSAR, uDAddr); loop = uBufcnt / 255; for (i=0; i<loop; i++) { #ifdef _SIC_USE_INT_ _fmi_bIsSDDataReady = FALSE; #endif //_SIC_USE_INT_ reg = inpw(REG_SDCR) & ~SDCR_CMD_CODE; reg = reg | 0xff0000; // set BLK_CNT to 255 if (bIsSendCmd == FALSE) { outpw(REG_SDCR, reg|(18<<8)|(SDCR_CO_EN | SDCR_RI_EN | SDCR_DI_EN)); bIsSendCmd = TRUE; } else outpw(REG_SDCR, reg | SDCR_DI_EN); #ifdef _SIC_USE_INT_ while(!_fmi_bIsSDDataReady) #else while(1) #endif //_SIC_USE_INT_ { #ifndef _SIC_USE_INT_ if ((inpw(REG_SDISR) & SDISR_BLKD_IF) && (!(inpw(REG_SDCR) & SDCR_DI_EN))) { outpw(REG_SDISR, SDISR_BLKD_IF); break; } #endif if (pSD == pSD0) fmiSD_CardStatus(); if (pSD->bIsCardInsert == FALSE) return FMI_NO_SD_CARD; /* Call schedule() to release CPU power to other tasks during waiting SIC/DMA completed. */ schedule(); } if (!(inpw(REG_SDISR) & SDISR_CRC_7)) // check CRC7 { #ifdef DEBUG sysprintf("fmiSD_Read_in(): response error!\n"); #endif return FMI_SD_CRC7_ERROR; } if (!(inpw(REG_SDISR) & SDISR_CRC_16)) // check CRC16 { #ifdef DEBUG sysprintf("fmiSD_Read_in() :read data CRC16 error!\n"); #endif return FMI_SD_CRC16_ERROR; } } loop = uBufcnt % 255; if (loop != 0) { #ifdef _SIC_USE_INT_ _fmi_bIsSDDataReady = FALSE; #endif //_SIC_USE_INT_ reg = inpw(REG_SDCR) & (~SDCR_CMD_CODE); reg = reg & (~SDCR_BLKCNT); reg |= (loop << 16); // setup SDCR_BLKCNT if (bIsSendCmd == FALSE) { outpw(REG_SDCR, reg|(18<<8)|(SDCR_CO_EN | SDCR_RI_EN | SDCR_DI_EN)); bIsSendCmd = TRUE; } else outpw(REG_SDCR, reg | SDCR_DI_EN); #ifdef _SIC_USE_INT_ while(!_fmi_bIsSDDataReady) #else while(1) #endif //_SIC_USE_INT_ { #ifndef _SIC_USE_INT_ if ((inpw(REG_SDISR) & SDISR_BLKD_IF) && (!(inpw(REG_SDCR) & SDCR_DI_EN))) { outpw(REG_SDISR, SDISR_BLKD_IF); break; } #endif if (pSD == pSD0) fmiSD_CardStatus(); if (pSD->bIsCardInsert == FALSE) return FMI_NO_SD_CARD; /* Call schedule() to release CPU power to other tasks during waiting SIC/DMA completed. */ schedule(); } if (!(inpw(REG_SDISR) & SDISR_CRC_7)) // check CRC7 { #ifdef DEBUG sysprintf("fmiSD_Read_in(): response error!\n"); #endif return FMI_SD_CRC7_ERROR; } if (!(inpw(REG_SDISR) & SDISR_CRC_16)) // check CRC16 { #ifdef DEBUG sysprintf("fmiSD_Read_in(): read data CRC16 error!\n"); #endif return FMI_SD_CRC16_ERROR; } } if (fmiSDCmdAndRsp(pSD, 12, 0, 0)) // stop command { #ifdef DEBUG sysprintf("stop command fail !!\n"); #endif return FMI_SD_CRC7_ERROR; } fmiCheckRB(); fmiSDCommand(pSD, 7, 0); // According to SD spec v2.0 chapter 4.4, // "After the last SD Memory Card bus transaction, the host is required, // to provide 8 (eight) clock cycles for the card to complete the // operation before shutting down the clock." outpw(REG_SDCR, inpw(REG_SDCR)|SDCR_8CLK_OE); return Successful; } /*----------------------------------------------------------------------------- * fmiSD_Write_in(), To write data with static black size SD_BLOCK_SIZE *---------------------------------------------------------------------------*/ INT fmiSD_Write_in(FMI_SD_INFO_T *pSD, UINT32 uSector, UINT32 uBufcnt, UINT32 uSAddr) { BOOL volatile bIsSendCmd=FALSE; unsigned int volatile reg; int volatile i, loop, status; //--- check input parameters status = fmiSDCheckSector(uSector, uBufcnt); if (status < 0) return status; // invalid sector if (uBufcnt == 0) { sysprintf("ERROR: fmiSD_Write_in(): uBufcnt cannot be 0!!\n"); return FMI_SD_SELECT_ERROR; } if ((status = fmiSDCmdAndRsp(pSD, 7, pSD->uRCA, 0)) != Successful) return status; fmiCheckRB(); // According to SD Spec v2.0, the write CMD block size MUST be 512, and the start address MUST be 512*n. outpw(REG_SDBLEN, SD_BLOCK_SIZE - 1); // set the block size if ((pSD->uCardType == FMI_TYPE_SD_HIGH) || (pSD->uCardType == FMI_TYPE_MMC_SECTOR_MODE)) outpw(REG_SDARG, uSector); else outpw(REG_SDARG, uSector * SD_BLOCK_SIZE); // set start address for SD CMD outpw(REG_DMACSAR, uSAddr); loop = uBufcnt / 255; // the maximum block count is 0xFF=255 for register SDCR[BLK_CNT] for (i=0; i<loop; i++) { #ifdef _SIC_USE_INT_ _fmi_bIsSDDataReady = FALSE; #endif //_SIC_USE_INT_ reg = inpw(REG_SDCR) & 0xff00c080; reg = reg | 0xff0000; // set BLK_CNT to 0xFF=255 if (!bIsSendCmd) { outpw(REG_SDCR, reg|(25<<8)|(SDCR_CO_EN | SDCR_RI_EN | SDCR_DO_EN)); bIsSendCmd = TRUE; } else outpw(REG_SDCR, reg | SDCR_DO_EN); #ifdef _SIC_USE_INT_ while(!_fmi_bIsSDDataReady) #else while(1) #endif //_SIC_USE_INT_ { #ifndef _SIC_USE_INT_ if ((inpw(REG_SDISR) & SDISR_BLKD_IF) && (!(inpw(REG_SDCR) & SDCR_DO_EN))) { outpw(REG_SDISR, SDISR_BLKD_IF); break; } #endif if (pSD == pSD0) fmiSD_CardStatus(); if (pSD->bIsCardInsert == FALSE) return FMI_NO_SD_CARD; /* Call schedule() to release CPU power to other tasks during waiting SIC/DMA completed. */ schedule(); } if ((inpw(REG_SDISR) & SDISR_CRC_IF) != 0) // check CRC { #ifdef DEBUG sysprintf("1. fmiSD_Write:write data error [SDISR = 0x%08X]\n", inpw(REG_SDISR)); #endif outpw(REG_SDISR, SDISR_CRC_IF); return FMI_SD_CRC_ERROR; } } loop = uBufcnt % 255; if (loop != 0) { #ifdef _SIC_USE_INT_ _fmi_bIsSDDataReady = FALSE; #endif //_SIC_USE_INT_ reg = (inpw(REG_SDCR) & 0xff00c080) | (loop << 16); if (!bIsSendCmd) { outpw(REG_SDCR, reg|(25<<8)|(SDCR_CO_EN | SDCR_RI_EN | SDCR_DO_EN)); bIsSendCmd = TRUE; } else outpw(REG_SDCR, reg | SDCR_DO_EN); #ifdef _SIC_USE_INT_ while(!_fmi_bIsSDDataReady) #else while(1) #endif //_SIC_USE_INT_ { #ifndef _SIC_USE_INT_ if ((inpw(REG_SDISR) & SDISR_BLKD_IF) && (!(inpw(REG_SDCR) & SDCR_DO_EN))) { outpw(REG_SDISR, SDISR_BLKD_IF); break; } #endif if (pSD == pSD0) fmiSD_CardStatus(); if (pSD->bIsCardInsert == FALSE) return FMI_NO_SD_CARD; /* Call schedule() to release CPU power to other tasks during waiting SIC/DMA completed. */ schedule(); } if ((inpw(REG_SDISR) & SDISR_CRC_IF) != 0) // check CRC { #ifdef DEBUG sysprintf("2. fmiSD_Write:write data error [SDISR = 0x%08X]\n", inpw(REG_SDISR)); #endif outpw(REG_SDISR, SDISR_CRC_IF); return FMI_SD_CRC_ERROR; } } outpw(REG_SDISR, SDISR_CRC_IF); if (fmiSDCmdAndRsp(pSD, 12, 0, 0)) // stop command { #ifdef DEBUG sysprintf("stop command fail !!\n"); #endif return FMI_SD_CRC7_ERROR; } fmiCheckRB(); fmiSDCommand(pSD, 7, 0); // According to SD spec v2.0 chapter 4.4, // "After the last SD Memory Card bus transaction, the host is required, // to provide 8 (eight) clock cycles for the card to complete the // operation before shutting down the clock." outpw(REG_SDCR, inpw(REG_SDCR)|SDCR_8CLK_OE); return Successful; } VOID fmiGet_SD_info(FMI_SD_INFO_T *pSD, DISK_DATA_T *_info) { unsigned int i; unsigned int R_LEN, C_Size, MULT, size; unsigned int Buffer[4]; unsigned char *ptr; int volatile status; fmiSDCmdAndRsp2(pSD, 9, pSD->uRCA, Buffer); #ifdef DEBUG sysprintf("max. data transfer rate [%x][%08x]\n", Buffer[0]&0xff, Buffer[0]); sysprintf("CSD = 0x%08X 0x%08X 0x%08X 0x%08X\n", Buffer[0], Buffer[1], Buffer[2], Buffer[3]); #endif if ((pSD->uCardType == FMI_TYPE_MMC) || (pSD->uCardType == FMI_TYPE_MMC_SECTOR_MODE)) { // for MMC/eMMC card if ((Buffer[0] & 0xc0000000) == 0xc0000000) { // CSD_STRUCTURE [127:126] is 3 // CSD version depend on EXT_CSD register in eMMC v4.4 for card size > 2GB fmiSDCmdAndRsp(pSD, 7, pSD->uRCA, 0); _fmi_pSDHCBuffer = (UINT8 *)((UINT32)_fmi_ucSDHCBuffer | 0x80000000); outpw(REG_DMACSAR, (UINT32)_fmi_pSDHCBuffer); // set DMA transfer starting address outpw(REG_SDBLEN, 511); // read 512 bytes for EXT_CSD if ((status = fmiSDCmdAndRspDataIn(pSD, 8, 0x00)) != Successful) return; fmiSDCommand(pSD, 7, 0); // According to SD spec v2.0 chapter 4.4, // "After the last SD Memory Card bus transaction, the host is required, // to provide 8 (eight) clock cycles for the card to complete the // operation before shutting down the clock." outpw(REG_SDCR, inpw(REG_SDCR)|SDCR_8CLK_OE); _info->totalSectorN = (*(UINT32 *)(_fmi_pSDHCBuffer+212)); _info->diskSize = _info->totalSectorN / 2; } else { // CSD version v1.0/1.1/1.2 in eMMC v4.4 spec for card size <= 2GB R_LEN = (Buffer[1] & 0x000f0000) >> 16; C_Size = ((Buffer[1] & 0x000003ff) << 2) | ((Buffer[2] & 0xc0000000) >> 30); MULT = (Buffer[2] & 0x00038000) >> 15; size = (C_Size+1) * (1<<(MULT+2)) * (1<<R_LEN); _info->diskSize = size / 1024; _info->totalSectorN = size / 512; } } else { // for SD/SDHC card if ((Buffer[0] & 0xc0000000) && (pSD->uCardType != FMI_TYPE_MMC)) { // CSD version 2.0 in SD v2.0 spec for SDHC card C_Size = ((Buffer[1] & 0x0000003f) << 16) | ((Buffer[2] & 0xffff0000) >> 16); size = (C_Size+1) * 512; // Kbytes _info->diskSize = size; _info->totalSectorN = size << 1; } else { // CSD version 1.0 in SD v2.0 spec for SD card R_LEN = (Buffer[1] & 0x000f0000) >> 16; C_Size = ((Buffer[1] & 0x000003ff) << 2) | ((Buffer[2] & 0xc0000000) >> 30); MULT = (Buffer[2] & 0x00038000) >> 15; size = (C_Size+1) * (1<<(MULT+2)) * (1<<R_LEN); _info->diskSize = size / 1024; _info->totalSectorN = size / 512; } } _info->sectorSize = 512; g_max_valid_sector = _info->totalSectorN; fmiSDCmdAndRsp2(pSD, 10, pSD->uRCA, Buffer); _info->vendor[0] = (Buffer[0] & 0xff000000) >> 24; ptr = (unsigned char *)Buffer; ptr = (unsigned char *)Buffer + 3; for (i=0; i<5; i++) _info->product[i] = *ptr++; ptr = (unsigned char *)Buffer + 9; for (i=0; i<4; i++) _info->serial[i] = *ptr++; #ifdef DEBUG sysprintf("SD card CID is %08X-%08X-%08X-%08X\n", Buffer[0], Buffer[1], Buffer[2], Buffer[3]); #endif }