From: "Leif Lindholm" <leif@nuviainc.com>
To: Ard Biesheuvel <ard.biesheuvel@arm.com>
Cc: devel@edk2.groups.io
Subject: Re: [PATCH edk2-platforms 2/2] Platform/ARM/VExpressPkg: incorporate PL180 driver
Date: Wed, 29 Apr 2020 22:51:01 +0100 [thread overview]
Message-ID: <20200429215101.GO21486@vanye> (raw)
In-Reply-To: <20200429184705.20934-2-ard.biesheuvel@arm.com>
On Wed, Apr 29, 2020 at 20:47:05 +0200, Ard Biesheuvel wrote:
> The PL180 SD host controller driver is only used on emulated ARM
> platforms, uses an obsolete version of the MMC host protocol and
> does not adhere to the UEFI driver model.
>
> Given the above, let's just move it into VExpressPkg where it
> belongs.
>
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
I agree with the change, but will want the warning message added
wherever we decide in the separate bikeshedding thread.
/
Leif
> ---
> Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc | 6 +-
> Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf | 2 +-
> Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.dsc | 6 +-
> Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf | 2 +-
> Platform/ARM/VExpressPkg/ArmVExpressPkg.dec | 4 +
> Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.c | 563 ++++++++++++++++++++
> Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.h | 162 ++++++
> Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf | 46 ++
> 8 files changed, 783 insertions(+), 8 deletions(-)
>
> diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc
> index 2f8021d3eabc..6dad31026aa5 100644
> --- a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc
> +++ b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc
> @@ -146,8 +146,8 @@ [PcdsFixedAtBuild.common]
> #
> # PL180 MMC/SD card controller
> #
> - gArmPlatformTokenSpaceGuid.PcdPL180SysMciRegAddress|0x1C010048
> - gArmPlatformTokenSpaceGuid.PcdPL180MciBaseAddress|0x1C050000
> + gArmVExpressTokenSpaceGuid.PcdPL180SysMciRegAddress|0x1C010048
> + gArmVExpressTokenSpaceGuid.PcdPL180MciBaseAddress|0x1C050000
>
>
> #
> @@ -249,7 +249,7 @@ [Components.common]
> # Multimedia Card Interface
> #
> EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf
> - ArmPlatformPkg/Drivers/PL180MciDxe/PL180MciDxe.inf
> + Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf
>
> # SMSC LAN 9118
> EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf
> diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf
> index 082f80d9996d..64da1102ff07 100644
> --- a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf
> +++ b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf
> @@ -103,7 +103,7 @@ [FV.FvMain]
> # Multimedia Card Interface
> #
> INF EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf
> - INF ArmPlatformPkg/Drivers/PL180MciDxe/PL180MciDxe.inf
> + INF Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf
>
> #
> # Filesystems
> diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.dsc b/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.dsc
> index 63d79a488500..a6f536a33228 100644
> --- a/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.dsc
> +++ b/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.dsc
> @@ -151,8 +151,8 @@ [PcdsFixedAtBuild.common]
> !endif
>
> ## PL180 MMC/SD card controller
> - gArmPlatformTokenSpaceGuid.PcdPL180SysMciRegAddress|0x1C010048
> - gArmPlatformTokenSpaceGuid.PcdPL180MciBaseAddress|0x1C050000
> + gArmVExpressTokenSpaceGuid.PcdPL180SysMciRegAddress|0x1C010048
> + gArmVExpressTokenSpaceGuid.PcdPL180MciBaseAddress|0x1C050000
>
> #
> # ARM Generic Interrupt Controller
> @@ -290,7 +290,7 @@ [Components.common]
> # Multimedia Card Interface
> #
> EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf
> - ArmPlatformPkg/Drivers/PL180MciDxe/PL180MciDxe.inf
> + Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf
>
> #
> # Platform Driver
> diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf b/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf
> index 8f49ed3dba3c..f18ead75eaec 100644
> --- a/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf
> +++ b/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf
> @@ -139,7 +139,7 @@ [FV.FvMain]
> # Multimedia Card Interface
> #
> INF EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf
> - INF ArmPlatformPkg/Drivers/PL180MciDxe/PL180MciDxe.inf
> + INF Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf
>
> #
> # SMBIOS Support
> diff --git a/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec b/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec
> index a659cda2e44a..a4e9bfd73eb6 100644
> --- a/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec
> +++ b/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec
> @@ -52,3 +52,7 @@ [PcdsFixedAtBuild.common]
> #
> gArmVExpressTokenSpaceGuid.PcdAndroidFastbootNvmDevicePath|""|VOID*|0x00000006
> gArmVExpressTokenSpaceGuid.PcdAndroidFastbootProductName|""|VOID*|0x00000007
> +
> + ## PL180 MCI
> + gArmVExpressTokenSpaceGuid.PcdPL180SysMciRegAddress|0x00000000|UINT32|0x00000009
> + gArmVExpressTokenSpaceGuid.PcdPL180MciBaseAddress|0x00000000|UINT32|0x0000000A
> diff --git a/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.c b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.c
> new file mode 100644
> index 000000000000..0c9e4b7ce15e
> --- /dev/null
> +++ b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.c
> @@ -0,0 +1,563 @@
> +/** @file
> + This file implement the MMC Host Protocol for the ARM PrimeCell PL180.
> +
> + Copyright (c) 2011-2012, ARM Limited. All rights reserved.
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#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);
> +}
> +
> +// Convert block size to 2^n
> +STATIC
> +UINT32
> +GetPow2BlockLen (
> + IN UINT32 BlockLen
> + )
> +{
> + UINTN Loop;
> + UINTN Pow2BlockLen;
> +
> + Loop = 0x8000;
> + Pow2BlockLen = 15;
> + do {
> + Loop = (Loop >> 1) & 0xFFFF;
> + Pow2BlockLen--;
> + } while (Pow2BlockLen && (!(Loop & BlockLen)));
> +
> + return Pow2BlockLen;
> +}
> +
> +VOID
> +MciPrepareDataPath (
> + IN UINTN TransferDirection
> + )
> +{
> + // Set Data Length & Data Timer
> + 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);
> + } else if (MmcCmd == MMC_CMD6) {
> + MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFFFF);
> + MmioWrite32 (MCI_DATA_LENGTH_REG, 64);
> +#ifndef USE_STREAM
> + MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | GetPow2BlockLen (64));
> +#else
> + MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | MCI_DATACTL_STREAM_TRANS);
> +#endif
> + } else if (MmcCmd == MMC_ACMD51) {
> + MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFFFF);
> + /* SCR register is 8 bytes long. */
> + MmioWrite32 (MCI_DATA_LENGTH_REG, 8);
> +#ifndef USE_STREAM
> + MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | GetPow2BlockLen (8));
> +#else
> + MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_TO_CONT | MCI_DATACTL_STREAM_TRANS);
> +#endif
> + }
> +
> + // 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;
> + if (Length < MMCI0_BLOCKLEN) {
> + Finish = Length / 4;
> + } else {
> + 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_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) {
> +
> + DEBUG ((EFI_D_WARN, "Probing ID registers at 0x%lx for a PL180"
> + " failed\n", MCI_PERIPH_ID_REG0));
> + return EFI_NOT_FOUND;
> + }
> +
> + Handle = NULL;
> +
> + MCI_TRACE ("PL180MciDxeInitialize()");
> +
> + //Publish Component Name, BlockIO protocol interfaces
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &Handle,
> + &gEdkiiMmcHostProtocolGuid, &gMciHost,
> + NULL
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + return EFI_SUCCESS;
> +}
> diff --git a/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.h b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.h
> new file mode 100644
> index 000000000000..a5bfe0b2eceb
> --- /dev/null
> +++ b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.h
> @@ -0,0 +1,162 @@
> +/** @file
> + Header for the MMC Host Protocol implementation for the ARM PrimeCell PL180.
> +
> + Copyright (c) 2011-2012, ARM Limited. All rights reserved.
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef __PL180_MCI_H
> +#define __PL180_MCI_H
> +
> +#include <Uefi.h>
> +
> +#include <Protocol/MmcHost.h>
> +
> +#include <Library/UefiLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/TimerLib.h>
> +#include <Library/PcdLib.h>
> +
> +#define PL180_MCI_DXE_VERSION 0x10
> +
> +#define MCI_SYSCTL FixedPcdGet32 (PcdPL180MciBaseAddress)
> +
> +#define MCI_POWER_CONTROL_REG (MCI_SYSCTL + 0x000)
> +#define MCI_CLOCK_CONTROL_REG (MCI_SYSCTL + 0x004)
> +#define MCI_ARGUMENT_REG (MCI_SYSCTL + 0x008)
> +#define MCI_COMMAND_REG (MCI_SYSCTL + 0x00C)
> +#define MCI_RESPCMD_REG (MCI_SYSCTL + 0x010)
> +#define MCI_RESPONSE3_REG (MCI_SYSCTL + 0x014)
> +#define MCI_RESPONSE2_REG (MCI_SYSCTL + 0x018)
> +#define MCI_RESPONSE1_REG (MCI_SYSCTL + 0x01C)
> +#define MCI_RESPONSE0_REG (MCI_SYSCTL + 0x020)
> +#define MCI_DATA_TIMER_REG (MCI_SYSCTL + 0x024)
> +#define MCI_DATA_LENGTH_REG (MCI_SYSCTL + 0x028)
> +#define MCI_DATA_CTL_REG (MCI_SYSCTL + 0x02C)
> +#define MCI_DATA_COUNTER (MCI_SYSCTL + 0x030)
> +#define MCI_STATUS_REG (MCI_SYSCTL + 0x034)
> +#define MCI_CLEAR_STATUS_REG (MCI_SYSCTL + 0x038)
> +#define MCI_INT0_MASK_REG (MCI_SYSCTL + 0x03C)
> +#define MCI_INT1_MASK_REG (MCI_SYSCTL + 0x040)
> +#define MCI_SELECT_REG (MCI_SYSCTL + 0x044)
> +#define MCI_FIFOCOUNT_REG (MCI_SYSCTL + 0x048)
> +#define MCI_FIFO_REG (MCI_SYSCTL + 0x080)
> +#define MCI_PERIPH_ID_REG0 (MCI_SYSCTL + 0xFE0)
> +#define MCI_PERIPH_ID_REG1 (MCI_SYSCTL + 0xFE4)
> +#define MCI_PERIPH_ID_REG2 (MCI_SYSCTL + 0xFE8)
> +#define MCI_PERIPH_ID_REG3 (MCI_SYSCTL + 0xFEC)
> +#define MCI_PCELL_ID_REG0 (MCI_SYSCTL + 0xFF0)
> +#define MCI_PCELL_ID_REG1 (MCI_SYSCTL + 0xFF4)
> +#define MCI_PCELL_ID_REG2 (MCI_SYSCTL + 0xFF8)
> +#define MCI_PCELL_ID_REG3 (MCI_SYSCTL + 0xFFC)
> +
> +#define MCI_PERIPH_ID0 0x80
> +#define MCI_PERIPH_ID1 0x11
> +#define MCI_PERIPH_ID2 0x04
> +#define MCI_PERIPH_ID3 0x00
> +#define MCI_PCELL_ID0 0x0D
> +#define MCI_PCELL_ID1 0xF0
> +#define MCI_PCELL_ID2 0x05
> +#define MCI_PCELL_ID3 0xB1
> +
> +#define MCI_POWER_OFF 0
> +#define MCI_POWER_UP BIT1
> +#define MCI_POWER_ON (BIT1 | BIT0)
> +#define MCI_POWER_OPENDRAIN BIT6
> +#define MCI_POWER_ROD BIT7
> +
> +#define MCI_CLOCK_ENABLE BIT8
> +#define MCI_CLOCK_POWERSAVE BIT9
> +#define MCI_CLOCK_BYPASS BIT10
> +#define MCI_CLOCK_WIDEBUS BIT11
> +
> +#define MCI_STATUS_CMD_CMDCRCFAIL BIT0
> +#define MCI_STATUS_CMD_DATACRCFAIL BIT1
> +#define MCI_STATUS_CMD_CMDTIMEOUT BIT2
> +#define MCI_STATUS_CMD_DATATIMEOUT BIT3
> +#define MCI_STATUS_CMD_TX_UNDERRUN BIT4
> +#define MCI_STATUS_CMD_RXOVERRUN BIT5
> +#define MCI_STATUS_CMD_RESPEND BIT6
> +#define MCI_STATUS_CMD_SENT BIT7
> +#define MCI_STATUS_CMD_DATAEND BIT8
> +#define MCI_STATUS_CMD_START_BIT_ERROR BIT9
> +#define MCI_STATUS_CMD_DATABLOCKEND BIT10
> +#define MCI_STATUS_CMD_ACTIVE BIT11
> +#define MCI_STATUS_CMD_TXACTIVE BIT12
> +#define MCI_STATUS_CMD_RXACTIVE BIT13
> +#define MCI_STATUS_CMD_TXFIFOHALFEMPTY BIT14
> +#define MCI_STATUS_CMD_RXFIFOHALFFULL BIT15
> +#define MCI_STATUS_CMD_TXFIFOFULL BIT16
> +#define MCI_STATUS_CMD_RXFIFOFULL BIT17
> +#define MCI_STATUS_CMD_TXFIFOEMPTY BIT18
> +#define MCI_STATUS_CMD_RXFIFOEMPTY BIT19
> +#define MCI_STATUS_CMD_TXDATAAVAILBL BIT20
> +#define MCI_STATUS_CMD_RXDATAAVAILBL BIT21
> +
> +#define MCI_STATUS_TXDONE (MCI_STATUS_CMD_DATAEND | MCI_STATUS_CMD_DATABLOCKEND)
> +#define MCI_STATUS_RXDONE (MCI_STATUS_CMD_DATAEND | MCI_STATUS_CMD_DATABLOCKEND)
> +#define MCI_STATUS_READ_ERROR ( MCI_STATUS_CMD_DATACRCFAIL \
> + | MCI_STATUS_CMD_DATATIMEOUT \
> + | MCI_STATUS_CMD_RXOVERRUN \
> + | MCI_STATUS_CMD_START_BIT_ERROR )
> +#define MCI_STATUS_WRITE_ERROR ( MCI_STATUS_CMD_DATACRCFAIL \
> + | MCI_STATUS_CMD_DATATIMEOUT \
> + | MCI_STATUS_CMD_TX_UNDERRUN )
> +#define MCI_STATUS_CMD_ERROR ( MCI_STATUS_CMD_CMDCRCFAIL \
> + | MCI_STATUS_CMD_CMDTIMEOUT \
> + | MCI_STATUS_CMD_START_BIT_ERROR )
> +
> +#define MCI_CLR_CMD_STATUS ( MCI_STATUS_CMD_RESPEND \
> + | MCI_STATUS_CMD_SENT \
> + | MCI_STATUS_CMD_ERROR )
> +
> +#define MCI_CLR_READ_STATUS ( MCI_STATUS_RXDONE \
> + | MCI_STATUS_READ_ERROR )
> +
> +#define MCI_CLR_WRITE_STATUS ( MCI_STATUS_TXDONE \
> + | MCI_STATUS_WRITE_ERROR )
> +
> +#define MCI_CLR_ALL_STATUS (BIT11 - 1)
> +
> +#define MCI_DATACTL_DISABLE_MASK 0xFE
> +#define MCI_DATACTL_ENABLE BIT0
> +#define MCI_DATACTL_CONT_TO_CARD 0
> +#define MCI_DATACTL_CARD_TO_CONT BIT1
> +#define MCI_DATACTL_BLOCK_TRANS 0
> +#define MCI_DATACTL_STREAM_TRANS BIT2
> +#define MCI_DATACTL_DMA_DISABLED 0
> +#define MCI_DATACTL_DMA_ENABLE BIT3
> +
> +#define INDX_MASK 0x3F
> +
> +#define MCI_CPSM_WAIT_RESPONSE BIT6
> +#define MCI_CPSM_LONG_RESPONSE BIT7
> +#define MCI_CPSM_LONG_INTERRUPT BIT8
> +#define MCI_CPSM_LONG_PENDING BIT9
> +#define MCI_CPSM_ENABLE BIT10
> +
> +#define MCI_TRACE(txt) DEBUG ((EFI_D_BLKIO, "ARM_MCI: " txt "\n"))
> +
> +EFI_STATUS
> +EFIAPI
> +MciGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +MciGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + );
> +
> +#endif
> diff --git a/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf
> new file mode 100644
> index 000000000000..3519de857ebb
> --- /dev/null
> +++ b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf
> @@ -0,0 +1,46 @@
> +#/** @file
> +# INF file for the MMC Host Protocol implementation for the ARM PrimeCell PL180.
> +#
> +# Copyright (c) 2011, ARM Limited. All rights reserved.
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#**/
> +
> +[Defines]
> + INF_VERSION = 0x00010005
> + BASE_NAME = PL180MciDxe
> + FILE_GUID = 09831032-6fa3-4484-af4f-0a000a8d3a82
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> +
> + ENTRY_POINT = PL180MciDxeInitialize
> +
> +[Sources.common]
> + PL180Mci.c
> +
> +[Packages]
> + EmbeddedPkg/EmbeddedPkg.dec
> + MdePkg/MdePkg.dec
> + Platform/ARM/VExpressPkg/ArmVExpressPkg.dec
> +
> +[LibraryClasses]
> + BaseLib
> + UefiLib
> + UefiDriverEntryPoint
> + BaseMemoryLib
> + ArmLib
> + IoLib
> + TimerLib
> +
> +[Protocols]
> + gEfiCpuArchProtocolGuid
> + gEfiDevicePathProtocolGuid
> + gEdkiiMmcHostProtocolGuid
> +
> +[Pcd]
> + gArmVExpressTokenSpaceGuid.PcdPL180SysMciRegAddress
> + gArmVExpressTokenSpaceGuid.PcdPL180MciBaseAddress
> +
> +[Depex]
> + gEfiCpuArchProtocolGuid
> --
> 2.17.1
>
next prev parent reply other threads:[~2020-04-29 21:51 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-04-29 18:47 [PATCH edk2-platforms 1/2] Silicon/TexasInstruments/Omap35xxPkg: switch to new MMC host protocol name Ard Biesheuvel
2020-04-29 18:47 ` [PATCH edk2-platforms 2/2] Platform/ARM/VExpressPkg: incorporate PL180 driver Ard Biesheuvel
2020-04-29 21:51 ` Leif Lindholm [this message]
2020-04-29 21:37 ` [PATCH edk2-platforms 1/2] Silicon/TexasInstruments/Omap35xxPkg: switch to new MMC host protocol name Leif Lindholm
2020-04-30 8:13 ` Ard Biesheuvel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200429215101.GO21486@vanye \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox