2011-07-01 17:40:16 +02:00
/** @file
This file implement the MMC Host Protocol for the ARM PrimeCell PL180 .
2012-08-02 13:20:37 +02:00
Copyright ( c ) 2011 - 2012 , ARM Limited . All rights reserved .
2011-07-01 17:40:16 +02:00
2019-04-04 01:03:21 +02:00
SPDX - License - Identifier : BSD - 2 - Clause - Patent
2011-07-01 17:40:16 +02:00
* */
# include "PL180Mci.h"
# include <Library/DevicePathLib.h>
# include <Library/BaseMemoryLib.h>
EFI_MMC_HOST_PROTOCOL * gpMmcHost ;
// Untested ...
//#define USE_STREAM
# define MMCI0_BLOCKLEN 512
# define MMCI0_POW2_BLOCKLEN 9
# define MMCI0_TIMEOUT 1000
2012-08-02 13:20:37 +02:00
# define SYS_MCI_CARDIN BIT0
# define SYS_MCI_WPROT BIT1
2011-07-01 17:40:16 +02:00
BOOLEAN
MciIsPowerOn (
VOID
)
{
2012-08-02 13:20:37 +02:00
return ( ( MmioRead32 ( MCI_POWER_CONTROL_REG ) & MCI_POWER_ON ) = = MCI_POWER_ON ) ;
2011-07-01 17:40:16 +02:00
}
EFI_STATUS
MciInitialize (
VOID
)
{
2012-08-02 13:20:37 +02:00
MCI_TRACE ( " MciInitialize() " ) ;
2011-07-01 17:40:16 +02:00
return EFI_SUCCESS ;
}
BOOLEAN
MciIsCardPresent (
2011-09-01 19:08:41 +02:00
IN EFI_MMC_HOST_PROTOCOL * This
2011-07-01 17:40:16 +02:00
)
{
2012-08-02 13:20:37 +02:00
return ( MmioRead32 ( FixedPcdGet32 ( PcdPL180SysMciRegAddress ) ) & SYS_MCI_CARDIN ) ;
2011-07-01 17:40:16 +02:00
}
BOOLEAN
MciIsReadOnly (
2011-09-01 19:08:41 +02:00
IN EFI_MMC_HOST_PROTOCOL * This
2011-07-01 17:40:16 +02:00
)
{
2012-08-02 13:20:37 +02:00
return ( MmioRead32 ( FixedPcdGet32 ( PcdPL180SysMciRegAddress ) ) & SYS_MCI_WPROT ) ;
2011-07-01 17:40:16 +02:00
}
// Convert block size to 2^n
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 (
IN UINTN TransferDirection
)
{
// Set Data Length & Data Timer
2012-08-02 13:20:37 +02:00
MmioWrite32 ( MCI_DATA_TIMER_REG , 0xFFFFFFF ) ;
MmioWrite32 ( MCI_DATA_LENGTH_REG , MMCI0_BLOCKLEN ) ;
2011-07-01 17:40:16 +02:00
# ifndef USE_STREAM
2012-08-02 13:20:37 +02:00
//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 ) ) ;
2011-07-01 17:40:16 +02:00
# else
2011-09-01 19:08:41 +02:00
MmioWrite32 ( MCI_DATA_CTL_REG , MCI_DATACTL_ENABLE | MCI_DATACTL_DMA_ENABLE | TransferDirection | MCI_DATACTL_STREAM_TRANS ) ;
2011-07-01 17:40:16 +02:00
# endif
}
EFI_STATUS
MciSendCommand (
2011-09-01 19:08:41 +02:00
IN EFI_MMC_HOST_PROTOCOL * This ,
IN MMC_CMD MmcCmd ,
IN UINT32 Argument
2011-07-01 17:40:16 +02:00
)
{
2012-08-02 13:20:37 +02:00
UINT32 Status ;
UINT32 Cmd ;
UINTN RetVal ;
UINTN CmdCtrlReg ;
2012-08-02 16:25:17 +02:00
UINT32 DoneMask ;
2011-07-01 17:40:16 +02:00
RetVal = EFI_SUCCESS ;
if ( ( MmcCmd = = MMC_CMD17 ) | | ( MmcCmd = = MMC_CMD11 ) ) {
2012-08-02 13:20:37 +02:00
MciPrepareDataPath ( MCI_DATACTL_CARD_TO_CONT ) ;
2011-07-01 17:40:16 +02:00
} else if ( ( MmcCmd = = MMC_CMD24 ) | | ( MmcCmd = = MMC_CMD20 ) ) {
2012-08-02 13:20:37 +02:00
MciPrepareDataPath ( MCI_DATACTL_CONT_TO_CARD ) ;
2016-11-23 14:36:23 +01:00
} else if ( MmcCmd = = MMC_CMD6 ) {
MmioWrite32 ( MCI_DATA_TIMER_REG , 0xFFFFFFF ) ;
MmioWrite32 ( MCI_DATA_LENGTH_REG , 64 ) ;
# ifndef USE_STREAM
MmioWrite32 ( MCI_DATA_CTL_REG , MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | GetPow2BlockLen ( 64 ) ) ;
# else
MmioWrite32 ( MCI_DATA_CTL_REG , MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | MCI_DATACTL_STREAM_TRANS ) ;
# endif
} else if ( MmcCmd = = MMC_ACMD51 ) {
MmioWrite32 ( MCI_DATA_TIMER_REG , 0xFFFFFFF ) ;
/* SCR register is 8 bytes long. */
MmioWrite32 ( MCI_DATA_LENGTH_REG , 8 ) ;
# ifndef USE_STREAM
MmioWrite32 ( MCI_DATA_CTL_REG , MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | GetPow2BlockLen ( 8 ) ) ;
# else
MmioWrite32 ( MCI_DATA_CTL_REG , MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | MCI_DATACTL_STREAM_TRANS ) ;
# endif
2011-07-01 17:40:16 +02:00
}
// Create Command for PL180
2012-08-02 13:20:37 +02:00
Cmd = ( MMC_GET_INDX ( MmcCmd ) & INDX_MASK ) | MCI_CPSM_ENABLE ;
2011-07-01 17:40:16 +02:00
if ( MmcCmd & MMC_CMD_WAIT_RESPONSE ) {
Cmd | = MCI_CPSM_WAIT_RESPONSE ;
}
if ( MmcCmd & MMC_CMD_LONG_RESPONSE ) {
Cmd | = MCI_CPSM_LONG_RESPONSE ;
}
// Clear Status register static flags
2012-08-02 13:20:37 +02:00
MmioWrite32 ( MCI_CLEAR_STATUS_REG , MCI_CLR_ALL_STATUS ) ;
2011-07-01 17:40:16 +02:00
2012-08-02 13:20:37 +02:00
// Write to command argument register
MmioWrite32 ( MCI_ARGUMENT_REG , Argument ) ;
2011-07-01 17:40:16 +02:00
2012-08-02 13:20:37 +02:00
// Write to command register
MmioWrite32 ( MCI_COMMAND_REG , Cmd ) ;
2011-07-01 17:40:16 +02:00
2012-08-02 16:25:17 +02:00
DoneMask = ( Cmd & MCI_CPSM_WAIT_RESPONSE )
? ( MCI_STATUS_CMD_RESPEND | MCI_STATUS_CMD_ERROR )
: ( MCI_STATUS_CMD_SENT | MCI_STATUS_CMD_ERROR ) ;
do {
2012-08-02 13:20:37 +02:00
Status = MmioRead32 ( MCI_STATUS_REG ) ;
2012-08-02 16:25:17 +02:00
} while ( ! ( Status & DoneMask ) ) ;
2011-07-01 17:40:16 +02:00
2012-08-02 16:25:17 +02:00
if ( ( Status & MCI_STATUS_CMD_ERROR ) ) {
// Clear Status register error flags
MmioWrite32 ( MCI_CLEAR_STATUS_REG , MCI_STATUS_CMD_ERROR ) ;
2014-08-19 15:29:52 +02:00
2011-07-01 17:40:16 +02:00
if ( ( Status & MCI_STATUS_CMD_START_BIT_ERROR ) ) {
2012-08-02 13:20:37 +02:00
DEBUG ( ( EFI_D_ERROR , " MciSendCommand(CmdIndex:%d) Start bit Error! Response:0x%X Status:0x%x \n " , ( Cmd & 0x3F ) , MmioRead32 ( MCI_RESPONSE0_REG ) , Status ) ) ;
2011-07-01 17:40:16 +02:00
RetVal = EFI_NO_RESPONSE ;
} else if ( ( Status & MCI_STATUS_CMD_CMDTIMEOUT ) ) {
2012-08-02 13:20:37 +02:00
//DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT! Response:0x%X Status:0x%x\n", (Cmd & 0x3F), MmioRead32 (MCI_RESPONSE0_REG), Status));
2011-07-01 17:40:16 +02:00
RetVal = EFI_TIMEOUT ;
2012-08-02 16:25:17 +02:00
} else if ( ( ! ( MmcCmd & MMC_CMD_NO_CRC_RESPONSE ) ) & & ( Status & MCI_STATUS_CMD_CMDCRCFAIL ) ) {
2011-07-01 17:40:16 +02:00
// The CMD1 and response type R3 do not contain CRC. We should ignore the CRC failed Status.
RetVal = EFI_CRC_ERROR ;
}
}
2012-08-02 13:20:37 +02:00
// Disable Command Path
CmdCtrlReg = MmioRead32 ( MCI_COMMAND_REG ) ;
MmioWrite32 ( MCI_COMMAND_REG , ( CmdCtrlReg & ~ MCI_CPSM_ENABLE ) ) ;
return RetVal ;
2011-07-01 17:40:16 +02:00
}
EFI_STATUS
MciReceiveResponse (
2011-09-01 19:08:41 +02:00
IN EFI_MMC_HOST_PROTOCOL * This ,
IN MMC_RESPONSE_TYPE Type ,
IN UINT32 * Buffer
2011-07-01 17:40:16 +02:00
)
{
if ( Buffer = = NULL ) {
return EFI_INVALID_PARAMETER ;
}
2012-08-02 13:20:37 +02:00
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 ) )
2011-07-01 17:40:16 +02:00
{
2012-08-02 13:20:37 +02:00
Buffer [ 0 ] = MmioRead32 ( MCI_RESPONSE3_REG ) ;
2011-07-01 17:40:16 +02:00
} else if ( Type = = MMC_RESPONSE_TYPE_R2 ) {
2012-08-02 13:20:37 +02:00
Buffer [ 0 ] = MmioRead32 ( MCI_RESPONSE0_REG ) ;
Buffer [ 1 ] = MmioRead32 ( MCI_RESPONSE1_REG ) ;
Buffer [ 2 ] = MmioRead32 ( MCI_RESPONSE2_REG ) ;
Buffer [ 3 ] = MmioRead32 ( MCI_RESPONSE3_REG ) ;
2011-07-01 17:40:16 +02:00
}
return EFI_SUCCESS ;
}
EFI_STATUS
MciReadBlockData (
2011-09-01 19:08:41 +02:00
IN EFI_MMC_HOST_PROTOCOL * This ,
IN EFI_LBA Lba ,
IN UINTN Length ,
IN UINT32 * Buffer
2011-07-01 17:40:16 +02:00
)
{
UINTN Loop ;
UINTN Finish ;
UINTN Status ;
EFI_STATUS RetVal ;
UINTN DataCtrlReg ;
2013-08-06 14:11:13 +02:00
EFI_TPL Tpl ;
2011-07-01 17:40:16 +02:00
RetVal = EFI_SUCCESS ;
// Read data from the RX FIFO
Loop = 0 ;
2016-11-23 14:36:23 +01:00
if ( Length < MMCI0_BLOCKLEN ) {
Finish = Length / 4 ;
} else {
Finish = MMCI0_BLOCKLEN / 4 ;
}
2014-08-19 15:29:52 +02:00
2013-08-06 14:11:13 +02:00
// Raise the TPL at the highest level to disable Interrupts.
Tpl = gBS - > RaiseTPL ( TPL_HIGH_LEVEL ) ;
2011-07-01 17:40:16 +02:00
do {
// Read the Status flags
2012-08-02 13:20:37 +02:00
Status = MmioRead32 ( MCI_STATUS_REG ) ;
2011-07-01 17:40:16 +02:00
// 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
2012-08-02 13:20:37 +02:00
if ( Status & MCI_STATUS_CMD_DATATIMEOUT ) {
DEBUG ( ( EFI_D_ERROR , " MciReadBlockData(): TIMEOUT! Response:0x%X Status:0x%x \n " , MmioRead32 ( MCI_RESPONSE0_REG ) , Status ) ) ;
2011-07-01 17:40:16 +02:00
RetVal = EFI_TIMEOUT ;
break ;
2012-08-02 13:20:37 +02:00
} 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 ) ) ;
2011-07-01 17:40:16 +02:00
RetVal = EFI_CRC_ERROR ;
break ;
2012-08-02 13:20:37 +02:00
} 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 ) ) ;
2011-07-01 17:40:16 +02:00
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 ) ) ;
2013-08-06 14:11:13 +02:00
// Restore Tpl
gBS - > RestoreTPL ( Tpl ) ;
2012-08-02 13:20:37 +02:00
// Clear Status flags
MmioWrite32 ( MCI_CLEAR_STATUS_REG , MCI_CLR_ALL_STATUS ) ;
2011-07-01 17:40:16 +02:00
2012-08-02 13:20:37 +02:00
//Disable Data path
DataCtrlReg = MmioRead32 ( MCI_DATA_CTL_REG ) ;
MmioWrite32 ( MCI_DATA_CTL_REG , ( DataCtrlReg & MCI_DATACTL_DISABLE_MASK ) ) ;
2011-07-01 17:40:16 +02:00
2012-08-02 13:20:37 +02:00
return RetVal ;
2011-07-01 17:40:16 +02:00
}
EFI_STATUS
MciWriteBlockData (
2011-09-01 19:08:41 +02:00
IN EFI_MMC_HOST_PROTOCOL * This ,
IN EFI_LBA Lba ,
IN UINTN Length ,
IN UINT32 * Buffer
2011-07-01 17:40:16 +02:00
)
{
UINTN Loop ;
UINTN Finish ;
UINTN Timer ;
UINTN Status ;
EFI_STATUS RetVal ;
UINTN DataCtrlReg ;
2013-08-06 14:11:13 +02:00
EFI_TPL Tpl ;
2011-07-01 17:40:16 +02:00
RetVal = EFI_SUCCESS ;
// Write the data to the TX FIFO
Loop = 0 ;
Finish = MMCI0_BLOCKLEN / 4 ;
Timer = MMCI0_TIMEOUT * 100 ;
2013-08-06 14:11:13 +02:00
// Raise the TPL at the highest level to disable Interrupts.
Tpl = gBS - > RaiseTPL ( TPL_HIGH_LEVEL ) ;
2011-07-01 17:40:16 +02:00
do {
// Read the Status flags
2012-08-02 13:20:37 +02:00
Status = MmioRead32 ( MCI_STATUS_REG ) ;
2011-07-01 17:40:16 +02:00
// 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 + + ;
2013-10-21 13:06:51 +02:00
} else if ( ! ( Status & MCI_STATUS_CMD_TXFIFOFULL ) ) {
2011-07-01 17:40:16 +02:00
MmioWrite32 ( MCI_FIFO_REG , Buffer [ Loop ] ) ;
Loop + + ;
} else {
2012-08-02 13:20:37 +02:00
// 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 ) ) ;
2011-07-01 17:40:16 +02:00
RetVal = EFI_TIMEOUT ;
goto Exit ;
2012-08-02 13:20:37 +02:00
} 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 ) ) ;
2011-07-01 17:40:16 +02:00
RetVal = EFI_CRC_ERROR ;
goto Exit ;
2012-08-02 13:20:37 +02:00
} else if ( Status & MCI_STATUS_CMD_TX_UNDERRUN ) {
2011-07-01 17:40:16 +02:00
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 ;
}
}
} while ( Loop < Finish ) ;
2013-08-06 14:11:13 +02:00
// Restore Tpl
gBS - > RestoreTPL ( Tpl ) ;
2011-07-01 17:40:16 +02:00
// Wait for FIFO to drain
2012-08-02 13:20:37 +02:00
Timer = MMCI0_TIMEOUT * 60 ;
Status = MmioRead32 ( MCI_STATUS_REG ) ;
2011-07-01 17:40:16 +02:00
# ifndef USE_STREAM
// Single block
2012-08-02 13:20:37 +02:00
while ( ( ( Status & MCI_STATUS_TXDONE ) ! = MCI_STATUS_TXDONE ) & & Timer ) {
2011-07-01 17:40:16 +02:00
# else
// Stream
while ( ( ( Status & MCI_STATUS_CMD_DATAEND ) ! = MCI_STATUS_CMD_DATAEND ) & & Timer ) {
# endif
NanoSecondDelay ( 10 ) ;
2012-08-02 13:20:37 +02:00
Status = MmioRead32 ( MCI_STATUS_REG ) ;
2011-07-01 17:40:16 +02:00
Timer - - ;
}
2012-08-02 13:20:37 +02:00
// Clear Status flags
MmioWrite32 ( MCI_CLEAR_STATUS_REG , MCI_CLR_ALL_STATUS ) ;
2012-08-02 16:25:17 +02:00
2011-07-01 17:40:16 +02:00
if ( Timer = = 0 ) {
2012-08-02 16:25:17 +02:00
DEBUG ( ( EFI_D_ERROR , " MciWriteBlockData(): Data End timeout Number of words written 0x%x \n " , Loop ) ) ;
2011-07-01 17:40:16 +02:00
RetVal = EFI_TIMEOUT ;
}
Exit :
2012-08-02 13:20:37 +02:00
// Disable Data path
DataCtrlReg = MmioRead32 ( MCI_DATA_CTL_REG ) ;
MmioWrite32 ( MCI_DATA_CTL_REG , ( DataCtrlReg & MCI_DATACTL_DISABLE_MASK ) ) ;
return RetVal ;
2011-07-01 17:40:16 +02:00
}
EFI_STATUS
MciNotifyState (
2011-09-01 19:08:41 +02:00
IN EFI_MMC_HOST_PROTOCOL * This ,
IN MMC_STATE State
2011-07-01 17:40:16 +02:00
)
{
UINT32 Data32 ;
2012-08-02 13:20:37 +02:00
switch ( State ) {
2011-07-01 17:40:16 +02:00
case MmcInvalidState :
2012-08-02 13:20:37 +02:00
ASSERT ( 0 ) ;
2011-07-01 17:40:16 +02:00
break ;
case MmcHwInitializationState :
// If device already turn on then restart it
2012-08-02 13:20:37 +02:00
Data32 = MmioRead32 ( MCI_POWER_CONTROL_REG ) ;
2011-07-01 17:40:16 +02:00
if ( ( Data32 & 0x2 ) = = MCI_POWER_UP ) {
2012-08-02 13:20:37 +02:00
MCI_TRACE ( " MciNotifyState(MmcHwInitializationState): TurnOff MCI " ) ;
2011-07-01 17:40:16 +02:00
// Turn off
2012-08-02 13:20:37 +02:00
MmioWrite32 ( MCI_CLOCK_CONTROL_REG , 0 ) ;
MmioWrite32 ( MCI_POWER_CONTROL_REG , 0 ) ;
MicroSecondDelay ( 100 ) ;
2011-07-01 17:40:16 +02:00
}
2012-08-02 13:20:37 +02:00
MCI_TRACE ( " MciNotifyState(MmcHwInitializationState): TurnOn MCI " ) ;
2011-07-01 17:40:16 +02:00
// Setup clock
// - 0x1D = 29 => should be the clock divider to be less than 400kHz at MCLK = 24Mhz
2012-08-02 13:20:37 +02:00
MmioWrite32 ( MCI_CLOCK_CONTROL_REG , 0x1D | MCI_CLOCK_ENABLE | MCI_CLOCK_POWERSAVE ) ;
2011-07-01 17:40:16 +02:00
// Set the voltage
2012-08-02 13:20:37 +02:00
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 ) ;
2011-07-01 17:40:16 +02:00
// Set Data Length & Data Timer
2012-08-02 13:20:37 +02:00
MmioWrite32 ( MCI_DATA_TIMER_REG , 0xFFFFF ) ;
MmioWrite32 ( MCI_DATA_LENGTH_REG , 8 ) ;
2011-07-01 17:40:16 +02:00
2012-08-02 13:20:37 +02:00
ASSERT ( ( MmioRead32 ( MCI_POWER_CONTROL_REG ) & 0x3 ) = = MCI_POWER_ON ) ;
2011-07-01 17:40:16 +02:00
break ;
case MmcIdleState :
2012-08-02 13:20:37 +02:00
MCI_TRACE ( " MciNotifyState(MmcIdleState) " ) ;
2011-07-01 17:40:16 +02:00
break ;
case MmcReadyState :
2012-08-02 13:20:37 +02:00
MCI_TRACE ( " MciNotifyState(MmcReadyState) " ) ;
2011-07-01 17:40:16 +02:00
break ;
case MmcIdentificationState :
2012-08-02 13:20:37 +02:00
MCI_TRACE ( " MciNotifyState (MmcIdentificationState) " ) ;
2011-07-01 17:40:16 +02:00
break ;
case MmcStandByState : {
volatile UINT32 PwrCtrlReg ;
2012-08-02 13:20:37 +02:00
MCI_TRACE ( " MciNotifyState (MmcStandByState) " ) ;
2011-07-01 17:40:16 +02:00
// Enable MCICMD push-pull drive
2012-08-02 13:20:37 +02:00
PwrCtrlReg = MmioRead32 ( MCI_POWER_CONTROL_REG ) ;
2011-07-01 17:40:16 +02:00
//Disable Open Drain output
2012-08-02 13:20:37 +02:00
PwrCtrlReg & = ~ ( MCI_POWER_OPENDRAIN ) ;
MmioWrite32 ( MCI_POWER_CONTROL_REG , PwrCtrlReg ) ;
2011-07-01 17:40:16 +02:00
// 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 :
2012-08-02 13:20:37 +02:00
//MCI_TRACE ("MciNotifyState(MmcTransferState)");
2011-07-01 17:40:16 +02:00
break ;
case MmcSendingDataState :
2012-08-02 13:20:37 +02:00
MCI_TRACE ( " MciNotifyState(MmcSendingDataState) " ) ;
2011-07-01 17:40:16 +02:00
break ;
case MmcReceiveDataState :
2012-08-02 13:20:37 +02:00
MCI_TRACE ( " MciNotifyState(MmcReceiveDataState) " ) ;
2011-07-01 17:40:16 +02:00
break ;
case MmcProgrammingState :
2012-08-02 13:20:37 +02:00
MCI_TRACE ( " MciNotifyState(MmcProgrammingState) " ) ;
2011-07-01 17:40:16 +02:00
break ;
case MmcDisconnectState :
2012-08-02 13:20:37 +02:00
MCI_TRACE ( " MciNotifyState(MmcDisconnectState) " ) ;
2011-07-01 17:40:16 +02:00
break ;
default :
2012-08-02 13:20:37 +02:00
ASSERT ( 0 ) ;
2011-07-01 17:40:16 +02:00
}
return EFI_SUCCESS ;
}
EFI_GUID mPL180MciDevicePathGuid = EFI_CALLER_ID_GUID ;
EFI_STATUS
MciBuildDevicePath (
2011-09-01 19:08:41 +02:00
IN EFI_MMC_HOST_PROTOCOL * This ,
IN EFI_DEVICE_PATH_PROTOCOL * * DevicePath
2011-07-01 17:40:16 +02:00
)
{
EFI_DEVICE_PATH_PROTOCOL * NewDevicePathNode ;
2012-08-02 13:20:37 +02:00
NewDevicePathNode = CreateDeviceNode ( HARDWARE_DEVICE_PATH , HW_VENDOR_DP , sizeof ( VENDOR_DEVICE_PATH ) ) ;
CopyGuid ( & ( ( VENDOR_DEVICE_PATH * ) NewDevicePathNode ) - > Guid , & mPL180MciDevicePathGuid ) ;
2011-07-01 17:40:16 +02:00
* DevicePath = NewDevicePathNode ;
return EFI_SUCCESS ;
}
EFI_MMC_HOST_PROTOCOL gMciHost = {
2011-09-01 19:08:41 +02:00
MMC_HOST_PROTOCOL_REVISION ,
2011-07-01 17:40:16 +02:00
MciIsCardPresent ,
MciIsReadOnly ,
MciBuildDevicePath ,
MciNotifyState ,
MciSendCommand ,
MciReceiveResponse ,
MciReadBlockData ,
MciWriteBlockData
} ;
EFI_STATUS
PL180MciDxeInitialize (
IN EFI_HANDLE ImageHandle ,
IN EFI_SYSTEM_TABLE * SystemTable
)
{
EFI_STATUS Status ;
2012-08-02 13:20:37 +02:00
EFI_HANDLE Handle ;
2015-08-25 15:11:02 +02:00
DEBUG ( ( EFI_D_WARN , " Probing ID registers at 0x%lx for a PL180 \n " ,
MCI_PERIPH_ID_REG0 ) ) ;
// Check if this is a PL180
if ( MmioRead8 ( MCI_PERIPH_ID_REG0 ) ! = MCI_PERIPH_ID0 | |
MmioRead8 ( MCI_PERIPH_ID_REG1 ) ! = MCI_PERIPH_ID1 | |
MmioRead8 ( MCI_PERIPH_ID_REG2 ) ! = MCI_PERIPH_ID2 | |
MmioRead8 ( MCI_PCELL_ID_REG0 ) ! = MCI_PCELL_ID0 | |
MmioRead8 ( MCI_PCELL_ID_REG1 ) ! = MCI_PCELL_ID1 | |
MmioRead8 ( MCI_PCELL_ID_REG2 ) ! = MCI_PCELL_ID2 | |
MmioRead8 ( MCI_PCELL_ID_REG3 ) ! = MCI_PCELL_ID3 ) {
2016-03-01 09:20:40 +01:00
DEBUG ( ( EFI_D_WARN , " Probing ID registers at 0x%lx for a PL180 "
" failed \n " , MCI_PERIPH_ID_REG0 ) ) ;
2015-08-25 15:11:02 +02:00
return EFI_NOT_FOUND ;
}
2012-08-02 13:20:37 +02:00
Handle = NULL ;
2011-07-01 17:40:16 +02:00
2012-08-02 13:20:37 +02:00
MCI_TRACE ( " PL180MciDxeInitialize() " ) ;
2011-07-01 17:40:16 +02:00
//Publish Component Name, BlockIO protocol interfaces
Status = gBS - > InstallMultipleProtocolInterfaces (
2014-08-19 15:29:52 +02:00
& Handle ,
2011-07-01 17:40:16 +02:00
& gEfiMmcHostProtocolGuid , & gMciHost ,
NULL
) ;
ASSERT_EFI_ERROR ( Status ) ;
return EFI_SUCCESS ;
}