mirror of https://github.com/acidanthera/audk.git
678 lines
16 KiB
C
Executable File
678 lines
16 KiB
C
Executable File
/** @file
|
|
*
|
|
* Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
|
|
* Copyright (c) 2011, ARM Limited. All rights reserved.
|
|
*
|
|
* This program and the accompanying materials
|
|
* are licensed and made available under the terms and conditions of the BSD License
|
|
* which accompanies this distribution. The full text of the license may be found at
|
|
* http://opensource.org/licenses/bsd-license.php
|
|
*
|
|
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
*
|
|
**/
|
|
|
|
#include "MmcHostDxe.h"
|
|
|
|
EMBEDDED_EXTERNAL_DEVICE *gTPS65950;
|
|
UINT8 mMaxDataTransferRate = 0;
|
|
UINT32 mRca = 0;
|
|
BOOLEAN mBitModeSet = FALSE;
|
|
|
|
|
|
typedef struct {
|
|
VENDOR_DEVICE_PATH Mmc;
|
|
EFI_DEVICE_PATH End;
|
|
} MMCHS_DEVICE_PATH;
|
|
|
|
MMCHS_DEVICE_PATH gMMCDevicePath = {
|
|
{
|
|
HARDWARE_DEVICE_PATH,
|
|
HW_VENDOR_DP,
|
|
(UINT8)(sizeof(VENDOR_DEVICE_PATH)),
|
|
(UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8),
|
|
0xb615f1f5, 0x5088, 0x43cd, 0x80, 0x9c, 0xa1, 0x6e, 0x52, 0x48, 0x7d, 0x00
|
|
},
|
|
{
|
|
END_DEVICE_PATH_TYPE,
|
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
|
sizeof (EFI_DEVICE_PATH_PROTOCOL),
|
|
0
|
|
}
|
|
};
|
|
|
|
BOOLEAN
|
|
IgnoreCommand (
|
|
UINT32 Command
|
|
)
|
|
{
|
|
switch(Command) {
|
|
case MMC_CMD12:
|
|
return TRUE;
|
|
case MMC_CMD13:
|
|
return TRUE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
UINT32
|
|
TranslateCommand (
|
|
UINT32 Command
|
|
)
|
|
{
|
|
UINT32 Translation;
|
|
|
|
switch(Command) {
|
|
case MMC_CMD2:
|
|
Translation = CMD2;
|
|
break;
|
|
case MMC_CMD3:
|
|
Translation = CMD3;
|
|
break;
|
|
/*case MMC_CMD6:
|
|
Translation = CMD6;
|
|
break;*/
|
|
case MMC_CMD7:
|
|
Translation = CMD7;
|
|
break;
|
|
case MMC_CMD8:
|
|
Translation = CMD8;
|
|
break;
|
|
case MMC_CMD9:
|
|
Translation = CMD9;
|
|
break;
|
|
/*case MMC_CMD12:
|
|
Translation = CMD12;
|
|
break;
|
|
case MMC_CMD13:
|
|
Translation = CMD13;
|
|
break;*/
|
|
case MMC_CMD16:
|
|
Translation = CMD16;
|
|
break;
|
|
case MMC_CMD17:
|
|
Translation = 0x113A0014;//CMD17;
|
|
break;
|
|
case MMC_CMD24:
|
|
Translation = CMD24 | 4;
|
|
break;
|
|
case MMC_CMD55:
|
|
Translation = CMD55;
|
|
break;
|
|
case MMC_ACMD41:
|
|
Translation = ACMD41;
|
|
break;
|
|
default:
|
|
Translation = Command;
|
|
}
|
|
|
|
return Translation;
|
|
}
|
|
|
|
VOID
|
|
CalculateCardCLKD (
|
|
UINTN *ClockFrequencySelect
|
|
)
|
|
{
|
|
UINTN TransferRateValue = 0;
|
|
UINTN TimeValue = 0 ;
|
|
UINTN Frequency = 0;
|
|
|
|
DEBUG ((DEBUG_BLKIO, "CalculateCardCLKD()\n"));
|
|
|
|
// For SD Cards we would need to send CMD6 to set
|
|
// speeds abouve 25MHz. High Speed mode 50 MHz and up
|
|
|
|
// Calculate Transfer rate unit (Bits 2:0 of TRAN_SPEED)
|
|
switch (mMaxDataTransferRate & 0x7) { // 2
|
|
case 0:
|
|
TransferRateValue = 100 * 1000;
|
|
break;
|
|
|
|
case 1:
|
|
TransferRateValue = 1 * 1000 * 1000;
|
|
break;
|
|
|
|
case 2:
|
|
TransferRateValue = 10 * 1000 * 1000;
|
|
break;
|
|
|
|
case 3:
|
|
TransferRateValue = 100 * 1000 * 1000;
|
|
break;
|
|
|
|
default:
|
|
DEBUG ((DEBUG_BLKIO, "Invalid parameter.\n"));
|
|
ASSERT(FALSE);
|
|
return;
|
|
}
|
|
|
|
//Calculate Time value (Bits 6:3 of TRAN_SPEED)
|
|
switch ((mMaxDataTransferRate >> 3) & 0xF) { // 6
|
|
case 1:
|
|
TimeValue = 10;
|
|
break;
|
|
|
|
case 2:
|
|
TimeValue = 12;
|
|
break;
|
|
|
|
case 3:
|
|
TimeValue = 13;
|
|
break;
|
|
|
|
case 4:
|
|
TimeValue = 15;
|
|
break;
|
|
|
|
case 5:
|
|
TimeValue = 20;
|
|
break;
|
|
|
|
case 6:
|
|
TimeValue = 25;
|
|
break;
|
|
|
|
case 7:
|
|
TimeValue = 30;
|
|
break;
|
|
|
|
case 8:
|
|
TimeValue = 35;
|
|
break;
|
|
|
|
case 9:
|
|
TimeValue = 40;
|
|
break;
|
|
|
|
case 10:
|
|
TimeValue = 45;
|
|
break;
|
|
|
|
case 11:
|
|
TimeValue = 50;
|
|
break;
|
|
|
|
case 12:
|
|
TimeValue = 55;
|
|
break;
|
|
|
|
case 13:
|
|
TimeValue = 60;
|
|
break;
|
|
|
|
case 14:
|
|
TimeValue = 70;
|
|
break;
|
|
|
|
case 15:
|
|
TimeValue = 80;
|
|
break;
|
|
|
|
default:
|
|
DEBUG ((DEBUG_BLKIO, "Invalid parameter.\n"));
|
|
ASSERT(FALSE);
|
|
return;
|
|
}
|
|
|
|
Frequency = TransferRateValue * TimeValue/10;
|
|
|
|
// Calculate Clock divider value to program in MMCHS_SYSCTL[CLKD] field.
|
|
*ClockFrequencySelect = ((MMC_REFERENCE_CLK/Frequency) + 1);
|
|
|
|
DEBUG ((DEBUG_BLKIO, "mMaxDataTransferRate: 0x%x, Frequency: %d KHz, ClockFrequencySelect: %x\n", mMaxDataTransferRate, Frequency/1000, *ClockFrequencySelect));
|
|
}
|
|
|
|
VOID
|
|
UpdateMMCHSClkFrequency (
|
|
UINTN NewCLKD
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_BLKIO, "UpdateMMCHSClkFrequency()\n"));
|
|
|
|
// Set Clock enable to 0x0 to not provide the clock to the card
|
|
MmioAnd32 (MMCHS_SYSCTL, ~CEN);
|
|
|
|
// Set new clock frequency.
|
|
MmioAndThenOr32 (MMCHS_SYSCTL, ~CLKD_MASK, NewCLKD << 6);
|
|
|
|
// Poll till Internal Clock Stable
|
|
while ((MmioRead32 (MMCHS_SYSCTL) & ICS_MASK) != ICS);
|
|
|
|
// Set Clock enable to 0x1 to provide the clock to the card
|
|
MmioOr32 (MMCHS_SYSCTL, CEN);
|
|
}
|
|
|
|
EFI_STATUS
|
|
InitializeMMCHS (
|
|
VOID
|
|
)
|
|
{
|
|
UINT8 Data;
|
|
EFI_STATUS Status;
|
|
|
|
DEBUG ((DEBUG_BLKIO, "InitializeMMCHS()\n"));
|
|
|
|
// Select Device group to belong to P1 device group in Power IC.
|
|
Data = DEV_GRP_P1;
|
|
Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEV_GRP), 1, &Data);
|
|
ASSERT_EFI_ERROR(Status);
|
|
|
|
// Configure voltage regulator for MMC1 in Power IC to output 3.0 voltage.
|
|
Data = VSEL_3_00V;
|
|
Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEDICATED_REG), 1, &Data);
|
|
ASSERT_EFI_ERROR(Status);
|
|
|
|
// After ramping up voltage, set VDDS stable bit to indicate that voltage level is stable.
|
|
MmioOr32 (CONTROL_PBIAS_LITE, (PBIASLITEVMODE0 | PBIASLITEPWRDNZ0 | PBIASSPEEDCTRL0 | PBIASLITEVMODE1 | PBIASLITEWRDNZ1));
|
|
|
|
// Enable WP GPIO
|
|
MmioAndThenOr32 (GPIO1_BASE + GPIO_OE, ~BIT23, BIT23);
|
|
|
|
// Enable Card Detect
|
|
Data = CARD_DETECT_ENABLE;
|
|
gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, TPS65950_GPIO_CTRL), 1, &Data);
|
|
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
MMCIsCardPresent (
|
|
IN EFI_MMC_HOST_PROTOCOL *This
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 Data;
|
|
|
|
//
|
|
// Card detect is a GPIO0 on the TPS65950
|
|
//
|
|
Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, GPIODATAIN1), 1, &Data);
|
|
if (EFI_ERROR (Status)) {
|
|
return FALSE;
|
|
}
|
|
|
|
return !(Data & CARD_DETECT_BIT);
|
|
}
|
|
|
|
BOOLEAN
|
|
MMCIsReadOnly (
|
|
IN EFI_MMC_HOST_PROTOCOL *This
|
|
)
|
|
{
|
|
/* Note:
|
|
* On our BeagleBoard the SD card WP pin is always read as TRUE.
|
|
* Probably something wrong with GPIO configuration.
|
|
* BeagleBoard-xM uses microSD cards so there is no write protect at all.
|
|
* Hence commenting out SD card WP pin read status.
|
|
*/
|
|
//return (MmioRead32 (GPIO1_BASE + GPIO_DATAIN) & BIT23) == BIT23;
|
|
return 0;
|
|
|
|
}
|
|
|
|
// TODO
|
|
EFI_GUID mPL180MciDevicePathGuid = EFI_CALLER_ID_GUID;
|
|
|
|
EFI_STATUS
|
|
MMCBuildDevicePath (
|
|
IN EFI_MMC_HOST_PROTOCOL *This,
|
|
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;
|
|
}
|
|
|
|
EFI_STATUS
|
|
MMCSendCommand (
|
|
IN EFI_MMC_HOST_PROTOCOL *This,
|
|
IN MMC_CMD MmcCmd,
|
|
IN UINT32 Argument
|
|
)
|
|
{
|
|
UINTN MmcStatus;
|
|
UINTN RetryCount = 0;
|
|
|
|
if (IgnoreCommand(MmcCmd))
|
|
return EFI_SUCCESS;
|
|
|
|
MmcCmd = TranslateCommand(MmcCmd);
|
|
|
|
//DEBUG ((EFI_D_ERROR, "MMCSendCommand(%d)\n", MmcCmd));
|
|
|
|
// Check if command line is in use or not. Poll till command line is available.
|
|
while ((MmioRead32 (MMCHS_PSTATE) & DATI_MASK) == DATI_NOT_ALLOWED);
|
|
|
|
// Provide the block size.
|
|
MmioWrite32 (MMCHS_BLK, BLEN_512BYTES);
|
|
|
|
// Setting Data timeout counter value to max value.
|
|
MmioAndThenOr32 (MMCHS_SYSCTL, ~DTO_MASK, DTO_VAL);
|
|
|
|
// Clear Status register.
|
|
MmioWrite32 (MMCHS_STAT, 0xFFFFFFFF);
|
|
|
|
// Set command argument register
|
|
MmioWrite32 (MMCHS_ARG, Argument);
|
|
|
|
//TODO: fix this
|
|
//Enable interrupt enable events to occur
|
|
//MmioWrite32 (MMCHS_IE, CmdInterruptEnableVal);
|
|
|
|
// Send a command
|
|
MmioWrite32 (MMCHS_CMD, MmcCmd);
|
|
|
|
// Check for the command status.
|
|
while (RetryCount < MAX_RETRY_COUNT) {
|
|
do {
|
|
MmcStatus = MmioRead32 (MMCHS_STAT);
|
|
} while (MmcStatus == 0);
|
|
|
|
// Read status of command response
|
|
if ((MmcStatus & ERRI) != 0) {
|
|
|
|
// Perform soft-reset for mmci_cmd line.
|
|
MmioOr32 (MMCHS_SYSCTL, SRC);
|
|
while ((MmioRead32 (MMCHS_SYSCTL) & SRC));
|
|
|
|
//DEBUG ((EFI_D_INFO, "MmcStatus: 0x%x\n", MmcStatus));
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
// Check if command is completed.
|
|
if ((MmcStatus & CC) == CC) {
|
|
MmioWrite32 (MMCHS_STAT, CC);
|
|
break;
|
|
}
|
|
|
|
RetryCount++;
|
|
}
|
|
|
|
if (RetryCount == MAX_RETRY_COUNT) {
|
|
DEBUG ((DEBUG_BLKIO, "MMCSendCommand: Timeout\n"));
|
|
return EFI_TIMEOUT;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
MMCNotifyState (
|
|
IN EFI_MMC_HOST_PROTOCOL *This,
|
|
IN MMC_STATE State
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN FreqSel;
|
|
|
|
switch(State) {
|
|
case MmcInvalidState:
|
|
ASSERT(0);
|
|
break;
|
|
case MmcHwInitializationState:
|
|
mBitModeSet = FALSE;
|
|
|
|
DEBUG ((DEBUG_BLKIO, "MMCHwInitializationState()\n"));
|
|
Status = InitializeMMCHS ();
|
|
if (EFI_ERROR(Status)) {
|
|
DEBUG ((DEBUG_BLKIO, "Initialize MMC host controller fails. Status: %x\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
// Software reset of the MMCHS host controller.
|
|
MmioWrite32 (MMCHS_SYSCONFIG, SOFTRESET);
|
|
gBS->Stall(1000);
|
|
while ((MmioRead32 (MMCHS_SYSSTATUS) & RESETDONE_MASK) != RESETDONE);
|
|
|
|
// Soft reset for all.
|
|
MmioWrite32 (MMCHS_SYSCTL, SRA);
|
|
gBS->Stall(1000);
|
|
while ((MmioRead32 (MMCHS_SYSCTL) & SRA) != 0x0);
|
|
|
|
//Voltage capabilities initialization. Activate VS18 and VS30.
|
|
MmioOr32 (MMCHS_CAPA, (VS30 | VS18));
|
|
|
|
// Wakeup configuration
|
|
MmioOr32 (MMCHS_SYSCONFIG, ENAWAKEUP);
|
|
MmioOr32 (MMCHS_HCTL, IWE);
|
|
|
|
// MMCHS Controller default initialization
|
|
MmioOr32 (MMCHS_CON, (OD | DW8_1_4_BIT | CEATA_OFF));
|
|
|
|
MmioWrite32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_OFF));
|
|
|
|
// Enable internal clock
|
|
MmioOr32 (MMCHS_SYSCTL, ICE);
|
|
|
|
// Set the clock frequency to 80KHz.
|
|
UpdateMMCHSClkFrequency (CLKD_80KHZ);
|
|
|
|
// Enable SD bus power.
|
|
MmioOr32 (MMCHS_HCTL, (SDBP_ON));
|
|
|
|
// Poll till SD bus power bit is set.
|
|
while ((MmioRead32 (MMCHS_HCTL) & SDBP_MASK) != SDBP_ON);
|
|
|
|
// Enable interrupts.
|
|
MmioWrite32 (MMCHS_IE, (BADA_EN | CERR_EN | DEB_EN | DCRC_EN | DTO_EN | CIE_EN |
|
|
CEB_EN | CCRC_EN | CTO_EN | BRR_EN | BWR_EN | TC_EN | CC_EN));
|
|
|
|
// Controller INIT procedure start.
|
|
MmioOr32 (MMCHS_CON, INIT);
|
|
MmioWrite32 (MMCHS_CMD, 0x00000000);
|
|
while (!(MmioRead32 (MMCHS_STAT) & CC));
|
|
|
|
// Wait for 1 ms
|
|
gBS->Stall (1000);
|
|
|
|
// Set CC bit to 0x1 to clear the flag
|
|
MmioOr32 (MMCHS_STAT, CC);
|
|
|
|
// Retry INIT procedure.
|
|
MmioWrite32 (MMCHS_CMD, 0x00000000);
|
|
while (!(MmioRead32 (MMCHS_STAT) & CC));
|
|
|
|
// End initialization sequence
|
|
MmioAnd32 (MMCHS_CON, ~INIT);
|
|
|
|
MmioOr32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_ON));
|
|
|
|
// Change clock frequency to 400KHz to fit protocol
|
|
UpdateMMCHSClkFrequency(CLKD_400KHZ);
|
|
|
|
MmioOr32 (MMCHS_CON, OD);
|
|
break;
|
|
case MmcIdleState:
|
|
break;
|
|
case MmcReadyState:
|
|
break;
|
|
case MmcIdentificationState:
|
|
break;
|
|
case MmcStandByState:
|
|
CalculateCardCLKD (&FreqSel);
|
|
UpdateMMCHSClkFrequency (FreqSel);
|
|
break;
|
|
case MmcTransferState:
|
|
if (!mBitModeSet) {
|
|
Status = MMCSendCommand (This, CMD55, mRca << 16);
|
|
if (!EFI_ERROR (Status)) {
|
|
// Set device into 4-bit data bus mode
|
|
Status = MMCSendCommand (This, ACMD6, 0x2);
|
|
if (!EFI_ERROR (Status)) {
|
|
// Set host controler into 4-bit mode
|
|
MmioOr32 (MMCHS_HCTL, DTW_4_BIT);
|
|
DEBUG ((DEBUG_BLKIO, "SD Memory Card set to 4-bit mode\n"));
|
|
mBitModeSet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case MmcSendingDataState:
|
|
break;
|
|
case MmcReceiveDataState:
|
|
break;
|
|
case MmcProgrammingState:
|
|
break;
|
|
case MmcDisconnectState:
|
|
default:
|
|
ASSERT(0);
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
MMCReceiveResponse (
|
|
IN EFI_MMC_HOST_PROTOCOL *This,
|
|
IN MMC_RESPONSE_TYPE Type,
|
|
IN UINT32* Buffer
|
|
)
|
|
{
|
|
if (Buffer == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Type == MMC_RESPONSE_TYPE_R2) {
|
|
Buffer[0] = MmioRead32 (MMCHS_RSP10);
|
|
Buffer[1] = MmioRead32 (MMCHS_RSP32);
|
|
Buffer[2] = MmioRead32 (MMCHS_RSP54);
|
|
Buffer[3] = MmioRead32 (MMCHS_RSP76);
|
|
} else {
|
|
Buffer[0] = MmioRead32 (MMCHS_RSP10);
|
|
}
|
|
|
|
if (Type == MMC_RESPONSE_TYPE_CSD) {
|
|
mMaxDataTransferRate = Buffer[3] & 0xFF;
|
|
} else if (Type == MMC_RESPONSE_TYPE_RCA) {
|
|
mRca = Buffer[0] >> 16;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
MMCReadBlockData (
|
|
IN EFI_MMC_HOST_PROTOCOL *This,
|
|
IN EFI_LBA Lba,
|
|
IN UINTN Length,
|
|
IN UINT32* Buffer
|
|
)
|
|
{
|
|
UINTN MmcStatus;
|
|
UINTN Count;
|
|
UINTN RetryCount = 0;
|
|
|
|
DEBUG ((DEBUG_BLKIO, "MMCReadBlockData(LBA: 0x%x, Length: 0x%x, Buffer: 0x%x)\n", Lba, Length, Buffer));
|
|
|
|
// Check controller status to make sure there is no error.
|
|
while (RetryCount < MAX_RETRY_COUNT) {
|
|
do {
|
|
// Read Status.
|
|
MmcStatus = MmioRead32 (MMCHS_STAT);
|
|
} while(MmcStatus == 0);
|
|
|
|
// Check if Buffer read ready (BRR) bit is set?
|
|
if (MmcStatus & BRR) {
|
|
|
|
// Clear BRR bit
|
|
MmioOr32 (MMCHS_STAT, BRR);
|
|
|
|
for (Count = 0; Count < Length / 4; Count++) {
|
|
*Buffer++ = MmioRead32(MMCHS_DATA);
|
|
}
|
|
break;
|
|
}
|
|
RetryCount++;
|
|
}
|
|
|
|
if (RetryCount == MAX_RETRY_COUNT) {
|
|
return EFI_TIMEOUT;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
MMCWriteBlockData (
|
|
IN EFI_MMC_HOST_PROTOCOL *This,
|
|
IN EFI_LBA Lba,
|
|
IN UINTN Length,
|
|
IN UINT32* Buffer
|
|
)
|
|
{
|
|
UINTN MmcStatus;
|
|
UINTN Count;
|
|
UINTN RetryCount = 0;
|
|
|
|
// Check controller status to make sure there is no error.
|
|
while (RetryCount < MAX_RETRY_COUNT) {
|
|
do {
|
|
// Read Status.
|
|
MmcStatus = MmioRead32 (MMCHS_STAT);
|
|
} while(MmcStatus == 0);
|
|
|
|
// Check if Buffer write ready (BWR) bit is set?
|
|
if (MmcStatus & BWR) {
|
|
|
|
// Clear BWR bit
|
|
MmioOr32 (MMCHS_STAT, BWR);
|
|
|
|
// Write block worth of data.
|
|
for (Count = 0; Count < Length / 4; Count++) {
|
|
MmioWrite32 (MMCHS_DATA, *Buffer++);
|
|
}
|
|
|
|
break;
|
|
}
|
|
RetryCount++;
|
|
}
|
|
|
|
if (RetryCount == MAX_RETRY_COUNT) {
|
|
return EFI_TIMEOUT;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_MMC_HOST_PROTOCOL gMMCHost = {
|
|
MMC_HOST_PROTOCOL_REVISION,
|
|
MMCIsCardPresent,
|
|
MMCIsReadOnly,
|
|
MMCBuildDevicePath,
|
|
MMCNotifyState,
|
|
MMCSendCommand,
|
|
MMCReceiveResponse,
|
|
MMCReadBlockData,
|
|
MMCWriteBlockData
|
|
};
|
|
|
|
EFI_STATUS
|
|
MMCInitialize (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE Handle = NULL;
|
|
|
|
DEBUG ((DEBUG_BLKIO, "MMCInitialize()\n"));
|
|
|
|
Status = gBS->LocateProtocol (&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);
|
|
ASSERT_EFI_ERROR(Status);
|
|
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&Handle,
|
|
&gEfiMmcHostProtocolGuid, &gMMCHost,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return Status;
|
|
}
|