Message ID | 1481093679-5636-3-git-send-email-haojian.zhuang@linaro.org |
---|---|
State | Superseded |
Headers | show |
On Wed, Dec 07, 2016 at 02:54:38PM +0800, Haojian Zhuang wrote: > Support designware emmc controller. > > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org> This looks much better, thanks. Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org> > --- > Drivers/Mmc/DwEmmcDxe/DwEmmc.h | 127 +++++++ > Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.c | 648 ++++++++++++++++++++++++++++++++++++ > Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.dec | 42 +++ > Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.inf | 55 +++ > 4 files changed, 872 insertions(+) > create mode 100644 Drivers/Mmc/DwEmmcDxe/DwEmmc.h > create mode 100644 Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.c > create mode 100644 Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.dec > create mode 100644 Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.inf > > diff --git a/Drivers/Mmc/DwEmmcDxe/DwEmmc.h b/Drivers/Mmc/DwEmmcDxe/DwEmmc.h > new file mode 100644 > index 0000000..04160f2 > --- /dev/null > +++ b/Drivers/Mmc/DwEmmcDxe/DwEmmc.h > @@ -0,0 +1,127 @@ > +/** @file > +* > +* Copyright (c) 2014-2016, Linaro 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. > +* > +**/ > + > + > +#ifndef __DWEMMC_H__ > +#define __DWEMMC_H__ > + > +#include <Protocol/EmbeddedGpio.h> > + > +// DW MMC Registers > +#define DWEMMC_CTRL ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x000) > +#define DWEMMC_PWREN ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x004) > +#define DWEMMC_CLKDIV ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x008) > +#define DWEMMC_CLKSRC ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x00c) > +#define DWEMMC_CLKENA ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x010) > +#define DWEMMC_TMOUT ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x014) > +#define DWEMMC_CTYPE ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x018) > +#define DWEMMC_BLKSIZ ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x01c) > +#define DWEMMC_BYTCNT ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x020) > +#define DWEMMC_INTMASK ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x024) > +#define DWEMMC_CMDARG ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x028) > +#define DWEMMC_CMD ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x02c) > +#define DWEMMC_RESP0 ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x030) > +#define DWEMMC_RESP1 ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x034) > +#define DWEMMC_RESP2 ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x038) > +#define DWEMMC_RESP3 ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x03c) > +#define DWEMMC_RINTSTS ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x044) > +#define DWEMMC_STATUS ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x048) > +#define DWEMMC_FIFOTH ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x04c) > +#define DWEMMC_DEBNCE ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x064) > +#define DWEMMC_UHSREG ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x074) > +#define DWEMMC_BMOD ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x080) > +#define DWEMMC_DBADDR ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x088) > +#define DWEMMC_IDSTS ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x08c) > +#define DWEMMC_IDINTEN ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x090) > +#define DWEMMC_DSCADDR ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x094) > +#define DWEMMC_BUFADDR ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x098) > +#define DWEMMC_CARDTHRCTL ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0X100) > + > +#define CMD_UPDATE_CLK 0x80202000 > +#define CMD_START_BIT (1 << 31) > + > +#define MMC_8BIT_MODE (1 << 16) > + > +#define BIT_CMD_RESPONSE_EXPECT (1 << 6) > +#define BIT_CMD_LONG_RESPONSE (1 << 7) > +#define BIT_CMD_CHECK_RESPONSE_CRC (1 << 8) > +#define BIT_CMD_DATA_EXPECTED (1 << 9) > +#define BIT_CMD_READ (0 << 10) > +#define BIT_CMD_WRITE (1 << 10) > +#define BIT_CMD_BLOCK_TRANSFER (0 << 11) > +#define BIT_CMD_STREAM_TRANSFER (1 << 11) > +#define BIT_CMD_SEND_AUTO_STOP (1 << 12) > +#define BIT_CMD_WAIT_PRVDATA_COMPLETE (1 << 13) > +#define BIT_CMD_STOP_ABORT_CMD (1 << 14) > +#define BIT_CMD_SEND_INIT (1 << 15) > +#define BIT_CMD_UPDATE_CLOCK_ONLY (1 << 21) > +#define BIT_CMD_READ_CEATA_DEVICE (1 << 22) > +#define BIT_CMD_CCS_EXPECTED (1 << 23) > +#define BIT_CMD_ENABLE_BOOT (1 << 24) > +#define BIT_CMD_EXPECT_BOOT_ACK (1 << 25) > +#define BIT_CMD_DISABLE_BOOT (1 << 26) > +#define BIT_CMD_MANDATORY_BOOT (0 << 27) > +#define BIT_CMD_ALTERNATE_BOOT (1 << 27) > +#define BIT_CMD_VOLT_SWITCH (1 << 28) > +#define BIT_CMD_USE_HOLD_REG (1 << 29) > +#define BIT_CMD_START (1 << 31) > + > +#define DWEMMC_INT_EBE (1 << 15) /* End-bit Err */ > +#define DWEMMC_INT_SBE (1 << 13) /* Start-bit Err */ > +#define DWEMMC_INT_HLE (1 << 12) /* Hardware-lock Err */ > +#define DWEMMC_INT_FRUN (1 << 11) /* FIFO UN/OV RUN */ > +#define DWEMMC_INT_DRT (1 << 9) /* Data timeout */ > +#define DWEMMC_INT_RTO (1 << 8) /* Response timeout */ > +#define DWEMMC_INT_DCRC (1 << 7) /* Data CRC err */ > +#define DWEMMC_INT_RCRC (1 << 6) /* Response CRC err */ > +#define DWEMMC_INT_RXDR (1 << 5) > +#define DWEMMC_INT_TXDR (1 << 4) > +#define DWEMMC_INT_DTO (1 << 3) /* Data trans over */ > +#define DWEMMC_INT_CMD_DONE (1 << 2) > +#define DWEMMC_INT_RE (1 << 1) > + > +#define DWEMMC_IDMAC_DES0_DIC (1 << 1) > +#define DWEMMC_IDMAC_DES0_LD (1 << 2) > +#define DWEMMC_IDMAC_DES0_FS (1 << 3) > +#define DWEMMC_IDMAC_DES0_CH (1 << 4) > +#define DWEMMC_IDMAC_DES0_ER (1 << 5) > +#define DWEMMC_IDMAC_DES0_CES (1 << 30) > +#define DWEMMC_IDMAC_DES0_OWN (1 << 31) > +#define DWEMMC_IDMAC_DES1_BS1(x) ((x) & 0x1fff) > +#define DWEMMC_IDMAC_DES2_BS2(x) (((x) & 0x1fff) << 13) > +#define DWEMMC_IDMAC_SWRESET (1 << 0) > +#define DWEMMC_IDMAC_FB (1 << 1) > +#define DWEMMC_IDMAC_ENABLE (1 << 7) > + > +#define EMMC_FIX_RCA 6 > + > +/* bits in MMC0_CTRL */ > +#define DWEMMC_CTRL_RESET (1 << 0) > +#define DWEMMC_CTRL_FIFO_RESET (1 << 1) > +#define DWEMMC_CTRL_DMA_RESET (1 << 2) > +#define DWEMMC_CTRL_INT_EN (1 << 4) > +#define DWEMMC_CTRL_DMA_EN (1 << 5) > +#define DWEMMC_CTRL_IDMAC_EN (1 << 25) > +#define DWEMMC_CTRL_RESET_ALL (DWEMMC_CTRL_RESET | DWEMMC_CTRL_FIFO_RESET | DWEMMC_CTRL_DMA_RESET) > + > +#define DWEMMC_STS_DATA_BUSY (1 << 9) > + > +#define DWEMMC_FIFO_TWMARK(x) (x & 0xfff) > +#define DWEMMC_FIFO_RWMARK(x) ((x & 0x1ff) << 16) > +#define DWEMMC_DMA_BURST_SIZE(x) ((x & 0x7) << 28) > + > +#define DWEMMC_CARD_RD_THR(x) ((x & 0xfff) << 16) > +#define DWEMMC_CARD_RD_THR_EN (1 << 0) > + > +#endif // __DWEMMC_H__ > diff --git a/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.c b/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.c > new file mode 100644 > index 0000000..7fbceaa > --- /dev/null > +++ b/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.c > @@ -0,0 +1,648 @@ > +/** @file > + This file implement the MMC Host Protocol for the DesignWare eMMC. > + > + Copyright (c) 2014-2016, Linaro 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 <Library/BaseMemoryLib.h> > +#include <Library/CacheMaintenanceLib.h> > +#include <Library/DebugLib.h> > +#include <Library/DevicePathLib.h> > +#include <Library/IoLib.h> > +#include <Library/MemoryAllocationLib.h> > +#include <Library/PcdLib.h> > +#include <Library/TimerLib.h> > +#include <Library/UefiBootServicesTableLib.h> > +#include <Library/UefiLib.h> > + > +#include <Protocol/MmcHost.h> > + > +#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 > + > +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; > + > +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; > +} > + > +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_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); > + 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); > + > + 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): > + 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(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; > + } > + > + 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); > + } > + 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; > +} > + > +EFI_STATUS > +PrepareDmaData ( > + IN DWEMMC_IDMAC_DESCRIPTOR* IdmacDesc, > + IN UINTN Length, > + IN UINT32* Buffer > + ) > +{ > + UINTN Cnt, Blks, Idx, LastIdx; > + > + 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_INT_EN | 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, DWEMMC_BLOCK_SIZE); > + MmioWrite32 (DWEMMC_BYTCNT, Length); > +} > + > +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); > + > + 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; > + } > +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; > + } > +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 (TimingMode != EMMCBACKWARD) { > + Data = MmioRead32 (DWEMMC_UHSREG); > + switch (TimingMode) { > + case EMMCHS52DDR1V2: > + case EMMCHS52DDR1V8: > + Data |= 1 << 16; > + break; > + case EMMCHS52: > + case EMMCHS26: > + Data &= ~(1 << 16); > + break; > + default: > + return EFI_UNSUPPORTED; > + } > + MmioWrite32 (DWEMMC_UHSREG, Data); > + } > + > + 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; > + > + Handle = NULL; > + > + 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, > + &gEfiMmcHostProtocolGuid, &gMciHost, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + > + return EFI_SUCCESS; > +} > diff --git a/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.dec b/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.dec > new file mode 100644 > index 0000000..f41deeb > --- /dev/null > +++ b/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.dec > @@ -0,0 +1,42 @@ > +#/** @file > +# Framework Module Development Environment Industry Standards > +# > +# This Package provides headers and libraries that conform to EFI/PI Industry standards. > +# Copyright (c) 2007, Intel Corporation. All rights reserved.<BR> > +# Copyright (c) 2012-2014, ARM Ltd. All rights reserved.<BR> > +# Copyright (c) 2015-2016, Linaro. All rights reserved.<BR> > +# > +# 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. > +# > +#**/ > + > +[Defines] > + DEC_SPECIFICATION = 0x00010005 > + PACKAGE_NAME = MmcDwEmmcDxePkg > + PACKAGE_GUID = 3869905e-c96c-4d20-9bfb-3b9d71bb900c > + PACKAGE_VERSION = 0.1 > + > + > +################################################################################ > +# > +# Include Section - list of Include Paths that are provided by this package. > +# Comments are used for Keywords and Module Types. > +# > +# Supported Module Types: > +# BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION > +# > +################################################################################ > + > +[Guids.common] > + gDwEmmcDxeTokenSpaceGuid = { 0x6fdd76a9, 0xf220, 0x4f1d, { 0x9c, 0xcf, 0xbc, 0x2d, 0x68, 0x29, 0xab, 0x9c }} > + > +[PcdsFixedAtBuild.common] > + # DwEmmc Driver PCDs > + gDwEmmcDxeTokenSpaceGuid.PcdDwEmmcDxeBaseAddress|0x0|UINT32|0x00000001 > + gDwEmmcDxeTokenSpaceGuid.PcdDwEmmcDxeClockFrequencyInHz|0x0|UINT32|0x00000002 > diff --git a/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.inf b/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.inf > new file mode 100644 > index 0000000..ba9a003 > --- /dev/null > +++ b/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.inf > @@ -0,0 +1,55 @@ > +#/** @file > +# INF file for the eMMC Host Protocol implementation for the DesignWare MMC. > +# > +# Copyright (c) 2014-2016, Linaro Limited. All rights reserved. > +# Copyright (c) 2014-2016, Hisilicon 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. > +# > +#**/ > + > +[Defines] > + INF_VERSION = 0x00010005 > + BASE_NAME = DwEmmcDxe > + FILE_GUID = b549f005-4bd4-4020-a0cb-06f42bda68c3 > + MODULE_TYPE = DXE_DRIVER > + VERSION_STRING = 1.0 > + > + ENTRY_POINT = DwEmmcDxeInitialize > + > +[Sources.common] > + DwEmmcDxe.c > + > +[Packages] > + EmbeddedPkg/EmbeddedPkg.dec > + MdePkg/MdePkg.dec > + OpenPlatformPkg/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.dec > + > +[LibraryClasses] > + ArmLib > + BaseLib > + BaseMemoryLib > + CacheMaintenanceLib > + IoLib > + MemoryAllocationLib > + TimerLib > + UefiDriverEntryPoint > + UefiLib > + > +[Protocols] > + gEfiCpuArchProtocolGuid > + gEfiDevicePathProtocolGuid > + gEfiMmcHostProtocolGuid > + > +[Pcd] > + gDwEmmcDxeTokenSpaceGuid.PcdDwEmmcDxeBaseAddress > + gDwEmmcDxeTokenSpaceGuid.PcdDwEmmcDxeClockFrequencyInHz > + > +[Depex] > + TRUE > -- > 2.7.4 >
diff --git a/Drivers/Mmc/DwEmmcDxe/DwEmmc.h b/Drivers/Mmc/DwEmmcDxe/DwEmmc.h new file mode 100644 index 0000000..04160f2 --- /dev/null +++ b/Drivers/Mmc/DwEmmcDxe/DwEmmc.h @@ -0,0 +1,127 @@ +/** @file +* +* Copyright (c) 2014-2016, Linaro 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. +* +**/ + + +#ifndef __DWEMMC_H__ +#define __DWEMMC_H__ + +#include <Protocol/EmbeddedGpio.h> + +// DW MMC Registers +#define DWEMMC_CTRL ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x000) +#define DWEMMC_PWREN ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x004) +#define DWEMMC_CLKDIV ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x008) +#define DWEMMC_CLKSRC ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x00c) +#define DWEMMC_CLKENA ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x010) +#define DWEMMC_TMOUT ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x014) +#define DWEMMC_CTYPE ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x018) +#define DWEMMC_BLKSIZ ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x01c) +#define DWEMMC_BYTCNT ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x020) +#define DWEMMC_INTMASK ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x024) +#define DWEMMC_CMDARG ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x028) +#define DWEMMC_CMD ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x02c) +#define DWEMMC_RESP0 ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x030) +#define DWEMMC_RESP1 ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x034) +#define DWEMMC_RESP2 ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x038) +#define DWEMMC_RESP3 ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x03c) +#define DWEMMC_RINTSTS ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x044) +#define DWEMMC_STATUS ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x048) +#define DWEMMC_FIFOTH ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x04c) +#define DWEMMC_DEBNCE ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x064) +#define DWEMMC_UHSREG ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x074) +#define DWEMMC_BMOD ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x080) +#define DWEMMC_DBADDR ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x088) +#define DWEMMC_IDSTS ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x08c) +#define DWEMMC_IDINTEN ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x090) +#define DWEMMC_DSCADDR ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x094) +#define DWEMMC_BUFADDR ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0x098) +#define DWEMMC_CARDTHRCTL ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress) + 0X100) + +#define CMD_UPDATE_CLK 0x80202000 +#define CMD_START_BIT (1 << 31) + +#define MMC_8BIT_MODE (1 << 16) + +#define BIT_CMD_RESPONSE_EXPECT (1 << 6) +#define BIT_CMD_LONG_RESPONSE (1 << 7) +#define BIT_CMD_CHECK_RESPONSE_CRC (1 << 8) +#define BIT_CMD_DATA_EXPECTED (1 << 9) +#define BIT_CMD_READ (0 << 10) +#define BIT_CMD_WRITE (1 << 10) +#define BIT_CMD_BLOCK_TRANSFER (0 << 11) +#define BIT_CMD_STREAM_TRANSFER (1 << 11) +#define BIT_CMD_SEND_AUTO_STOP (1 << 12) +#define BIT_CMD_WAIT_PRVDATA_COMPLETE (1 << 13) +#define BIT_CMD_STOP_ABORT_CMD (1 << 14) +#define BIT_CMD_SEND_INIT (1 << 15) +#define BIT_CMD_UPDATE_CLOCK_ONLY (1 << 21) +#define BIT_CMD_READ_CEATA_DEVICE (1 << 22) +#define BIT_CMD_CCS_EXPECTED (1 << 23) +#define BIT_CMD_ENABLE_BOOT (1 << 24) +#define BIT_CMD_EXPECT_BOOT_ACK (1 << 25) +#define BIT_CMD_DISABLE_BOOT (1 << 26) +#define BIT_CMD_MANDATORY_BOOT (0 << 27) +#define BIT_CMD_ALTERNATE_BOOT (1 << 27) +#define BIT_CMD_VOLT_SWITCH (1 << 28) +#define BIT_CMD_USE_HOLD_REG (1 << 29) +#define BIT_CMD_START (1 << 31) + +#define DWEMMC_INT_EBE (1 << 15) /* End-bit Err */ +#define DWEMMC_INT_SBE (1 << 13) /* Start-bit Err */ +#define DWEMMC_INT_HLE (1 << 12) /* Hardware-lock Err */ +#define DWEMMC_INT_FRUN (1 << 11) /* FIFO UN/OV RUN */ +#define DWEMMC_INT_DRT (1 << 9) /* Data timeout */ +#define DWEMMC_INT_RTO (1 << 8) /* Response timeout */ +#define DWEMMC_INT_DCRC (1 << 7) /* Data CRC err */ +#define DWEMMC_INT_RCRC (1 << 6) /* Response CRC err */ +#define DWEMMC_INT_RXDR (1 << 5) +#define DWEMMC_INT_TXDR (1 << 4) +#define DWEMMC_INT_DTO (1 << 3) /* Data trans over */ +#define DWEMMC_INT_CMD_DONE (1 << 2) +#define DWEMMC_INT_RE (1 << 1) + +#define DWEMMC_IDMAC_DES0_DIC (1 << 1) +#define DWEMMC_IDMAC_DES0_LD (1 << 2) +#define DWEMMC_IDMAC_DES0_FS (1 << 3) +#define DWEMMC_IDMAC_DES0_CH (1 << 4) +#define DWEMMC_IDMAC_DES0_ER (1 << 5) +#define DWEMMC_IDMAC_DES0_CES (1 << 30) +#define DWEMMC_IDMAC_DES0_OWN (1 << 31) +#define DWEMMC_IDMAC_DES1_BS1(x) ((x) & 0x1fff) +#define DWEMMC_IDMAC_DES2_BS2(x) (((x) & 0x1fff) << 13) +#define DWEMMC_IDMAC_SWRESET (1 << 0) +#define DWEMMC_IDMAC_FB (1 << 1) +#define DWEMMC_IDMAC_ENABLE (1 << 7) + +#define EMMC_FIX_RCA 6 + +/* bits in MMC0_CTRL */ +#define DWEMMC_CTRL_RESET (1 << 0) +#define DWEMMC_CTRL_FIFO_RESET (1 << 1) +#define DWEMMC_CTRL_DMA_RESET (1 << 2) +#define DWEMMC_CTRL_INT_EN (1 << 4) +#define DWEMMC_CTRL_DMA_EN (1 << 5) +#define DWEMMC_CTRL_IDMAC_EN (1 << 25) +#define DWEMMC_CTRL_RESET_ALL (DWEMMC_CTRL_RESET | DWEMMC_CTRL_FIFO_RESET | DWEMMC_CTRL_DMA_RESET) + +#define DWEMMC_STS_DATA_BUSY (1 << 9) + +#define DWEMMC_FIFO_TWMARK(x) (x & 0xfff) +#define DWEMMC_FIFO_RWMARK(x) ((x & 0x1ff) << 16) +#define DWEMMC_DMA_BURST_SIZE(x) ((x & 0x7) << 28) + +#define DWEMMC_CARD_RD_THR(x) ((x & 0xfff) << 16) +#define DWEMMC_CARD_RD_THR_EN (1 << 0) + +#endif // __DWEMMC_H__ diff --git a/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.c b/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.c new file mode 100644 index 0000000..7fbceaa --- /dev/null +++ b/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.c @@ -0,0 +1,648 @@ +/** @file + This file implement the MMC Host Protocol for the DesignWare eMMC. + + Copyright (c) 2014-2016, Linaro 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 <Library/BaseMemoryLib.h> +#include <Library/CacheMaintenanceLib.h> +#include <Library/DebugLib.h> +#include <Library/DevicePathLib.h> +#include <Library/IoLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PcdLib.h> +#include <Library/TimerLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> + +#include <Protocol/MmcHost.h> + +#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 + +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; + +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; +} + +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_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); + 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); + + 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): + 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(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; + } + + 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); + } + 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; +} + +EFI_STATUS +PrepareDmaData ( + IN DWEMMC_IDMAC_DESCRIPTOR* IdmacDesc, + IN UINTN Length, + IN UINT32* Buffer + ) +{ + UINTN Cnt, Blks, Idx, LastIdx; + + 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_INT_EN | 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, DWEMMC_BLOCK_SIZE); + MmioWrite32 (DWEMMC_BYTCNT, Length); +} + +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); + + 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; + } +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; + } +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 (TimingMode != EMMCBACKWARD) { + Data = MmioRead32 (DWEMMC_UHSREG); + switch (TimingMode) { + case EMMCHS52DDR1V2: + case EMMCHS52DDR1V8: + Data |= 1 << 16; + break; + case EMMCHS52: + case EMMCHS26: + Data &= ~(1 << 16); + break; + default: + return EFI_UNSUPPORTED; + } + MmioWrite32 (DWEMMC_UHSREG, Data); + } + + 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; + + Handle = NULL; + + 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, + &gEfiMmcHostProtocolGuid, &gMciHost, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} diff --git a/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.dec b/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.dec new file mode 100644 index 0000000..f41deeb --- /dev/null +++ b/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.dec @@ -0,0 +1,42 @@ +#/** @file +# Framework Module Development Environment Industry Standards +# +# This Package provides headers and libraries that conform to EFI/PI Industry standards. +# Copyright (c) 2007, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2012-2014, ARM Ltd. All rights reserved.<BR> +# Copyright (c) 2015-2016, Linaro. All rights reserved.<BR> +# +# 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. +# +#**/ + +[Defines] + DEC_SPECIFICATION = 0x00010005 + PACKAGE_NAME = MmcDwEmmcDxePkg + PACKAGE_GUID = 3869905e-c96c-4d20-9bfb-3b9d71bb900c + PACKAGE_VERSION = 0.1 + + +################################################################################ +# +# Include Section - list of Include Paths that are provided by this package. +# Comments are used for Keywords and Module Types. +# +# Supported Module Types: +# BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION +# +################################################################################ + +[Guids.common] + gDwEmmcDxeTokenSpaceGuid = { 0x6fdd76a9, 0xf220, 0x4f1d, { 0x9c, 0xcf, 0xbc, 0x2d, 0x68, 0x29, 0xab, 0x9c }} + +[PcdsFixedAtBuild.common] + # DwEmmc Driver PCDs + gDwEmmcDxeTokenSpaceGuid.PcdDwEmmcDxeBaseAddress|0x0|UINT32|0x00000001 + gDwEmmcDxeTokenSpaceGuid.PcdDwEmmcDxeClockFrequencyInHz|0x0|UINT32|0x00000002 diff --git a/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.inf b/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.inf new file mode 100644 index 0000000..ba9a003 --- /dev/null +++ b/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.inf @@ -0,0 +1,55 @@ +#/** @file +# INF file for the eMMC Host Protocol implementation for the DesignWare MMC. +# +# Copyright (c) 2014-2016, Linaro Limited. All rights reserved. +# Copyright (c) 2014-2016, Hisilicon 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. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DwEmmcDxe + FILE_GUID = b549f005-4bd4-4020-a0cb-06f42bda68c3 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = DwEmmcDxeInitialize + +[Sources.common] + DwEmmcDxe.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + OpenPlatformPkg/Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.dec + +[LibraryClasses] + ArmLib + BaseLib + BaseMemoryLib + CacheMaintenanceLib + IoLib + MemoryAllocationLib + TimerLib + UefiDriverEntryPoint + UefiLib + +[Protocols] + gEfiCpuArchProtocolGuid + gEfiDevicePathProtocolGuid + gEfiMmcHostProtocolGuid + +[Pcd] + gDwEmmcDxeTokenSpaceGuid.PcdDwEmmcDxeBaseAddress + gDwEmmcDxeTokenSpaceGuid.PcdDwEmmcDxeClockFrequencyInHz + +[Depex] + TRUE
Support designware emmc controller. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org> --- Drivers/Mmc/DwEmmcDxe/DwEmmc.h | 127 +++++++ Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.c | 648 ++++++++++++++++++++++++++++++++++++ Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.dec | 42 +++ Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.inf | 55 +++ 4 files changed, 872 insertions(+) create mode 100644 Drivers/Mmc/DwEmmcDxe/DwEmmc.h create mode 100644 Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.c create mode 100644 Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.dec create mode 100644 Drivers/Mmc/DwEmmcDxe/DwEmmcDxe.inf