| /****************************************************************************** |
| * |
| * (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; |
| } |
| |