blob: 8353daa21fab8078cfde583e7e93c4bc6fd63e12 [file] [log] [blame]
/******************************************************************************
*
* (C)Copyright 2005 - 2011 Marvell. All Rights Reserved.
*
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MARVELL.
* The copyright notice above does not evidence any actual or intended
* publication of such source code.
* This Module contains Proprietary Information of Marvell and should be
* treated as Confidential.
* The information in this file is provided for the exclusive use of the
* licensees of Marvell.
* Such users have the right to use, modify, and incorporate this code into
* products for purposes authorized by the license agreement provided they
* include this notice and the associated copyright notice with any such
* product.
* The information in this file is provided "AS IS" without warranty.
*
******************************************************************************/
#include "sdmmc_api.h"
#include "Errors.h"
#include "PlatformConfig.h"
#include "sdhc2.h"
#include "SD.h"
#if SDIO_HOST
#include "sdio.h"
#endif
ADMA_DESCRIPTOR *admaDesc;
static SDMMC_Properties_T SDMMC_Prop;
static P_SDMMC_Properties_T pSDMMC_Prop = &SDMMC_Prop;
extern UINT_T MMCEraseAll;
/***********************************************************
* UINT_T SDMMC_SHUTDOWN()
* Description:
* Shutsdown and cleans up after the SDMMC device
* input:
* none
* output:
* All the needed hardware should be un-initialized.
* returns:
* WTPTP recognized errors
************************************************************/
UINT_T SDMMC_SHUTDOWN()
{
UINT_T Retval = NoError;
// Initialize Flash Properties
P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
// Is this even initialized?
if (pSDMMCP->State == UNINITIALIZED)
return Retval;
// Shutdown
pSDMMCP->Funcs.Shut_F();
// Restore MMC GPIO's to their default settings
DisableMMCSlots();
pSDMMCP->State = UNINITIALIZED;
return Retval;
}
/***********************************************************
* UINT_T InitializeSDMMCDevice (P_FlashProperties_T pFlashP, UINT8_T* P_DefaultPartitionNum)
* Description:
* Initializes the SDMMC port on the platform and all
* of the other necessary hardware needed for SDMMC
* reading, writing and erasing.
* input:
* none
* output:
* All the needed hardware should be initialized.
* returns:
* WTPTP recognized errors
************************************************************/
UINT_T InitializeSDMMCDevice(UINT8_T FlashNum, FlashBootType_T FlashBootType, UINT8_T* P_DefaultPartitionNum)
{
UINT_T switchReturn;
UINT_T baseAddress; // base address of the Host Controller and interface
UINT_T interruptMask; // the interrupt ID generated by the selected SDMMC Host Controller
UINT_T fusePartitionNumber;
P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
P_FlashProperties_T pFlashP = GetFlashProperties(FlashBootType);
CONTROLLER_TYPE controller;
XLLP_STATUS_T Status = NoError;
admaDesc = malloc(sizeof(ADMA_DESCRIPTOR) * NO_ADMA_TX_DESCS);
if(admaDesc == NULL) {
obm_printf("malloc ADMA descriptor failed\r\n");
return HeapExhaustedError;
}
// Setup pins and determine controller.
controller = ConfigureMMC(FlashNum, &baseAddress, &interruptMask, &fusePartitionNumber);
// Initialize Flash Properties
// Clean it out
memset (pSDMMCP, 0, sizeof(SDMMC_Prop));
pSDMMCP->ControllerType = controller;
//define functions
pFlashP->ReadFromFlash = &SDMMC_READ;
pFlashP->WriteToFlash = &SDMMC_WRITE;
pFlashP->EraseFlash = &SDMMC_ERASE;
pFlashP->FinalizeFlash = &SDMMC_SHUTDOWN;
pFlashP->TimFlashAddress = TIMOffset_SDMMC;
pFlashP->FlashType = SDMMC_FLASH;
pFlashP->ChangePartition = &SDMMC_SETPARTITION;
pFlashP->StagedInitRequired = FALSE;
pSDMMCP->pFlashP = pFlashP;
pSDMMCP->StrictErrorCheck = 0; // Relax error checking during card init. Not all cards are strictly compliant.
if (pSDMMCP->ControllerType == MMCNOTENABLED)
{
return SDMMCNotFound;
}
else
{
pSDMMCP->Funcs.Write_F = &MM4_WriteBlocks;
pSDMMCP->Funcs.Erase_F = &MM4_EraseBlocks;
pSDMMCP->Funcs.Shut_F = &MM4_CardShutdown;
pSDMMCP->Funcs.SwitchPartition_F = &MM4SwitchPartition;
pSDMMCP->Funcs.Init_F = &MM4_CardInit;
pSDMMCP->Funcs.Read_F = &MM4_ReadBlocks;
pFlashP->StreamingFlash = FALSE;
}
// Find a card in the desired controller
Status = pSDMMCP->Funcs.Init_F(baseAddress, interruptMask);
if (Status != NoError)
{
if (pSDMMCP->State == FAULT)
Status = (SDMMCGetCardErrorState(pSDMMCP));
SDMMC_SHUTDOWN();
return Status;
}
// Does this platform care what partition to boot from? If not allow default partition if it can't switch.
if (fusePartitionNumber == MMC_SD_USER_PARTITION)
{
*P_DefaultPartitionNum = MMC_SD_USER_PARTITION; // Default value
// try to set to the Boot partition
switchReturn = pSDMMCP->Funcs.SwitchPartition_F(MMC_SD_BOOT_PARTITION);
if (switchReturn == NoError)
*P_DefaultPartitionNum = MMC_SD_BOOT_PARTITION; // Return back Boot Partition
}
else // Must boot from selected partition or error.
{
switchReturn = pSDMMCP->Funcs.SwitchPartition_F(fusePartitionNumber);
if (switchReturn != NoError)
return SDMMC_SWITCH_ERROR;
else
*P_DefaultPartitionNum = fusePartitionNumber;
}
return Status;
}
/***********************************************************
* SDMMC_READ()
* Description:
* This function will read as many bytes as specified from FlashOffset to Local
* Buffer. The flash driver must have been previously initailized using
* InitializeSDMMCDriver. If the function encounters an error it will not
* re-attempt the operation.
* input:
* FlashOffset - The source address on the flash where data will come from
* specified as a byte value. Must be 32 bits aligned
* Local Buffer - Local address where data will be read in to.
* Size - Specifies number of bytes to read - 32 bits aligned
* output:
* Desired Values are read
* returns:
* WTPTP recognized errors
************************************************************/
UINT_T SDMMC_READ (UINT_T FlashOffset, UINT_T LocalBuffer, UINT_T Size)
{
UINT_T Retval = NoError;
UINT_T flags = NO_FLAGS;
int mod;
// Initialize Flash Properties
P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
P_MM4_SDMMC_CONTEXT_T pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
// Make sure State is correct
if (pSDMMCP->State != READY)
return SDMMCDeviceNotReadyError;
//The Boerne(SRAM) Switch supports up to 32-bytes burst size and the DDR up to 128-bytes burst size.
//The MMC supports burst size of 32, 64, 128, and 256-byte (configurable with 128-byte as default)
#if 0
if(!(LocalBuffer & DDR_PHY_ADDR))
{
pContext->pMMC4Reg->mm4_op_ctrl = (pContext->pMMC4Reg->mm4_op_ctrl & SD_DMA_BRST_SIZE_CLEAR_MASK);
}
#endif
//else
//{
// pContext->pMMC4Reg->mm4_op_ctrl = (pContext->pMMC4Reg->mm4_op_ctrl & SD_DMA_BRST_SIZE_CLEAR_MASK);
// pContext->pMMC4Reg->mm4_op_ctrl = (pContext->pMMC4Reg->mm4_op_ctrl | SD_DMA_128_BRST_SIZE_MASK);
//}
// this is a special case for second_gpt
if (FlashOffset == 0xffffffff)
{
FlashOffset = SDMMC_GetFlashLastRoom(Size);
if (FlashOffset == SGPT_ILLEGAL_LENGTH)
return SDMMC_SGPT_ILLEGAL_LENGTH;
}
if ( ((Size % 4) !=0) || ((LocalBuffer % 4) !=0))
return SDMMC_ADDR_MISALIGN_ERROR;
// Set up State
pSDMMCP->State = READ;
pSDMMCP->Trans.CardAddress = FlashOffset;
// Does the start/end addresses align on Block Boundries? Probably not, record discard bytes
pSDMMCP->Trans.StartDiscardWords = ((UINT64)FlashOffset * 512) % pSDMMCP->ReadBlockSize;
mod = ((UINT64)FlashOffset * 512 + Size) % pSDMMCP->ReadBlockSize;
if ( mod == 0)
pSDMMCP->Trans.EndDiscardWords = 0;
else
pSDMMCP->Trans.EndDiscardWords = pSDMMCP->ReadBlockSize - mod;
pSDMMCP->Trans.NumBlocks = (pSDMMCP->Trans.EndDiscardWords + pSDMMCP->Trans.StartDiscardWords + Size) / pSDMMCP->ReadBlockSize;
pSDMMCP->Trans.TransWordSize = (pSDMMCP->Trans.NumBlocks * pSDMMCP->ReadBlockSize) >> 2; // Total Transfer Size including pre and post bytes
// Convert to # of words
pSDMMCP->Trans.StartDiscardWords = (pSDMMCP->Trans.StartDiscardWords >> 2);
pSDMMCP->Trans.EndDiscardWords = (pSDMMCP->Trans.EndDiscardWords >> 2);
pSDMMCP->Trans.LocalAddr = LocalBuffer;
pSDMMCP->Trans.WordIndex = 0; // Stores Index of Current write position
Retval = pSDMMCP->Funcs.Read_F();
if (pSDMMCP->State == FAULT)
Retval = (SDMMCGetCardErrorState(pSDMMCP)); // TBD s/w reset?
pSDMMCP->State = READY;
return Retval;
}
/***********************************************************
* SDHC2_SDMMC_GetFlashLastRoom()
* input:
* Description:
* This function will get the last room in flash which is enough for second_gpt
* Inputs:
* None
* output:
* None
* returns:
* flash offset
************************************************************/
UINT_T SDMMC_GetFlashLastRoom(UINT_T Size)
{
// this is a special case for second_gpt
UINT_T capacity, offset;
P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
capacity = pSDMMCP->CardCapacity;
// size of second_gpt is 0x21 sectors
if (pSDMMCP->AccessMode == SECTOR_ACCESS)
{
offset = capacity - 0x22; // 0x21 sectors
}
else
{
offset = capacity - 0x22 * 512; // 0x21 sectors
}
if (Size != (0x22 * 512))
return SGPT_ILLEGAL_LENGTH;
return offset;
}
/***********************************************************
* SDMMC_WRITE()
* input:
* Description:
* This function will write as many bytes as specified from LocalBuffer to Flash
* Offset. The flash driver must have been previously initialized using
* InitializeSDMMCDriver. The relavent addresses must have been previously erased.
* If the function encounters an error it will not
* re-attempt the operation.
* Inputs:
* FlashOffset - The source address on the flash where data will be written to
* specified as a byte value. Must be 32 bits aligned
* LocalBuffer - Local address where data will be copied from.
* Size - Specifies number of bytes to write - 32 bits aligned
* output:
* Desired Values are written to flash
* returns:
* WTPTP recognized errors
************************************************************/
UINT_T SDMMC_WRITE (UINT_T FlashOffset, UINT_T LocalBuffer, UINT_T Size)
{
UINT_T Retval = NoError;
UINT_T flags = NO_FLAGS;
int mod;
// Initialize Flash Properties
P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
P_MM4_SDMMC_CONTEXT_T pContext = (P_MM4_SDMMC_CONTEXT_T) pSDMMCP->pContext;
// Make sure State is correct
if (pSDMMCP->State != READY)
return SDMMCDeviceNotReadyError;
//The Boerne(SRAM) Switch supports up to 32-bytes burst size and the DDR up to 128-bytes burst size.
//The MMC supports burst size of 32, 64, 128, and 256-byte (configurable with 128-byte as default)
#if 0
if(!(LocalBuffer & DDR_PHY_ADDR))
{
pContext->pMMC4Reg->mm4_op_ctrl = (pContext->pMMC4Reg->mm4_op_ctrl & SD_DMA_BRST_SIZE_CLEAR_MASK);
}
#endif
//else
//{
// pContext->pMMC4Reg->mm4_op_ctrl = (pContext->pMMC4Reg->mm4_op_ctrl & SD_DMA_BRST_SIZE_CLEAR_MASK);
// pContext->pMMC4Reg->mm4_op_ctrl = (pContext->pMMC4Reg->mm4_op_ctrl | SD_DMA_128_BRST_SIZE_MASK);
//}
// this is a special case for second_gpt
if (FlashOffset == 0xffffffff)
{
FlashOffset = SDMMC_GetFlashLastRoom(Size);
if (FlashOffset == SGPT_ILLEGAL_LENGTH)
return SDMMC_SGPT_ILLEGAL_LENGTH;
}
if ( ((Size % 4) !=0) || ((LocalBuffer % 4) !=0))
return SDMMC_ADDR_MISALIGN_ERROR;
// Set up State
pSDMMCP->State = WRITE;
pSDMMCP->Trans.CardAddress = FlashOffset;
// Does the start/end addresses align on Block Boundries? Probably not, record discard bytes
pSDMMCP->Trans.StartDiscardWords = ((UINT64)FlashOffset * 512) % pSDMMCP->WriteBlockSize;
mod = ((UINT64)FlashOffset * 512 + Size) % pSDMMCP->WriteBlockSize;
if (mod == 0)
pSDMMCP->Trans.EndDiscardWords = 0;
else
pSDMMCP->Trans.EndDiscardWords = pSDMMCP->WriteBlockSize - mod;
pSDMMCP->Trans.NumBlocks = (pSDMMCP->Trans.EndDiscardWords + pSDMMCP->Trans.StartDiscardWords + Size) / pSDMMCP->WriteBlockSize;
pSDMMCP->Trans.TransWordSize = (pSDMMCP->Trans.NumBlocks * pSDMMCP->WriteBlockSize) >> 2; // Total Transfer Size including pre and post bytes
// Convert to # of words
pSDMMCP->Trans.StartDiscardWords = (pSDMMCP->Trans.StartDiscardWords >> 2);
pSDMMCP->Trans.EndDiscardWords = (pSDMMCP->Trans.EndDiscardWords >> 2);
pSDMMCP->Trans.LocalAddr = LocalBuffer;
pSDMMCP->Trans.WordIndex = 0; // Stores Index of Current write position
// Kick off the Write
Retval = pSDMMCP->Funcs.Write_F();
if (pSDMMCP->State == FAULT)
Retval = (SDMMCGetCardErrorState(pSDMMCP)); // TBD s/w reset?
pSDMMCP->State = READY;
return Retval;
}
/***********************************************************
* SDMMC_ERASE()
* Description:
* This function will erase bytes that fall on erase group boundries. If the starting
* address and size do not fall on erase group boundries, they will be rounded up to do so.
* input:
* FlashOffset - The source address on the flash where data will begin to be erased
* Size - Specifies number of bytes to erase. Note that flash technology dictates
* flash be erased on erase group granularity
* output:
* Desired blocks are erased from flash
* returns:
* WTPTP recognized errors
************************************************************/
UINT_T SDMMC_ERASE (UINT_T FlashOffset, UINT_T Size)
{
UINT_T Retval = NoError;
// Initialize Flash Properties
P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
// Make sure State is correct
if (pSDMMCP->State != READY)
return SDMMCDeviceNotReadyError;
// Set the correct state
pSDMMCP->State = ERASE;
pSDMMCP->Trans.CardAddress = FlashOffset;
if (MMCEraseAll)
pSDMMCP->Trans.TransWordSize = (Size - 4) / 4; // sector address already
else
pSDMMCP->Trans.TransWordSize = (Size / 512 - 4) / 4; // use sector address as default
// Kick off the read
Retval = pSDMMCP->Funcs.Erase_F();
//send CMD13 to check the status of the card
if (pSDMMCP->State == FAULT)
Retval = (SDMMCGetCardErrorState(pSDMMCP)); // TBD s/w reset?
pSDMMCP->State = READY;
return Retval;
}
/***********************************************************
* SDMMC_SETPARTITION()
* Description:
* This function will call into the MMC device to change to the specified partition
* input:
* PartitionNum - Partition Number to set in the device
* output:
* none
* returns:
* WTPTP recognized errors
************************************************************/
UINT_T SDMMC_SETPARTITION (UINT_T PartitionNum)
{
UINT_T Retval = NoError;
// Initialize Flash Properties
P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
// Make sure State is correct
if (pSDMMCP->State != READY)
return SDMMCDeviceNotReadyError;
// If we can't switch partitions we continue don't flag an error
Retval = pSDMMCP->Funcs.SwitchPartition_F(PartitionNum);
if (pSDMMCP->State == FAULT)
Retval = (SDMMCGetCardErrorState(pSDMMCP)); // TBD s/w reset?
pSDMMCP->State = READY;
return Retval;
}
/***********************************************************************************
************************************************************************************
Below routines are not Application interface but common between driver variants
***********************************************************************************
************************************************************************************
****************************************************************
* GetSDMMCProperties
* Rerturn SDMMC Properties structure
* Input:
* none
* Output:
* none
* Returns:
* none
*****************************************************************/
P_SDMMC_Properties_T GetSDMMCProperties(void)
{
return pSDMMC_Prop;
}
/****************************************************************
* SetSDMMCProperties
* Set SDMMC Properties pointer
* Input:
* none
* Output:
* none
* Returns:
* none
*****************************************************************/
void SetSDMMCProperties(P_SDMMC_Properties_T pNewSDMMC_Prop)
{
pSDMMC_Prop = pNewSDMMC_Prop;
}
/****************************************************************
* SDMMC_ISR
* Interrupt Service Routine for SDMMC controller
* Provides switch control to appropriate controller's low level ISR
* Input:
* none
* Output:
* none
* Returns:
* none
*****************************************************************/
void SDMMC_ISR()
{
// Retreive SDMMC context
P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
MM4_ISR(pSDMMCP);
return;
}
/****************************************************************
* SDMMCGetCardErrorState
*
* Input:
* pSDMMCP - pointer to the current context
* Output:
* none
* Returns:
* Converts the error code read in from the card as R1 value in to
* a WTPTP recognized return value
*****************************************************************/
UINT_T SDMMCGetCardErrorState(P_SDMMC_Properties_T pSDMMCP)
{
UINT_T RetVal = SDMMC_GENERAL_ERROR;
obm_printf("pSDMMCP->CardReponse.R1_RESP: 0x%08x\n\r", pSDMMCP->CardReponse);
if ((pSDMMCP->CardReponse.R1_RESP & R1_SWITCH_ERROR) == R1_SWITCH_ERROR)
RetVal = SDMMC_SWITCH_ERROR;
else if ((pSDMMCP->CardReponse.R1_RESP & R1_ERASE_RESET_ERROR) == R1_ERASE_RESET_ERROR)
RetVal = SDMMC_ERASE_RESET_ERROR;
else if ((pSDMMCP->CardReponse.R1_RESP & R1_CIDCSD_OVERWRITE_ERROR) == R1_CIDCSD_OVERWRITE_ERROR)
RetVal = SDMMC_CIDCSD_OVERWRITE_ERROR;
else if ((pSDMMCP->CardReponse.R1_RESP & R1_CC_ERROR) == R1_CC_ERROR)
RetVal = SDMMC_CC_ERROR;
else if ((pSDMMCP->CardReponse.R1_RESP & R1_ECC_ERROR) == R1_ECC_ERROR)
RetVal = SDMMC_ECC_ERROR;
else if ((pSDMMCP->CardReponse.R1_RESP & R1_ILL_CMD_ERROR) == R1_ILL_CMD_ERROR)
RetVal = SDMMC_ILL_CMD_ERROR;
else if ((pSDMMCP->CardReponse.R1_RESP & R1_COM_CRC_ERROR) == R1_COM_CRC_ERROR)
RetVal = SDMMC_COM_CRC_ERROR;
else if ((pSDMMCP->CardReponse.R1_RESP & R1_LOCK_ULOCK_ERRROR) == R1_LOCK_ULOCK_ERRROR)
RetVal = SDMMC_LOCK_ULOCK_ERRROR;
else if ((pSDMMCP->CardReponse.R1_RESP & R1_LOCK_ERROR) == R1_LOCK_ERROR)
RetVal = SDMMC_LOCK_ERROR;
else if ((pSDMMCP->CardReponse.R1_RESP & R1_WP_ERROR) == R1_WP_ERROR)
RetVal = SDMMC_WP_ERROR;
else if ((pSDMMCP->CardReponse.R1_RESP & R1_ERASE_PARAM_ERROR) == R1_ERASE_PARAM_ERROR)
RetVal = SDMMC_ERASE_PARAM_ERROR;
else if ((pSDMMCP->CardReponse.R1_RESP & R1_ERASE_SEQ_ERROR) == R1_ERASE_SEQ_ERROR)
RetVal = SDMMC_ERASE_SEQ_ERROR;
else if ((pSDMMCP->CardReponse.R1_RESP & R1_BLK_LEN_ERROR) == R1_BLK_LEN_ERROR)
RetVal = SDMMC_BLK_LEN_ERROR;
else if ((pSDMMCP->CardReponse.R1_RESP & R1_ADDR_MISALIGN_ERROR) == R1_ADDR_MISALIGN_ERROR)
RetVal = SDMMC_ADDR_MISALIGN_ERROR;
else if ((pSDMMCP->CardReponse.R1_RESP & R1_ADDR_RANGE_ERROR) == R1_ADDR_RANGE_ERROR)
RetVal = SDMMC_ADDR_RANGE_ERROR;
if (RetVal == SDMMC_GENERAL_ERROR)
{
obm_printf("pSDMMCP->DeviceStatus: 0x%08x\n\r", pSDMMCP->DeviceStatus);
pSDMMCP->DeviceStatus = pSDMMCP->DeviceStatus >> 16;
if ((pSDMMCP->DeviceStatus & SD_ERROR_INT_STATUS_CMD_TIMEOUT_ERR) == SD_ERROR_INT_STATUS_CMD_TIMEOUT_ERR)
RetVal = SDH_CMD_TIMEOUT_ERR;
else if ((pSDMMCP->DeviceStatus & SD_ERROR_INT_STATUS_CMD_CRC_ERR) == SD_ERROR_INT_STATUS_CMD_CRC_ERR)
RetVal = SDH_CMD_CRC_ERR;
else if ((pSDMMCP->DeviceStatus & SD_ERROR_INT_STATUS_CMD_END_BIT_ERR) == SD_ERROR_INT_STATUS_CMD_END_BIT_ERR)
RetVal = SDH_CMD_END_BIT_ERR;
else if ((pSDMMCP->DeviceStatus & SD_ERROR_INT_STATUS_CMD_INDEX_ERR) == SD_ERROR_INT_STATUS_CMD_INDEX_ERR)
RetVal = SDH_CMD_INDEX_ERR;
else if ((pSDMMCP->DeviceStatus & SD_ERROR_INT_STATUS_DATA_TIMEOUT_ERR) == SD_ERROR_INT_STATUS_DATA_TIMEOUT_ERR)
RetVal = SDH_DATA_TIMEOUT_ERR;
else if ((pSDMMCP->DeviceStatus & SD_ERROR_INT_STATUS_RD_DATA_CRC_ERR) == SD_ERROR_INT_STATUS_RD_DATA_CRC_ERR)
RetVal = SDH_RD_DATA_CRC_ERR;
else if ((pSDMMCP->DeviceStatus & SD_ERROR_INT_STATUS_RD_DATA_END_BIT_ERR) == SD_ERROR_INT_STATUS_RD_DATA_END_BIT_ERR)
RetVal = SDH_RD_DATA_END_BIT_ERR;
else if ((pSDMMCP->DeviceStatus & SD_ERROR_INT_STATUS_AUTO_CMD12_ERR) == SD_ERROR_INT_STATUS_AUTO_CMD12_ERR)
RetVal = SDH_AUTO_CMD12_ERR;
else if ((pSDMMCP->DeviceStatus & SD_ERROR_INT_STATUS_ADMA_ERR) == SD_ERROR_INT_STATUS_ADMA_ERR)
RetVal = SDH_ADMA_ERR;
else if ((pSDMMCP->DeviceStatus & SD_ERROR_INT_STATUS_TUNE_ERR) == SD_ERROR_INT_STATUS_TUNE_ERR)
RetVal = SDH_TUNE_ERR;
else if ((pSDMMCP->DeviceStatus & SD_ERROR_INT_STATUS_SPI_ERR) == SD_ERROR_INT_STATUS_SPI_ERR)
RetVal = SDH_SPI_ERR;
else if ((pSDMMCP->DeviceStatus & SD_ERROR_INT_STATUS_AXI_RESP_ERR) == SD_ERROR_INT_STATUS_AXI_RESP_ERR)
RetVal = SDH_AXI_RESP_ERR;
else if ((pSDMMCP->DeviceStatus & SD_ERROR_INT_STATUS_CPL_TIMEOUT_ERR) == SD_ERROR_INT_STATUS_CPL_TIMEOUT_ERR)
RetVal = SDH_CPL_TIMEOUT_ERR;
else if ((pSDMMCP->DeviceStatus & SD_ERROR_INT_STATUS_CRC_STATUS_ERR) == SD_ERROR_INT_STATUS_CRC_STATUS_ERR)
RetVal = SDH_CRC_STATUS_ERR;
}
return RetVal;
}