From 2ed2ed29c27dc488dcfa602059847a168941e593 Mon Sep 17 00:00:00 2001 From: oliviermartin Date: Thu, 31 Mar 2011 11:20:15 +0000 Subject: [PATCH] ArmPkg/PL180MciDxe: Improve error handling Get more error handling using PL180 status registers. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11466 6f19259b-4bc3-4df7-8a09-765794883524 --- ArmPkg/Drivers/PL180MciDxe/PL180Mci.c | 720 +++++++++++++++----------- ArmPkg/Drivers/PL180MciDxe/PL180Mci.h | 4 +- 2 files changed, 435 insertions(+), 289 deletions(-) diff --git a/ArmPkg/Drivers/PL180MciDxe/PL180Mci.c b/ArmPkg/Drivers/PL180MciDxe/PL180Mci.c index fe6c904ff3..250ea8b54d 100644 --- a/ArmPkg/Drivers/PL180MciDxe/PL180Mci.c +++ b/ArmPkg/Drivers/PL180MciDxe/PL180Mci.c @@ -27,341 +27,485 @@ EFI_MMC_HOST_PROTOCOL *gpMmcHost; #define MMCI0_POW2_BLOCKLEN 9 #define MMCI0_TIMEOUT 1000 -BOOLEAN MciIsPowerOn() { - return ((MmioRead32(MCI_POWER_CONTROL_REG) & 0x3) == MCI_POWER_ON); +BOOLEAN +MciIsPowerOn ( + VOID + ) +{ + return ((MmioRead32(MCI_POWER_CONTROL_REG) & 0x3) == MCI_POWER_ON); } -EFI_STATUS MciInitialize() { - MCI_TRACE("MciInitialize()"); - return EFI_SUCCESS; +EFI_STATUS +MciInitialize ( + VOID + ) +{ + MCI_TRACE("MciInitialize()"); + return EFI_SUCCESS; } -BOOLEAN MciIsCardPresent() { - return (MmioRead32(FixedPcdGet32(PcdPL180SysMciRegAddress)) & 1); +BOOLEAN +MciIsCardPresent ( + VOID + ) +{ + return (MmioRead32(FixedPcdGet32(PcdPL180SysMciRegAddress)) & 1); } -BOOLEAN MciIsReadOnly() { - return (MmioRead32(FixedPcdGet32(PcdPL180SysMciRegAddress)) & 2); +BOOLEAN +MciIsReadOnly ( + VOID + ) +{ + return (MmioRead32(FixedPcdGet32(PcdPL180SysMciRegAddress)) & 2); } // Convert block size to 2^n -UINT32 GetPow2BlockLen(UINT32 BlockLen) { - UINTN Loop; - UINTN Pow2BlockLen; - - Loop = 0x8000; - Pow2BlockLen = 15; - do { - Loop = (Loop >> 1) & 0xFFFF; - Pow2BlockLen--; - } while (Pow2BlockLen && (!(Loop & BlockLen))); - - return Pow2BlockLen; +STATIC +UINT32 +GetPow2BlockLen ( + IN UINT32 BlockLen + ) +{ + UINTN Loop; + UINTN Pow2BlockLen; + + Loop = 0x8000; + Pow2BlockLen = 15; + do { + Loop = (Loop >> 1) & 0xFFFF; + Pow2BlockLen--; + } while (Pow2BlockLen && (!(Loop & BlockLen))); + + return Pow2BlockLen; } -VOID MciPrepareDataPath(UINTN TransferDirection) { - // Set Data Length & Data Timer - MmioWrite32(MCI_DATA_TIMER_REG,0xFFFFFFF); - MmioWrite32(MCI_DATA_LENGTH_REG,MMCI0_BLOCKLEN); +VOID +MciPrepareDataPath ( + IN UINTN TransferDirection + ) +{ + // Set Data Length & Data Timer + MmioWrite32(MCI_DATA_TIMER_REG,0xFFFFFFF); + MmioWrite32(MCI_DATA_LENGTH_REG,MMCI0_BLOCKLEN); #ifndef USE_STREAM - //Note: we are using a hardcoded BlockLen (=512). If we decide to use a variable size, we could - // compute the pow2 of BlockLen with the above function GetPow2BlockLen() - MmioWrite32(MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | TransferDirection | (MMCI0_POW2_BLOCKLEN << 4)); + //Note: we are using a hardcoded BlockLen (=512). If we decide to use a variable size, we could + // compute the pow2 of BlockLen with the above function GetPow2BlockLen() + MmioWrite32(MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_DMA_ENABLE | TransferDirection | (MMCI0_POW2_BLOCKLEN << 4)); #else - MmioWrite32(MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | TransferDirection | MCI_DATACTL_STREAM_TRANS); + MmioWrite32(MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_DMA_ENABLE | TransferDirection | MCI_DATACTL_STREAM_TRANS); #endif } -EFI_STATUS MciSendCommand(MMC_CMD MmcCmd, UINT32 Argument) { - UINT32 Status; - UINT32 Timer; - UINT32 Cmd; +EFI_STATUS +MciSendCommand ( + IN MMC_CMD MmcCmd, + IN UINT32 Argument + ) +{ + UINT32 Status; + UINT32 Cmd; + UINTN RetVal; + UINTN CmdCtrlReg; + + RetVal = EFI_SUCCESS; + + if ((MmcCmd == MMC_CMD17) || (MmcCmd == MMC_CMD11)) { + MciPrepareDataPath(MCI_DATACTL_CARD_TO_CONT); + } else if ((MmcCmd == MMC_CMD24) || (MmcCmd == MMC_CMD20)) { + MciPrepareDataPath(MCI_DATACTL_CONT_TO_CARD); + } + + // Create Command for PL180 + Cmd = INDX(MmcCmd); + if (MmcCmd & MMC_CMD_WAIT_RESPONSE) { + Cmd |= MCI_CPSM_WAIT_RESPONSE; + } + + if (MmcCmd & MMC_CMD_LONG_RESPONSE) { + Cmd |= MCI_CPSM_LONG_RESPONSE; + } - if ((MmcCmd == MMC_CMD17) || (MmcCmd == MMC_CMD11)) { - MciPrepareDataPath(MCI_DATACTL_CARD_TO_CONT); - } else if ((MmcCmd == MMC_CMD24) || (MmcCmd == MMC_CMD20)) { - MciPrepareDataPath(MCI_DATACTL_CONT_TO_CARD); + // Clear Status register static flags + MmioWrite32(MCI_CLEAR_STATUS_REG,0x7FF); + + //Write to command argument register + MmioWrite32(MCI_ARGUMENT_REG,Argument); + + //Write to command register + MmioWrite32(MCI_COMMAND_REG,Cmd); + + if (Cmd & MCI_CPSM_WAIT_RESPONSE) { + Status = MmioRead32(MCI_STATUS_REG); + while (!(Status & (MCI_STATUS_CMD_RESPEND | MCI_STATUS_CMD_CMDCRCFAIL | MCI_STATUS_CMD_CMDTIMEOUT | MCI_STATUS_CMD_START_BIT_ERROR))) { + Status = MmioRead32(MCI_STATUS_REG); } - // Create Command for PL180 - Cmd = INDX(MmcCmd); - if (MmcCmd & MMC_CMD_WAIT_RESPONSE) - Cmd |= MCI_CPSM_WAIT_RESPONSE; - if (MmcCmd & MMC_CMD_LONG_RESPONSE) - Cmd |= MCI_CPSM_LONG_RESPONSE; - - MmioWrite32(MCI_CLEAR_STATUS_REG,0x5FFF); - MmioWrite32(MCI_ARGUMENT_REG,Argument); - MmioWrite32(MCI_COMMAND_REG,Cmd); - - Timer = 1000; - if (Cmd & MCI_CPSM_WAIT_RESPONSE) { - Status = MmioRead32(MCI_STATUS_REG); - while (!(Status & (MCI_STATUS_CMD_RESPEND | MCI_STATUS_CMD_CMDCRCFAIL | MCI_STATUS_CMD_CMDTIMEOUT)) && Timer) { - //NanoSecondDelay(10); - Status = MmioRead32(MCI_STATUS_REG); - Timer--; - } - - if ((Timer == 0) || (Status == MCI_STATUS_CMD_CMDTIMEOUT)) { - //DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT! Response:0x%X Status:0x%X\n",Cmd & 0x3F,MmioRead32(MCI_RESPONSE0_REG),Status)); - return EFI_TIMEOUT; - } else if (!((Cmd & 0x3F) == INDX(1)) && (Status & MCI_STATUS_CMD_CMDCRCFAIL)) { - // The CMD1 does not contain CRC. We should ignore the CRC failed Status. - return EFI_CRC_ERROR; - } else { - return EFI_SUCCESS; - } + if ((Status & MCI_STATUS_CMD_START_BIT_ERROR)) { + DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) Start bit Error! Response:0x%X Status:0x%x\n",(Cmd & 0x3F),MmioRead32(MCI_RESPONSE0_REG),Status)); + RetVal = EFI_NO_RESPONSE; + goto Exit; + } else if ((Status & MCI_STATUS_CMD_CMDTIMEOUT)) { + //DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT! Response:0x%X Status:0x%x\n",(Cmd & 0x3F),MmioRead32(MCI_RESPONSE0_REG),Status)); + RetVal = EFI_TIMEOUT; + goto Exit; + } else if (!((Cmd & 0x3F) == INDX(1)) && (Status & MCI_STATUS_CMD_CMDCRCFAIL)) { + // The CMD1 does not contain CRC. We should ignore the CRC failed Status. + RetVal = EFI_CRC_ERROR; + goto Exit; } else { - Status = MmioRead32(MCI_STATUS_REG); - while (!(Status & MCI_STATUS_CMD_SENT) && Timer) { - //NanoSecondDelay(10); - Status = MmioRead32(MCI_STATUS_REG); - Timer--; - } - - if (Timer == 0) { - //DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT2! 0x%X\n",Cmd & 0x3F,MmioRead32(MCI_RESPONSE0_REG))); - return EFI_TIMEOUT; - } else { - return EFI_SUCCESS; - } + RetVal = EFI_SUCCESS; + goto Exit; } -} - -EFI_STATUS MciReceiveResponse(MMC_RESPONSE_TYPE Type, UINT32* Buffer) { - if (Buffer == NULL) { - return EFI_INVALID_PARAMETER; + } else { + Status = MmioRead32(MCI_STATUS_REG); + while (!(Status & (MCI_STATUS_CMD_SENT | MCI_STATUS_CMD_CMDCRCFAIL | MCI_STATUS_CMD_CMDTIMEOUT| MCI_STATUS_CMD_START_BIT_ERROR))) { + Status = MmioRead32(MCI_STATUS_REG); } - if ((Type == MMC_RESPONSE_TYPE_R1) || (Type == MMC_RESPONSE_TYPE_R1b) || - (Type == MMC_RESPONSE_TYPE_R3) || (Type == MMC_RESPONSE_TYPE_R6) || - (Type == MMC_RESPONSE_TYPE_R7)) { - Buffer[0] = MmioRead32(MCI_RESPONSE0_REG); - Buffer[1] = MmioRead32(MCI_RESPONSE1_REG); - } else if (Type == MMC_RESPONSE_TYPE_R2) { - Buffer[0] = MmioRead32(MCI_RESPONSE0_REG); - Buffer[1] = MmioRead32(MCI_RESPONSE1_REG); - Buffer[2] = MmioRead32(MCI_RESPONSE2_REG); - Buffer[3] = MmioRead32(MCI_RESPONSE3_REG); + if ((Status & MCI_STATUS_CMD_START_BIT_ERROR)) { + DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) Start bit Error! Response:0x%X Status:0x%x\n",(Cmd & 0x3F),MmioRead32(MCI_RESPONSE0_REG),Status)); + RetVal = EFI_NO_RESPONSE; + goto Exit; + } else if ((Status & MCI_STATUS_CMD_CMDTIMEOUT)) { + //DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT! Response:0x%X Status:0x%x\n",(Cmd & 0x3F),MmioRead32(MCI_RESPONSE0_REG),Status)); + RetVal = EFI_TIMEOUT; + goto Exit; + } else + if (!((Cmd & 0x3F) == INDX(1)) && (Status & MCI_STATUS_CMD_CMDCRCFAIL)) { + // The CMD1 does not contain CRC. We should ignore the CRC failed Status. + RetVal = EFI_CRC_ERROR; + goto Exit; + } else { + RetVal = EFI_SUCCESS; + goto Exit; } + } - return EFI_SUCCESS; -} - -EFI_STATUS MciReadBlockData(EFI_LBA Lba, UINTN Length, UINT32* Buffer) { - UINTN Loop; - UINTN Finish; - UINTN Timer; - UINTN Status; - - // Read data from the RX FIFO - Loop = 0; - Finish = MMCI0_BLOCKLEN / 4; - Timer = MMCI0_TIMEOUT * 10; - do { - // Read the Status flags - Status = MmioRead32(MCI_STATUS_REG); - // Do eight reads if possible else a single read - if (Status & MCI_STATUS_CMD_RXFIFOHALFFULL) { - Buffer[Loop] = MmioRead32(MCI_FIFO_REG); - Loop++; - Buffer[Loop] = MmioRead32(MCI_FIFO_REG); - Loop++; - Buffer[Loop] = MmioRead32(MCI_FIFO_REG); - Loop++; - Buffer[Loop] = MmioRead32(MCI_FIFO_REG); - Loop++; - Buffer[Loop] = MmioRead32(MCI_FIFO_REG); - Loop++; - Buffer[Loop] = MmioRead32(MCI_FIFO_REG); - Loop++; - Buffer[Loop] = MmioRead32(MCI_FIFO_REG); - Loop++; - Buffer[Loop] = MmioRead32(MCI_FIFO_REG); - Loop++; - } - else if (!(Status & MCI_STATUS_CMD_RXFIFOEMPTY)) { - Buffer[Loop] = MmioRead32(MCI_FIFO_REG); - Loop++; - } else - Timer--; - } while ((Loop < Finish) && Timer); - - if (Timer == 0) { - DEBUG ((EFI_D_ERROR, "MciReadBlockData: Timeout Status:0x%X Loop:%d // Finish:%d\n",MmioRead32(MCI_STATUS_REG),Loop,Finish)); - return EFI_TIMEOUT; - } else - return EFI_SUCCESS; +Exit: + //Disable Command Path + CmdCtrlReg = MmioRead32(MCI_COMMAND_REG); + MmioWrite32(MCI_COMMAND_REG, (CmdCtrlReg & ~MCI_CPSM_ENABLED)); + return RetVal; } -EFI_STATUS MciWriteBlockData(EFI_LBA Lba, UINTN Length, UINT32* Buffer) { - UINTN Loop; - UINTN Finish; - UINTN Timer; - UINTN Status; - - // Write the data to the TX FIFO - Loop = 0; - Finish = MMCI0_BLOCKLEN / 4; - Timer = MMCI0_TIMEOUT * 100; - do { - // Read the Status flags - Status = MmioRead32(MCI_STATUS_REG); - - // Do eight writes if possible else a single write - if (Status & MCI_STATUS_CMD_TXFIFOHALFEMPTY) { - MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); - Loop++; - MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); - Loop++; - MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); - Loop++; - MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); - Loop++; - MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); - Loop++; - MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); - Loop++; - MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); - Loop++; - MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); - Loop++; - } - else if (!(Status & MCI_STATUS_CMD_TXFIFOFULL)) { - MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); - Loop++; - } - else - Timer--; - } while ((Loop < Finish) && Timer); +EFI_STATUS +MciReceiveResponse ( + IN MMC_RESPONSE_TYPE Type, + IN UINT32* Buffer + ) +{ + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((Type == MMC_RESPONSE_TYPE_R1) || (Type == MMC_RESPONSE_TYPE_R1b) || + (Type == MMC_RESPONSE_TYPE_R3) || (Type == MMC_RESPONSE_TYPE_R6) || + (Type == MMC_RESPONSE_TYPE_R7)) + { + Buffer[0] = MmioRead32(MCI_RESPONSE0_REG); + Buffer[1] = MmioRead32(MCI_RESPONSE1_REG); + } else if (Type == MMC_RESPONSE_TYPE_R2) { + Buffer[0] = MmioRead32(MCI_RESPONSE0_REG); + Buffer[1] = MmioRead32(MCI_RESPONSE1_REG); + Buffer[2] = MmioRead32(MCI_RESPONSE2_REG); + Buffer[3] = MmioRead32(MCI_RESPONSE3_REG); + } - ASSERT(Timer > 0); + return EFI_SUCCESS; +} - // Wait for FIFO to drain - Timer = MMCI0_TIMEOUT; +EFI_STATUS +MciReadBlockData ( + IN EFI_LBA Lba, + IN UINTN Length, + IN UINT32* Buffer + ) +{ + UINTN Loop; + UINTN Finish; + UINTN Status; + EFI_STATUS RetVal; + UINTN DataCtrlReg; + + RetVal = EFI_SUCCESS; + + // Read data from the RX FIFO + Loop = 0; + Finish = MMCI0_BLOCKLEN / 4; + do { + // Read the Status flags Status = MmioRead32(MCI_STATUS_REG); -/*#ifndef USE_STREAM - // Single block - while (((Status & MCI_STATUS_CMD_TXDONE) != MCI_STATUS_CMD_TXDONE) && Timer) { -#else*/ - // Stream - while (((Status & MCI_STATUS_CMD_DATAEND) != MCI_STATUS_CMD_DATAEND) && Timer) { -//#endif - NanoSecondDelay(10); - Status = MmioRead32(MCI_STATUS_REG); - Timer--; + + // Do eight reads if possible else a single read + if (Status & MCI_STATUS_CMD_RXFIFOHALFFULL) { + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); + Loop++; + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); + Loop++; + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); + Loop++; + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); + Loop++; + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); + Loop++; + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); + Loop++; + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); + Loop++; + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); + Loop++; + } else if (Status & MCI_STATUS_CMD_RXDATAAVAILBL) { + Buffer[Loop] = MmioRead32(MCI_FIFO_REG); + Loop++; + } else { + //Check for error conditions and timeouts + if(Status & MCI_STATUS_CMD_DATATIMEOUT) { + DEBUG ((EFI_D_ERROR, "MciReadBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n",MmioRead32(MCI_RESPONSE0_REG),Status)); + RetVal = EFI_TIMEOUT; + break; + } else if(Status & MCI_STATUS_CMD_DATACRCFAIL) { + DEBUG ((EFI_D_ERROR, "MciReadBlockData(): CRC Error! Response:0x%X Status:0x%x\n",MmioRead32(MCI_RESPONSE0_REG),Status)); + RetVal = EFI_CRC_ERROR; + break; + } else if(Status & MCI_STATUS_CMD_START_BIT_ERROR) { + DEBUG ((EFI_D_ERROR, "MciReadBlockData(): Start-bit Error! Response:0x%X Status:0x%x\n",MmioRead32(MCI_RESPONSE0_REG),Status)); + RetVal = EFI_NO_RESPONSE; + break; + } } + //clear RX over run flag + if(Status & MCI_STATUS_CMD_RXOVERRUN) { + MmioWrite32(MCI_CLEAR_STATUS_REG, MCI_STATUS_CMD_RXOVERRUN); + } + } while ((Loop < Finish)); - ASSERT(Timer > 0); + //Clear Status flags + MmioWrite32(MCI_CLEAR_STATUS_REG, 0x7FF); + + //Disable Data path + DataCtrlReg = MmioRead32(MCI_DATA_CTL_REG); + MmioWrite32(MCI_DATA_CTL_REG, (DataCtrlReg & 0xFE)); - if (Timer == 0) - return EFI_TIMEOUT; - else - return EFI_SUCCESS; + return RetVal; } -EFI_STATUS MciNotifyState(MMC_STATE State) { - UINT32 Data32; +EFI_STATUS +MciWriteBlockData ( + IN EFI_LBA Lba, + IN UINTN Length, + IN UINT32* Buffer + ) +{ + UINTN Loop; + UINTN Finish; + UINTN Timer; + UINTN Status; + EFI_STATUS RetVal; + UINTN DataCtrlReg; + + RetVal = EFI_SUCCESS; + + // Write the data to the TX FIFO + Loop = 0; + Finish = MMCI0_BLOCKLEN / 4; + Timer = MMCI0_TIMEOUT * 100; + do { + // Read the Status flags + Status = MmioRead32(MCI_STATUS_REG); - switch(State) { - case MmcInvalidState: - ASSERT(0); - break; - case MmcHwInitializationState: - // If device already turn on then restart it - Data32 = MmioRead32(MCI_POWER_CONTROL_REG); - if ((Data32 & 0x2) == MCI_POWER_UP) { - MCI_TRACE("MciNotifyState(MmcHwInitializationState): TurnOff MCI"); - - // Turn off - MmioWrite32(MCI_CLOCK_CONTROL_REG, 0); - MmioWrite32(MCI_POWER_CONTROL_REG, 0); - MicroSecondDelay(100); - } - - MCI_TRACE("MciNotifyState(MmcHwInitializationState): TurnOn MCI"); - // Setup clock - // - 0x1D = 29 => should be the clock divider to be less than 400kHz at MCLK = 24Mhz - MmioWrite32(MCI_CLOCK_CONTROL_REG,0x1D | MCI_CLOCK_ENABLE | MCI_CLOCK_POWERSAVE); - //MmioWrite32(MCI_CLOCK_CONTROL_REG,0x1D | MCI_CLOCK_ENABLE); - - // Set the voltage - MmioWrite32(MCI_POWER_CONTROL_REG,MCI_POWER_OPENDRAIN | (15<<2)); - MmioWrite32(MCI_POWER_CONTROL_REG,MCI_POWER_ROD | MCI_POWER_OPENDRAIN | (15<<2) | MCI_POWER_UP); - MicroSecondDelay(10); - MmioWrite32(MCI_POWER_CONTROL_REG,MCI_POWER_ROD | MCI_POWER_OPENDRAIN | (15<<2) | MCI_POWER_ON); - MicroSecondDelay(100); - - // Set Data Length & Data Timer - MmioWrite32(MCI_DATA_TIMER_REG,0xFFFFF); - MmioWrite32(MCI_DATA_LENGTH_REG,8); - - ASSERT((MmioRead32(MCI_POWER_CONTROL_REG) & 0x3) == MCI_POWER_ON); - break; - case MmcIdleState: - MCI_TRACE("MciNotifyState(MmcIdleState)"); - break; - case MmcReadyState: - MCI_TRACE("MciNotifyState(MmcReadyState)"); - break; - case MmcIdentificationState: - MCI_TRACE("MciNotifyState(MmcIdentificationState)"); - break; - case MmcStandByState: - MCI_TRACE("MciNotifyState(MmcStandByState)"); - - // Enable MCICMD push-pull drive - MmioWrite32(MCI_POWER_CONTROL_REG,MCI_POWER_ROD | (15<<2) | MCI_POWER_ON); - - /*// Set MMCI0 clock to 4MHz (24MHz may be possible with cache enabled) - MmioWrite32(MCI_CLOCK_CONTROL_REG,0x02 | MCI_CLOCK_ENABLE | MCI_CLOCK_POWERSAVE);*/ - // Set MMCI0 clock to 24MHz (by bypassing the divider) - MmioWrite32(MCI_CLOCK_CONTROL_REG,MCI_CLOCK_BYPASS | MCI_CLOCK_ENABLE); - break; - case MmcTransferState: - //MCI_TRACE("MciNotifyState(MmcTransferState)"); - break; - case MmcSendingDataState: - MCI_TRACE("MciNotifyState(MmcSendingDataState)"); - break; - case MmcReceiveDataState: - MCI_TRACE("MciNotifyState(MmcReceiveDataState)"); - break; - case MmcProgrammingState: - MCI_TRACE("MciNotifyState(MmcProgrammingState)"); - break; - case MmcDisconnectState: - MCI_TRACE("MciNotifyState(MmcDisconnectState)"); - break; - default: + // Do eight writes if possible else a single write + if (Status & MCI_STATUS_CMD_TXFIFOHALFEMPTY) { + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + } else if ((Status & MCI_STATUS_CMD_TXFIFOEMPTY)) { + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + } else { + //Check for error conditions and timeouts + if(Status & MCI_STATUS_CMD_DATATIMEOUT) { + DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): TIMEOUT! Response:0x%X Status:0x%x\n",MmioRead32(MCI_RESPONSE0_REG),Status)); + RetVal = EFI_TIMEOUT; + goto Exit; + } else if(Status & MCI_STATUS_CMD_DATACRCFAIL) { + DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): CRC Error! Response:0x%X Status:0x%x\n",MmioRead32(MCI_RESPONSE0_REG),Status)); + RetVal = EFI_CRC_ERROR; + goto Exit; + } else if(Status & MCI_STATUS_CMD_TX_UNDERRUN) { + DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): TX buffer Underrun! Response:0x%X Status:0x%x, Number of bytes written 0x%x\n",MmioRead32(MCI_RESPONSE0_REG),Status, Loop)); + RetVal = EFI_BUFFER_TOO_SMALL; ASSERT(0); + goto Exit; + } } - return EFI_SUCCESS; + } while (Loop < Finish); + + // Wait for FIFO to drain + Timer = MMCI0_TIMEOUT * 60; + Status = MmioRead32(MCI_STATUS_REG); +#ifndef USE_STREAM + // Single block + while (((Status & MCI_STATUS_CMD_TXDONE) != MCI_STATUS_CMD_TXDONE) && Timer) { +#else + // Stream + while (((Status & MCI_STATUS_CMD_DATAEND) != MCI_STATUS_CMD_DATAEND) && Timer) { +#endif + NanoSecondDelay(10); + Status = MmioRead32(MCI_STATUS_REG); + Timer--; + } + + if(Timer == 0) { + DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): Data End timeout Number of bytes written 0x%x\n",Loop)); + ASSERT(Timer > 0); + return EFI_TIMEOUT; + } + + //Clear Status flags + MmioWrite32(MCI_CLEAR_STATUS_REG, 0x7FF); + if (Timer == 0) { + RetVal = EFI_TIMEOUT; + } + +Exit: + //Disable Data path + DataCtrlReg = MmioRead32(MCI_DATA_CTL_REG); + MmioWrite32(MCI_DATA_CTL_REG, (DataCtrlReg & 0xFE)); + return RetVal; +} + +EFI_STATUS +MciNotifyState ( + IN MMC_STATE State + ) +{ + UINT32 Data32; + + switch(State) { + case MmcInvalidState: + ASSERT(0); + break; + case MmcHwInitializationState: + // If device already turn on then restart it + Data32 = MmioRead32(MCI_POWER_CONTROL_REG); + if ((Data32 & 0x2) == MCI_POWER_UP) { + MCI_TRACE("MciNotifyState(MmcHwInitializationState): TurnOff MCI"); + + // Turn off + MmioWrite32(MCI_CLOCK_CONTROL_REG, 0); + MmioWrite32(MCI_POWER_CONTROL_REG, 0); + MicroSecondDelay(100); + } + + MCI_TRACE("MciNotifyState(MmcHwInitializationState): TurnOn MCI"); + // Setup clock + // - 0x1D = 29 => should be the clock divider to be less than 400kHz at MCLK = 24Mhz + MmioWrite32(MCI_CLOCK_CONTROL_REG,0x1D | MCI_CLOCK_ENABLE | MCI_CLOCK_POWERSAVE); + //MmioWrite32(MCI_CLOCK_CONTROL_REG,0x1D | MCI_CLOCK_ENABLE); + + // Set the voltage + MmioWrite32(MCI_POWER_CONTROL_REG,MCI_POWER_OPENDRAIN | (15<<2)); + MmioWrite32(MCI_POWER_CONTROL_REG,MCI_POWER_ROD | MCI_POWER_OPENDRAIN | (15<<2) | MCI_POWER_UP); + MicroSecondDelay(10); + MmioWrite32(MCI_POWER_CONTROL_REG,MCI_POWER_ROD | MCI_POWER_OPENDRAIN | (15<<2) | MCI_POWER_ON); + MicroSecondDelay(100); + + // Set Data Length & Data Timer + MmioWrite32(MCI_DATA_TIMER_REG,0xFFFFF); + MmioWrite32(MCI_DATA_LENGTH_REG,8); + + ASSERT((MmioRead32(MCI_POWER_CONTROL_REG) & 0x3) == MCI_POWER_ON); + break; + case MmcIdleState: + MCI_TRACE("MciNotifyState(MmcIdleState)"); + break; + case MmcReadyState: + MCI_TRACE("MciNotifyState(MmcReadyState)"); + break; + case MmcIdentificationState: + MCI_TRACE("MciNotifyState(MmcIdentificationState)"); + break; + case MmcStandByState:{ + volatile UINT32 PwrCtrlReg; + MCI_TRACE("MciNotifyState(MmcStandByState)"); + + // Enable MCICMD push-pull drive + PwrCtrlReg = MmioRead32(MCI_POWER_CONTROL_REG); + //Disable Open Drain output + PwrCtrlReg &=~(MCI_POWER_OPENDRAIN); + MmioWrite32(MCI_POWER_CONTROL_REG,PwrCtrlReg); + + // Set MMCI0 clock to 4MHz (24MHz may be possible with cache enabled) + // + // Note: Increasing clock speed causes TX FIFO under-run errors. + // So careful when optimising this driver for higher performance. + // + MmioWrite32(MCI_CLOCK_CONTROL_REG,0x02 | MCI_CLOCK_ENABLE | MCI_CLOCK_POWERSAVE); + // Set MMCI0 clock to 24MHz (by bypassing the divider) + //MmioWrite32(MCI_CLOCK_CONTROL_REG,MCI_CLOCK_BYPASS | MCI_CLOCK_ENABLE); + break; + } + case MmcTransferState: + //MCI_TRACE("MciNotifyState(MmcTransferState)"); + break; + case MmcSendingDataState: + MCI_TRACE("MciNotifyState(MmcSendingDataState)"); + break; + case MmcReceiveDataState: + MCI_TRACE("MciNotifyState(MmcReceiveDataState)"); + break; + case MmcProgrammingState: + MCI_TRACE("MciNotifyState(MmcProgrammingState)"); + break; + case MmcDisconnectState: + MCI_TRACE("MciNotifyState(MmcDisconnectState)"); + break; + default: + ASSERT(0); + } + return EFI_SUCCESS; } EFI_GUID mPL180MciDevicePathGuid = { 0x621b6fa5, 0x4dc1, 0x476f, 0xb9, 0xd8, 0x52, 0xc5, 0x57, 0xd8, 0x10, 0x70 }; -EFI_STATUS MciBuildDevicePath(EFI_DEVICE_PATH_PROTOCOL **DevicePath) { - EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode; +EFI_STATUS +MciBuildDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL **DevicePath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode; - NewDevicePathNode = CreateDeviceNode(HARDWARE_DEVICE_PATH,HW_VENDOR_DP,sizeof(VENDOR_DEVICE_PATH)); - CopyGuid(&((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid,&mPL180MciDevicePathGuid); - - *DevicePath = NewDevicePathNode; - return EFI_SUCCESS; + NewDevicePathNode = CreateDeviceNode(HARDWARE_DEVICE_PATH,HW_VENDOR_DP,sizeof(VENDOR_DEVICE_PATH)); + CopyGuid(&((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid,&mPL180MciDevicePathGuid); + + *DevicePath = NewDevicePathNode; + return EFI_SUCCESS; } EFI_MMC_HOST_PROTOCOL gMciHost = { - MciIsCardPresent, - MciIsReadOnly, - MciBuildDevicePath, - MciNotifyState, - MciSendCommand, - MciReceiveResponse, - MciReadBlockData, - MciWriteBlockData + MciIsCardPresent, + MciIsReadOnly, + MciBuildDevicePath, + MciNotifyState, + MciSendCommand, + MciReceiveResponse, + MciReadBlockData, + MciWriteBlockData }; EFI_STATUS diff --git a/ArmPkg/Drivers/PL180MciDxe/PL180Mci.h b/ArmPkg/Drivers/PL180MciDxe/PL180Mci.h index 2120716554..46c6700974 100644 --- a/ArmPkg/Drivers/PL180MciDxe/PL180Mci.h +++ b/ArmPkg/Drivers/PL180MciDxe/PL180Mci.h @@ -64,11 +64,13 @@ #define MCI_STATUS_CMD_DATACRCFAIL 0x2 #define MCI_STATUS_CMD_CMDTIMEOUT 0x4 #define MCI_STATUS_CMD_DATATIMEOUT 0x8 +#define MCI_STATUS_CMD_TX_UNDERRUN 0x10 #define MCI_STATUS_CMD_RXOVERRUN 0x20 #define MCI_STATUS_CMD_RESPEND 0x40 #define MCI_STATUS_CMD_SENT 0x80 #define MCI_STATUS_CMD_TXDONE (MCI_STATUS_CMD_DATAEND | MCI_STATUS_CMD_DATABLOCKEND) #define MCI_STATUS_CMD_DATAEND 0x000100 // Command Status - Data end +#define MCI_STATUS_CMD_START_BIT_ERROR 0x000200 #define MCI_STATUS_CMD_DATABLOCKEND 0x000400 // Command Status - Data end #define MCI_STATUS_CMD_ACTIVE 0x800 #define MCI_STATUS_CMD_RXACTIVE (1 << 13) @@ -86,7 +88,7 @@ #define MCI_DATACTL_CARD_TO_CONT 2 #define MCI_DATACTL_BLOCK_TRANS 0 #define MCI_DATACTL_STREAM_TRANS 4 -#define MCI_DATACTL_DMA_ENABLE 8 +#define MCI_DATACTL_DMA_ENABLE (1 << 3) #define INDX(CMD_INDX) ((CMD_INDX & 0x3F) | MCI_CPSM_ENABLED) -- 2.39.2