public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Ard Biesheuvel" <ard.biesheuvel@arm.com>
To: devel@edk2.groups.io
Cc: leif@nuviainc.com, Ard Biesheuvel <ard.biesheuvel@arm.com>
Subject: [PATCH edk2-platforms v2 1/2] Platform/ARM/VExpressPkg: incorporate PL180 driver
Date: Thu, 30 Apr 2020 10:25:17 +0200	[thread overview]
Message-ID: <20200430082518.26219-2-ard.biesheuvel@arm.com> (raw)
In-Reply-To: <20200430082518.26219-1-ard.biesheuvel@arm.com>

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>
---
 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      | 570 ++++++++++++++++++++
 Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.h      | 169 ++++++
 Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf |  53 ++
 8 files changed, 804 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..8526bb41600e
--- /dev/null
+++ b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.c
@@ -0,0 +1,570 @@
+/** @file
+  This file implement the MMC Host Protocol for the ARM PrimeCell PL180.
+
+  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 removed when no longer used.
+  New platforms should not use it, and no one should use this as
+  reference code for developing new drivers.
+
+  Copyright (c) 2011-2020, 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,
+                  &gEmbeddedMmcHostProtocolGuid,       &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..5d5acd603d00
--- /dev/null
+++ b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.h
@@ -0,0 +1,169 @@
+/** @file
+  Header for the MMC Host Protocol implementation for the ARM PrimeCell PL180.
+
+  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 removed when no longer used.
+  New platforms should not use it, and no one should use this as
+  reference code for developing new drivers.
+
+  Copyright (c) 2011-2020, 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..761f63b90fc4
--- /dev/null
+++ b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf
@@ -0,0 +1,53 @@
+#/** @file
+#  INF file for the MMC Host Protocol implementation for the ARM PrimeCell PL180.
+#
+#  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 removed when no longer used.
+#  New platforms should not use it, and no one should use this as
+#  reference code for developing new drivers.
+#
+#  Copyright (c) 2011-2020, 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
+  gEmbeddedMmcHostProtocolGuid
+
+[Pcd]
+  gArmVExpressTokenSpaceGuid.PcdPL180SysMciRegAddress
+  gArmVExpressTokenSpaceGuid.PcdPL180MciBaseAddress
+
+[Depex]
+  gEfiCpuArchProtocolGuid
-- 
2.17.1


  reply	other threads:[~2020-04-30  8:25 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-30  8:25 [PATCH edk2-platforms v2 0/2] move obsolete platform drivers out of core edk2 Ard Biesheuvel
2020-04-30  8:25 ` Ard Biesheuvel [this message]
2020-04-30 10:06   ` [edk2-devel] [PATCH edk2-platforms v2 1/2] Platform/ARM/VExpressPkg: incorporate PL180 driver Philippe Mathieu-Daudé
2020-04-30 10:47     ` Ard Biesheuvel
2020-04-30  8:25 ` [PATCH edk2-platforms v2 2/2] Platform/ARM/JunoPkg: incorporate SiI3132 SATA controller driver 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=20200430082518.26219-2-ard.biesheuvel@arm.com \
    --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