/** @file This file implement the MMC Host Protocol for the DesignWare eMMC. WARNING: This driver fails to follow the UEFI driver model without a good reason, and only remains in the tree because it is still used by a small number of platforms. It will be removed when no longer used. Copyright (c) 2014-2017, Linaro Limited. All rights reserved. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_DWEMMC #define PcdDwDxeBaseAddress ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress)) #elif CONFIG_DWSDMMC #define PcdDwDxeBaseAddress ((UINT32)PcdGet32 (PcdDwSdDxeBaseAddress)) #endif #include "DwEmmc.h" #define DWEMMC_DESC_PAGE 1 #define DWEMMC_BLOCK_SIZE 512 #define DWEMMC_DMA_BUF_SIZE (512 * 8) #define DWEMMC_MAX_DESC_PAGES 512 /* Internal IDMAC interrupt defines */ #define DWMCI_IDINTEN_RI (1 << 1) #define DWMCI_IDINTEN_TI (1 << 0) #define DWMCI_IDINTEN_MASK (DWMCI_IDINTEN_TI | \ DWMCI_IDINTEN_RI) #define DWMCI_DMA_EN (1 << 5) typedef struct { UINT32 Des0; UINT32 Des1; UINT32 Des2; UINT32 Des3; } DWEMMC_IDMAC_DESCRIPTOR; EFI_MMC_HOST_PROTOCOL *gpMmcHost; DWEMMC_IDMAC_DESCRIPTOR *gpIdmacDesc; EFI_GUID mDwEmmcDevicePathGuid = EFI_CALLER_ID_GUID; STATIC UINT32 mDwEmmcCommand; STATIC UINT32 mDwEmmcArgument; STATIC UINT32 app_cmd = 0; EFI_STATUS DwEmmcReadBlockData ( IN EFI_MMC_HOST_PROTOCOL *This, IN EFI_LBA Lba, IN UINTN Length, IN UINT32* Buffer ); BOOLEAN DwEmmcIsPowerOn ( VOID ) { return TRUE; } EFI_STATUS DwEmmcInitialize ( VOID ) { DEBUG ((DEBUG_BLKIO, "DwEmmcInitialize()")); return EFI_SUCCESS; } BOOLEAN DwEmmcIsCardPresent ( IN EFI_MMC_HOST_PROTOCOL *This ) { return TRUE; } BOOLEAN DwEmmcIsReadOnly ( IN EFI_MMC_HOST_PROTOCOL *This ) { return FALSE; } BOOLEAN DwEmmcIsDmaSupported ( IN EFI_MMC_HOST_PROTOCOL *This ) { return TRUE; } void mmc_debug_printf() { //UINT32 data, data1, UINT32 addr = 0x16020000; //data = MmioRead32(0x13020170); //data1 = MmioRead32(0x13020178); //DEBUG ((DEBUG_INFO, "\nCLK 0 0x%x clk 1 0x%x\n", data, data1)); for (; addr <= 0x16020098; addr+=4) { if ((addr & 0xf) == 0x0) { DEBUG ((DEBUG_INFO,"\naddr 0x%08x:", addr)); } DEBUG ((DEBUG_INFO, " %08x", MmioRead32(addr))); } DEBUG ((DEBUG_INFO, "\n")); } EFI_STATUS DwEmmcBuildDevicePath ( 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, &mDwEmmcDevicePathGuid); *DevicePath = NewDevicePathNode; return EFI_SUCCESS; } EFI_STATUS DwEmmcUpdateClock ( VOID ) { UINT32 Data; /* CMD_UPDATE_CLK */ Data = BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_UPDATE_CLOCK_ONLY | BIT_CMD_START; MmioWrite32 (DWEMMC_CMD, Data); while (1) { Data = MmioRead32 (DWEMMC_CMD); if (!(Data & CMD_START_BIT)) { break; } Data = MmioRead32 (DWEMMC_RINTSTS); if (Data & DWEMMC_INT_HLE) { Print (L"failed to update mmc clock frequency\n"); return EFI_DEVICE_ERROR; } } return EFI_SUCCESS; } EFI_STATUS DwEmmcSetClock ( IN UINTN ClockFreq ) { UINT32 Divider, Rate, Data; EFI_STATUS Status; BOOLEAN Found = FALSE; for (Divider = 1; Divider < 256; Divider++) { Rate = PcdGet32 (PcdDwEmmcDxeClockFrequencyInHz); if ((Rate / (2 * Divider)) <= ClockFreq) { Found = TRUE; break; } } if (Found == FALSE) { return EFI_NOT_FOUND; } // Wait until MMC is idle do { Data = MmioRead32 (DWEMMC_STATUS); } while (Data & DWEMMC_STS_DATA_BUSY); // Disable MMC clock first MmioWrite32 (DWEMMC_CLKENA, 0); Status = DwEmmcUpdateClock (); ASSERT (!EFI_ERROR (Status)); MmioWrite32 (DWEMMC_CLKDIV, Divider); Status = DwEmmcUpdateClock (); ASSERT (!EFI_ERROR (Status)); // Enable MMC clock MmioWrite32 (DWEMMC_CLKENA, 1); MmioWrite32 (DWEMMC_CLKSRC, 0); Status = DwEmmcUpdateClock (); ASSERT (!EFI_ERROR (Status)); return EFI_SUCCESS; } EFI_STATUS DwEmmcNotifyState ( IN EFI_MMC_HOST_PROTOCOL *This, IN MMC_STATE State ) { UINT32 Data; EFI_STATUS Status; switch (State) { case MmcInvalidState: return EFI_INVALID_PARAMETER; case MmcHwInitializationState: MmioWrite32 (DWEMMC_PWREN, 1); // If device already turn on then restart it Data = DWEMMC_CTRL_RESET_ALL; MmioWrite32 (DWEMMC_CTRL, Data); do { // Wait until reset operation finished Data = MmioRead32 (DWEMMC_CTRL); } while (Data & DWEMMC_CTRL_RESET_ALL); // Setup clock that could not be higher than 400KHz. Status = DwEmmcSetClock (400000); ASSERT (!EFI_ERROR (Status)); // Wait clock stable MicroSecondDelay (100); MmioWrite32 (DWEMMC_CTYPE, 0); MmioWrite32 (DWEMMC_RINTSTS, ~0); MmioWrite32 (DWEMMC_INTMASK, 0); MmioWrite32 (DWEMMC_TMOUT, ~0); MmioWrite32 (DWEMMC_IDINTEN, 0); MmioWrite32 (DWEMMC_BMOD, DWEMMC_IDMAC_SWRESET); MmioWrite32 (DWEMMC_BLKSIZ, DWEMMC_BLOCK_SIZE); do { Data = MmioRead32 (DWEMMC_BMOD); } while (Data & DWEMMC_IDMAC_SWRESET); MmioWrite32 (DWEMMC_IDINTEN, 0x3); break; case MmcIdleState: break; case MmcReadyState: break; case MmcIdentificationState: break; case MmcStandByState: break; case MmcTransferState: break; case MmcSendingDataState: break; case MmcReceiveDataState: break; case MmcProgrammingState: break; case MmcDisconnectState: break; default: return EFI_INVALID_PARAMETER; } return EFI_SUCCESS; } // Need to prepare DMA buffer first before sending commands to MMC card BOOLEAN IsPendingReadCommand ( IN MMC_CMD MmcCmd ) { UINTN Mask; Mask = BIT_CMD_DATA_EXPECTED | BIT_CMD_READ; if ((MmcCmd & Mask) == Mask) { return TRUE; } return FALSE; } BOOLEAN IsPendingWriteCommand ( IN MMC_CMD MmcCmd ) { UINTN Mask; Mask = BIT_CMD_DATA_EXPECTED | BIT_CMD_WRITE; if ((MmcCmd & Mask) == Mask) { return TRUE; } return FALSE; } EFI_STATUS SendCommand ( IN MMC_CMD MmcCmd, IN UINT32 Argument ) { UINT32 Data, ErrMask; // Wait until MMC is idle do { Data = MmioRead32 (DWEMMC_STATUS); } while (Data & DWEMMC_STS_DATA_BUSY); MmioWrite32 (DWEMMC_RINTSTS, ~0); MmioWrite32 (DWEMMC_CMDARG, Argument); MmioWrite32 (DWEMMC_CMD, MmcCmd); //DEBUG ((DEBUG_INFO, "send cmd %d arg %x\n", MmcCmd & 0x3f, Argument)); ErrMask = DWEMMC_INT_EBE | DWEMMC_INT_HLE | DWEMMC_INT_RTO | DWEMMC_INT_RCRC | DWEMMC_INT_RE; ErrMask |= DWEMMC_INT_DCRC | DWEMMC_INT_DRT | DWEMMC_INT_SBE; do { MicroSecondDelay(500); Data = MmioRead32 (DWEMMC_RINTSTS); if (Data & ErrMask) { return EFI_DEVICE_ERROR; } if (Data & DWEMMC_INT_DTO) { // Transfer Done break; } } while (!(Data & DWEMMC_INT_CMD_DONE)); return EFI_SUCCESS; } EFI_STATUS DwEmmcSendCommand ( IN EFI_MMC_HOST_PROTOCOL *This, IN MMC_CMD MmcCmd, IN UINT32 Argument ) { UINT32 Cmd = 0; EFI_STATUS Status = EFI_SUCCESS; switch (MMC_GET_INDX(MmcCmd)) { case MMC_INDX(0): Cmd = BIT_CMD_SEND_INIT; break; case MMC_INDX(1): Cmd = BIT_CMD_RESPONSE_EXPECT; break; case MMC_INDX(2): Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_LONG_RESPONSE | BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_SEND_INIT; break; case MMC_INDX(3): Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_SEND_INIT; break; case MMC_INDX(7): if (Argument) Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC; else Cmd = 0; break; case MMC_INDX(8): if (Argument) /* sd */ Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_WAIT_PRVDATA_COMPLETE; else /* emmc */ Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_DATA_EXPECTED | BIT_CMD_READ | BIT_CMD_WAIT_PRVDATA_COMPLETE; break; case MMC_INDX(9): Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_LONG_RESPONSE; break; case MMC_INDX(12): Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_STOP_ABORT_CMD; break; case MMC_INDX(13): Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_WAIT_PRVDATA_COMPLETE; break; case MMC_INDX(16): Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | /* BIT_CMD_DATA_EXPECTED | BIT_CMD_READ | */ BIT_CMD_WAIT_PRVDATA_COMPLETE; break; case MMC_INDX(6): /* sd */ if (MmcCmd & (1 << 31)) Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_DATA_EXPECTED | BIT_CMD_READ | BIT_CMD_WAIT_PRVDATA_COMPLETE; else Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC; break; case MMC_INDX(17): case MMC_INDX(18): Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_DATA_EXPECTED | BIT_CMD_READ | BIT_CMD_WAIT_PRVDATA_COMPLETE; break; case MMC_INDX(24): case MMC_INDX(25): Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_DATA_EXPECTED | BIT_CMD_WRITE | BIT_CMD_WAIT_PRVDATA_COMPLETE; break; case MMC_INDX(30): Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_DATA_EXPECTED; break; default: Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC; break; } if (app_cmd) { switch (MMC_GET_INDX(MmcCmd)) { case MMC_INDX(41): Cmd = BIT_CMD_RESPONSE_EXPECT; break; case MMC_INDX(51): Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_DATA_EXPECTED | BIT_CMD_READ | BIT_CMD_WAIT_PRVDATA_COMPLETE; break; case MMC_INDX(6): Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC; break; default: break; } } Cmd |= MMC_GET_INDX(MmcCmd) | BIT_CMD_USE_HOLD_REG | BIT_CMD_START; if (IsPendingReadCommand (Cmd) || IsPendingWriteCommand (Cmd)) { mDwEmmcCommand = Cmd; mDwEmmcArgument = Argument; } else { Status = SendCommand (Cmd, Argument); } if ((Status == EFI_SUCCESS) && ((MmcCmd & 0x3f) == 55)) app_cmd = 1; else app_cmd = 0; return Status; } EFI_STATUS DwEmmcReceiveResponse ( 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 (DWEMMC_RESP0); } else if (Type == MMC_RESPONSE_TYPE_R2) { Buffer[0] = MmioRead32 (DWEMMC_RESP0); Buffer[1] = MmioRead32 (DWEMMC_RESP1); Buffer[2] = MmioRead32 (DWEMMC_RESP2); Buffer[3] = MmioRead32 (DWEMMC_RESP3); } return EFI_SUCCESS; } VOID DwEmmcAdjustFifoThreshold ( VOID ) { /* DMA multiple transaction size map to reg value as array index */ CONST UINT32 BurstSize[] = {1, 4, 8, 16, 32, 64, 128, 256}; UINT32 BlkDepthInFifo, FifoThreshold, FifoWidth, FifoDepth; UINT32 BlkSize = DWEMMC_BLOCK_SIZE, Idx = 0, RxWatermark = 1, TxWatermark, TxWatermarkInvers; /* Skip FIFO adjustment if we do not have platform FIFO depth info */ FifoDepth = PcdGet32 (PcdDwEmmcDxeFifoDepth); if (!FifoDepth) { return; } TxWatermark = FifoDepth / 2; TxWatermarkInvers = FifoDepth - TxWatermark; FifoWidth = DWEMMC_GET_HDATA_WIDTH (MmioRead32 (DWEMMC_HCON)); if (!FifoWidth) { FifoWidth = 2; } else if (FifoWidth == 2) { FifoWidth = 8; } else { FifoWidth = 4; } BlkDepthInFifo = BlkSize / FifoWidth; Idx = ARRAY_SIZE (BurstSize) - 1; while (Idx && ((BlkDepthInFifo % BurstSize[Idx]) || (TxWatermarkInvers % BurstSize[Idx]))) { Idx--; } RxWatermark = BurstSize[Idx] - 1; FifoThreshold = DWEMMC_DMA_BURST_SIZE (Idx) | DWEMMC_FIFO_TWMARK (TxWatermark) | DWEMMC_FIFO_RWMARK (RxWatermark); MmioWrite32 (DWEMMC_FIFOTH, FifoThreshold); } EFI_STATUS PrepareDmaData ( IN DWEMMC_IDMAC_DESCRIPTOR* IdmacDesc, IN UINTN Length, IN UINT32* Buffer ) { UINTN Cnt, Blks, Idx, LastIdx; UINT32 Data/* , flag, cnt */; MmioWrite32 (DWEMMC_CTRL, DWEMMC_CTRL_FIFO_RESET); do { // Wait until reset operation finished Data = MmioRead32 (DWEMMC_CTRL); } while (Data & DWEMMC_CTRL_RESET_ALL); MmioWrite32 (DWEMMC_IDSTS, 0xffffffff); Cnt = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE; Blks = (Length + DWEMMC_BLOCK_SIZE - 1) / DWEMMC_BLOCK_SIZE; //Length = DWEMMC_BLOCK_SIZE * Blks; for (Idx = 0; Idx < Cnt; Idx++) { (IdmacDesc + Idx)->Des0 = DWEMMC_IDMAC_DES0_OWN | DWEMMC_IDMAC_DES0_CH | DWEMMC_IDMAC_DES0_DIC; (IdmacDesc + Idx)->Des1 = DWEMMC_IDMAC_DES1_BS1(DWEMMC_DMA_BUF_SIZE); /* Buffer Address */ (IdmacDesc + Idx)->Des2 = (UINT32)((UINTN)Buffer + DWEMMC_DMA_BUF_SIZE * Idx); /* Next Descriptor Address */ (IdmacDesc + Idx)->Des3 = (UINT32)((UINTN)IdmacDesc + (sizeof(DWEMMC_IDMAC_DESCRIPTOR) * (Idx + 1))); } /* First Descriptor */ IdmacDesc->Des0 |= DWEMMC_IDMAC_DES0_FS; /* Last Descriptor */ LastIdx = Cnt - 1; (IdmacDesc + LastIdx)->Des0 |= DWEMMC_IDMAC_DES0_LD; (IdmacDesc + LastIdx)->Des0 &= ~(DWEMMC_IDMAC_DES0_DIC | DWEMMC_IDMAC_DES0_CH); (IdmacDesc + LastIdx)->Des1 = DWEMMC_IDMAC_DES1_BS1(Length - (LastIdx * DWEMMC_DMA_BUF_SIZE)); /* Set the Next field of Last Descriptor */ //(IdmacDesc + LastIdx)->Des3 = 0; MmioWrite32 (DWEMMC_DBADDR, (UINT32)((UINTN)IdmacDesc)); return EFI_SUCCESS; } VOID StartDma ( UINTN Length ) { UINT32 Data; Data = MmioRead32 (DWEMMC_CTRL); Data |= DWEMMC_CTRL_DMA_EN | DWEMMC_CTRL_IDMAC_EN; MmioWrite32 (DWEMMC_CTRL, Data); Data = MmioRead32 (DWEMMC_BMOD); Data |= DWEMMC_IDMAC_ENABLE | DWEMMC_IDMAC_FB; MmioWrite32 (DWEMMC_BMOD, Data); MmioWrite32 (DWEMMC_BLKSIZ, (Length < DWEMMC_BLOCK_SIZE) ? Length : DWEMMC_BLOCK_SIZE); MmioWrite32 (DWEMMC_BYTCNT, Length); } EFI_STATUS DwEmmcWaitDmaComplete ( IN EFI_MMC_HOST_PROTOCOL *This, IN UINT32 read ) { UINT32 mask, Ctrl, timeout = 100000; EFI_STATUS ret = EFI_SUCCESS; if (read) mask = DWMCI_IDINTEN_RI; else mask = DWMCI_IDINTEN_TI; do { Ctrl = MmioRead32 (DWEMMC_IDSTS); if (Ctrl & mask) break; timeout--; gBS->Stall(1); } while (timeout); if (!timeout) { DEBUG ((DEBUG_INFO, "wait dma to\n")); ret = EFI_DEVICE_ERROR; } MmioWrite32 (DWEMMC_IDSTS, DWMCI_IDINTEN_MASK); Ctrl = MmioRead32(DWEMMC_CTRL); Ctrl &= ~(DWMCI_DMA_EN); Ctrl = MmioWrite32(DWEMMC_CTRL, Ctrl); gBS->Stall(100); return ret; } EFI_STATUS DwEmmcReadBlockData ( IN EFI_MMC_HOST_PROTOCOL *This, IN EFI_LBA Lba, IN UINTN Length, IN UINT32* Buffer ) { EFI_STATUS Status; UINT32 DescPages, CountPerPage, Count; EFI_TPL Tpl; Tpl = gBS->RaiseTPL (TPL_NOTIFY); CountPerPage = EFI_PAGE_SIZE / 16; Count = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE; DescPages = (Count + CountPerPage - 1) / CountPerPage; InvalidateDataCacheRange (Buffer, Length); // DEBUG ((DEBUG_INFO, "BUFFER %lx length %x\n", (UINT64)Buffer, Length)); Status = PrepareDmaData (gpIdmacDesc, Length, Buffer); if (EFI_ERROR (Status)) { goto out; } WriteBackDataCacheRange (gpIdmacDesc, DescPages * EFI_PAGE_SIZE); StartDma (Length); Status = SendCommand (mDwEmmcCommand, mDwEmmcArgument); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to read data, mDwEmmcCommand:%x, mDwEmmcArgument:%x, Status:%r\n", mDwEmmcCommand, mDwEmmcArgument, Status)); goto out; } Status = DwEmmcWaitDmaComplete(This, 1); out: // Restore Tpl gBS->RestoreTPL (Tpl); return Status; } EFI_STATUS DwEmmcWriteBlockData ( IN EFI_MMC_HOST_PROTOCOL *This, IN EFI_LBA Lba, IN UINTN Length, IN UINT32* Buffer ) { EFI_STATUS Status; UINT32 DescPages, CountPerPage, Count; EFI_TPL Tpl; Tpl = gBS->RaiseTPL (TPL_NOTIFY); CountPerPage = EFI_PAGE_SIZE / 16; Count = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE; DescPages = (Count + CountPerPage - 1) / CountPerPage; WriteBackDataCacheRange (Buffer, Length); Status = PrepareDmaData (gpIdmacDesc, Length, Buffer); if (EFI_ERROR (Status)) { goto out; } WriteBackDataCacheRange (gpIdmacDesc, DescPages * EFI_PAGE_SIZE); StartDma (Length); Status = SendCommand (mDwEmmcCommand, mDwEmmcArgument); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to write data, mDwEmmcCommand:%x, mDwEmmcArgument:%x, Status:%r\n", mDwEmmcCommand, mDwEmmcArgument, Status)); goto out; } Status = DwEmmcWaitDmaComplete(This, 0); out: // Restore Tpl gBS->RestoreTPL (Tpl); return Status; } EFI_STATUS DwEmmcSetIos ( IN EFI_MMC_HOST_PROTOCOL *This, IN UINT32 BusClockFreq, IN UINT32 BusWidth, IN UINT32 TimingMode ) { EFI_STATUS Status = EFI_SUCCESS; UINT32 Data; if ((PcdGet32 (PcdDwEmmcDxeMaxClockFreqInHz) != 0) && (BusClockFreq > PcdGet32 (PcdDwEmmcDxeMaxClockFreqInHz))) { return EFI_UNSUPPORTED; } if (TimingMode != EMMCBACKWARD) { Data = MmioRead32 (DWEMMC_UHSREG); switch (TimingMode) { case EMMCHS52DDR1V2: case EMMCHS52DDR1V8: //Data |= 1 << 16; //break; return EFI_UNSUPPORTED; case EMMCHS52: case EMMCHS26: Data &= ~(1 << 16); break; default: break; } MmioWrite32 (DWEMMC_UHSREG, Data); } //DEBUG ((DEBUG_INFO, "Set bus width %d clock %d\n",BusWidth, BusClockFreq)); switch (BusWidth) { case 1: MmioWrite32 (DWEMMC_CTYPE, 0); break; case 4: MmioWrite32 (DWEMMC_CTYPE, 1); break; case 8: MmioWrite32 (DWEMMC_CTYPE, 1 << 16); break; default: return EFI_UNSUPPORTED; } if (BusClockFreq) { Status = DwEmmcSetClock (BusClockFreq); } return Status; } BOOLEAN DwEmmcIsMultiBlock ( IN EFI_MMC_HOST_PROTOCOL *This ) { return TRUE; } EFI_MMC_HOST_PROTOCOL gMciHost = { MMC_HOST_PROTOCOL_REVISION, DwEmmcIsCardPresent, DwEmmcIsReadOnly, DwEmmcBuildDevicePath, DwEmmcNotifyState, DwEmmcSendCommand, DwEmmcReceiveResponse, DwEmmcReadBlockData, DwEmmcWriteBlockData, DwEmmcSetIos, DwEmmcIsMultiBlock }; EFI_STATUS DwEmmcDxeInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; EFI_HANDLE Handle; if (!FixedPcdGetBool (PcdDwPermitObsoleteDrivers)) { ASSERT (FALSE); return EFI_UNSUPPORTED; } Handle = NULL; DwEmmcAdjustFifoThreshold (); gpIdmacDesc = (DWEMMC_IDMAC_DESCRIPTOR *)AllocatePages (DWEMMC_MAX_DESC_PAGES); if (gpIdmacDesc == NULL) { return EFI_BUFFER_TOO_SMALL; } DEBUG ((DEBUG_BLKIO, "DwEmmcDxeInitialize()\n")); //Publish Component Name, BlockIO protocol interfaces Status = gBS->InstallMultipleProtocolInterfaces ( &Handle, &gEmbeddedMmcHostProtocolGuid, &gMciHost, NULL ); ASSERT_EFI_ERROR (Status); return EFI_SUCCESS; }