| /** @file | |
| This file implement the MMC Host Protocol for the ARM PrimeCell PL180. | |
| Copyright (c) 2011-2012, 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 "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 | |
| #define SYS_MCI_CARDIN BIT0 | |
| #define SYS_MCI_WPROT BIT1 | |
| BOOLEAN | |
| MciIsPowerOn ( | |
| VOID | |
| ) | |
| { | |
| return ((MmioRead32 (MCI_POWER_CONTROL_REG) & MCI_POWER_ON) == MCI_POWER_ON); | |
| } | |
| EFI_STATUS | |
| MciInitialize ( | |
| VOID | |
| ) | |
| { | |
| MCI_TRACE ("MciInitialize()"); | |
| return EFI_SUCCESS; | |
| } | |
| BOOLEAN | |
| MciIsCardPresent ( | |
| IN EFI_MMC_HOST_PROTOCOL *This | |
| ) | |
| { | |
| return (MmioRead32 (FixedPcdGet32 (PcdPL180SysMciRegAddress)) & SYS_MCI_CARDIN); | |
| } | |
| BOOLEAN | |
| MciIsReadOnly ( | |
| IN EFI_MMC_HOST_PROTOCOL *This | |
| ) | |
| { | |
| return (MmioRead32 (FixedPcdGet32 (PcdPL180SysMciRegAddress)) & SYS_MCI_WPROT); | |
| } | |
| #if 0 | |
| //Note: This function has been commented out because it is not used yet. | |
| // This function could be used to remove the hardcoded BlockLen used | |
| // in MciPrepareDataPath | |
| // 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; | |
| } | |
| #endif | |
| 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 | MCI_DATACTL_DMA_ENABLE | TransferDirection | (MMCI0_POW2_BLOCKLEN << 4)); | |
| #else | |
| MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_DMA_ENABLE | TransferDirection | MCI_DATACTL_STREAM_TRANS); | |
| #endif | |
| } | |
| EFI_STATUS | |
| MciSendCommand ( | |
| IN EFI_MMC_HOST_PROTOCOL *This, | |
| IN MMC_CMD MmcCmd, | |
| IN UINT32 Argument | |
| ) | |
| { | |
| UINT32 Status; | |
| UINT32 Cmd; | |
| UINTN RetVal; | |
| UINTN CmdCtrlReg; | |
| UINT32 DoneMask; | |
| 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 = (MMC_GET_INDX (MmcCmd) & INDX_MASK) | MCI_CPSM_ENABLE; | |
| 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 | |
| MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS); | |
| // Write to command argument register | |
| MmioWrite32 (MCI_ARGUMENT_REG, Argument); | |
| // Write to command register | |
| MmioWrite32 (MCI_COMMAND_REG, Cmd); | |
| DoneMask = (Cmd & MCI_CPSM_WAIT_RESPONSE) | |
| ? (MCI_STATUS_CMD_RESPEND | MCI_STATUS_CMD_ERROR) | |
| : (MCI_STATUS_CMD_SENT | MCI_STATUS_CMD_ERROR); | |
| do { | |
| Status = MmioRead32 (MCI_STATUS_REG); | |
| } while (! (Status & DoneMask)); | |
| if ((Status & MCI_STATUS_CMD_ERROR)) { | |
| // Clear Status register error flags | |
| MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_STATUS_CMD_ERROR); | |
| 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; | |
| } 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; | |
| } else if ((!(MmcCmd & MMC_CMD_NO_CRC_RESPONSE)) && (Status & MCI_STATUS_CMD_CMDCRCFAIL)) { | |
| // The CMD1 and response type R3 do not contain CRC. We should ignore the CRC failed Status. | |
| RetVal = EFI_CRC_ERROR; | |
| } | |
| } | |
| // Disable Command Path | |
| CmdCtrlReg = MmioRead32 (MCI_COMMAND_REG); | |
| MmioWrite32 (MCI_COMMAND_REG, (CmdCtrlReg & ~MCI_CPSM_ENABLE)); | |
| return RetVal; | |
| } | |
| EFI_STATUS | |
| MciReceiveResponse ( | |
| 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_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_RESPONSE3_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); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| MciReadBlockData ( | |
| IN EFI_MMC_HOST_PROTOCOL *This, | |
| IN EFI_LBA Lba, | |
| IN UINTN Length, | |
| IN UINT32* Buffer | |
| ) | |
| { | |
| UINTN Loop; | |
| UINTN Finish; | |
| UINTN Status; | |
| EFI_STATUS RetVal; | |
| UINTN DataCtrlReg; | |
| EFI_TPL Tpl; | |
| RetVal = EFI_SUCCESS; | |
| // Read data from the RX FIFO | |
| Loop = 0; | |
| Finish = MMCI0_BLOCKLEN / 4; | |
| // Raise the TPL at the highest level to disable Interrupts. | |
| Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); | |
| 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_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)); | |
| // Restore Tpl | |
| gBS->RestoreTPL (Tpl); | |
| // Clear Status flags | |
| MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS); | |
| //Disable Data path | |
| DataCtrlReg = MmioRead32 (MCI_DATA_CTL_REG); | |
| MmioWrite32 (MCI_DATA_CTL_REG, (DataCtrlReg & MCI_DATACTL_DISABLE_MASK)); | |
| return RetVal; | |
| } | |
| EFI_STATUS | |
| MciWriteBlockData ( | |
| IN EFI_MMC_HOST_PROTOCOL *This, | |
| IN EFI_LBA Lba, | |
| IN UINTN Length, | |
| IN UINT32* Buffer | |
| ) | |
| { | |
| UINTN Loop; | |
| UINTN Finish; | |
| UINTN Timer; | |
| UINTN Status; | |
| EFI_STATUS RetVal; | |
| UINTN DataCtrlReg; | |
| EFI_TPL Tpl; | |
| RetVal = EFI_SUCCESS; | |
| // Write the data to the TX FIFO | |
| Loop = 0; | |
| Finish = MMCI0_BLOCKLEN / 4; | |
| Timer = MMCI0_TIMEOUT * 100; | |
| // Raise the TPL at the highest level to disable Interrupts. | |
| Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); | |
| 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 { | |
| // 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; | |
| } | |
| } | |
| } while (Loop < Finish); | |
| // Restore Tpl | |
| gBS->RestoreTPL (Tpl); | |
| // Wait for FIFO to drain | |
| Timer = MMCI0_TIMEOUT * 60; | |
| Status = MmioRead32 (MCI_STATUS_REG); | |
| #ifndef USE_STREAM | |
| // Single block | |
| while (((Status & MCI_STATUS_TXDONE) != MCI_STATUS_TXDONE) && Timer) { | |
| #else | |
| // Stream | |
| while (((Status & MCI_STATUS_CMD_DATAEND) != MCI_STATUS_CMD_DATAEND) && Timer) { | |
| #endif | |
| NanoSecondDelay(10); | |
| Status = MmioRead32 (MCI_STATUS_REG); | |
| Timer--; | |
| } | |
| // Clear Status flags | |
| MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS); | |
| if (Timer == 0) { | |
| DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): Data End timeout Number of words written 0x%x\n", Loop)); | |
| RetVal = EFI_TIMEOUT; | |
| } | |
| Exit: | |
| // Disable Data path | |
| DataCtrlReg = MmioRead32 (MCI_DATA_CTL_REG); | |
| MmioWrite32 (MCI_DATA_CTL_REG, (DataCtrlReg & MCI_DATACTL_DISABLE_MASK)); | |
| return RetVal; | |
| } | |
| EFI_STATUS | |
| MciNotifyState ( | |
| IN EFI_MMC_HOST_PROTOCOL *This, | |
| 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); | |
| // 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 = EFI_CALLER_ID_GUID; | |
| EFI_STATUS | |
| MciBuildDevicePath ( | |
| 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_MMC_HOST_PROTOCOL gMciHost = { | |
| MMC_HOST_PROTOCOL_REVISION, | |
| MciIsCardPresent, | |
| MciIsReadOnly, | |
| MciBuildDevicePath, | |
| MciNotifyState, | |
| MciSendCommand, | |
| MciReceiveResponse, | |
| MciReadBlockData, | |
| MciWriteBlockData | |
| }; | |
| EFI_STATUS | |
| PL180MciDxeInitialize ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_HANDLE Handle; | |
| 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_PERIPH_ID_REG3) != MCI_PERIPH_ID3 || | |
| 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) { | |
| return EFI_NOT_FOUND; | |
| } | |
| Handle = NULL; | |
| MCI_TRACE ("PL180MciDxeInitialize()"); | |
| //Publish Component Name, BlockIO protocol interfaces | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &Handle, | |
| &gEfiMmcHostProtocolGuid, &gMciHost, | |
| NULL | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return EFI_SUCCESS; | |
| } |