[edk2] [PATCH 1/3] Platform/NXP :Add Support for MMC Library

Vabhav posted 3 patches 7 years ago
[edk2] [PATCH 1/3] Platform/NXP :Add Support for MMC Library
Posted by Vabhav 7 years ago
This patch adds support for MMC library(MmcLib)to
provide functions which will be used by MMC Host
driver.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Meenakshi Aggarwal <meenakshi.aggarwal@nxp.com>
Signed-off-by: Vabhav <vabhav.sharma@nxp.com>
---
 Platform/NXP/Include/Library/MmcLib.h      | 138 +++++++
 Platform/NXP/Library/MmcLib/MmcInterface.c | 544 ++++++++++++++++++++++++++
 Platform/NXP/Library/MmcLib/MmcInternal.h  | 350 +++++++++++++++++
 Platform/NXP/Library/MmcLib/MmcLib.c       | 597 +++++++++++++++++++++++++++++
 Platform/NXP/Library/MmcLib/MmcLib.inf     |  39 ++
 5 files changed, 1668 insertions(+)
 create mode 100644 Platform/NXP/Include/Library/MmcLib.h
 create mode 100644 Platform/NXP/Library/MmcLib/MmcInterface.c
 create mode 100644 Platform/NXP/Library/MmcLib/MmcInternal.h
 create mode 100644 Platform/NXP/Library/MmcLib/MmcLib.c
 create mode 100644 Platform/NXP/Library/MmcLib/MmcLib.inf

diff --git a/Platform/NXP/Include/Library/MmcLib.h b/Platform/NXP/Include/Library/MmcLib.h
new file mode 100644
index 0000000..36941bc
--- /dev/null
+++ b/Platform/NXP/Include/Library/MmcLib.h
@@ -0,0 +1,138 @@
+/** @file
+  Header Defining The MMC Memory Controller Constants, Function Prototype, Structures Etc
+
+  Copyright 2017 NXP
+
+  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 __MMCLIB_H__
+#define __MMCLIB_H__
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+
+//define MMC_DEBUG to enable debug feature
+//#define MMC_DEBUG  1
+#ifdef MMC_DEBUG
+#define DEBUG_MSG(_Fmt,...)   DEBUG ((DEBUG_ERROR, "MMC: " _Fmt, ##__VA_ARGS__));
+#else
+#define DEBUG_MSG(_Fmt,...)
+#endif
+
+/**
+ MMC RESPONSE TYPE
+**/
+#define MMC_RSP_PRESENT  (1 << 0)
+#define MMC_RSP_136      (1 << 1)  // 136 Bit Response
+#define MMC_RSP_CRC      (1 << 2)  // Expect Valid Crc
+#define MMC_RSP_BUSY     (1 << 3)  // Card May Send Busy
+#define MMC_RSP_OPCODE   (1 << 4)  // Response Contains Opcode
+
+#define MMC_RSP_NONE     (0)
+#define MMC_RSP_R1       (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+#define MMC_RSP_R1b      (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE| \
+                         MMC_RSP_BUSY)
+#define MMC_RSP_R2       (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
+#define MMC_RSP_R3       (MMC_RSP_PRESENT)
+#define MMC_RSP_R4       (MMC_RSP_PRESENT)
+#define MMC_RSP_R5       (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+#define MMC_RSP_R6       (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+#define MMC_RSP_R7       (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+
+/**
+  Find most significant set
+
+  @param   X  word to search
+
+  @retval most significant set bit number
+
+**/
+static inline INT32 GenericFls (INT32 X)
+{
+
+  INT32 I = 31;
+
+  for (I=31; I >= 0; I--) {
+    if(X & (1<<I))
+      return (I+1);
+  }
+
+  return 0;
+}
+
+struct SdCmd {
+  UINT16 CmdIdx;
+  UINT32 RespType;
+  UINT32 CmdArg;
+};
+
+EFI_STATUS
+MmcInitialize (
+  VOID
+  );
+
+EFI_STATUS
+RcvResp (
+  IN  UINT32  RespType,
+  OUT UINT32* Response,
+  IN  UINT8   Data
+  );
+
+BOOLEAN
+DetectCardPresence (
+  IN VOID
+  );
+
+BOOLEAN
+IsCardReadOnly (
+  IN VOID
+  );
+
+struct SdData {
+  UINT32 Flags;
+  UINT32 Blocks;
+  UINT32 Blocksize;
+  VOID   *Addr;
+};
+
+EFI_STATUS
+SendCmd (
+  IN  struct SdCmd  *Cmd,
+  IN  struct SdData *Data
+  );
+
+VOID
+SetIos (
+  IN  UINT32 BusClockFreq,
+  IN  UINT32 BusWidth,
+  IN  UINT32 TimingMode
+  );
+
+EFI_STATUS
+WriteBlock (
+  IN UINTN        Offset,
+  IN UINTN        Length,
+  IN UINT32*      Buffer,
+  IN struct SdCmd Cmd
+  );
+
+EFI_STATUS
+ReadBlock (
+  IN UINTN        Offset,
+  IN UINTN        Length,
+  OUT UINT32*     Buffer,
+  IN struct SdCmd Cmd
+  );
+
+extern UINT64 GetSdxcFrequency();
+
+#endif
diff --git a/Platform/NXP/Library/MmcLib/MmcInterface.c b/Platform/NXP/Library/MmcLib/MmcInterface.c
new file mode 100644
index 0000000..1b8ce25
--- /dev/null
+++ b/Platform/NXP/Library/MmcLib/MmcInterface.c
@@ -0,0 +1,544 @@
+/** @MmcInterface.c
+
+  Functions for providing Library interface APIs.
+
+  Copyright 2017 NXP
+
+  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/MemLibInternals.h>
+#include <Library/BeIoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/MmcLib.h>
+#include <Library/TimerLib.h>
+
+#include "MmcInternal.h"
+
+struct Mmc *mMmc;
+
+/**
+  Function to detect card presence by checking host controller
+  present state register
+
+  @retval  Returns the card presence as TRUE/FALSE
+
+**/
+BOOLEAN
+DetectCardPresence (
+  IN VOID
+  )
+{
+  struct SdxcRegs *Regs;
+  INT32 Timeout;
+
+  Regs = (VOID *)PcdGet64 (PcdSdxcBaseAddr);
+  Timeout = 1000;
+
+  while (!(MmcRead ((UINTN)&Regs->Prsstat) & PRSSTATE_CINS) && --Timeout)
+    MicroSecondDelay (10);
+
+  if (Timeout > 0) {
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+/**
+  Function to check whether card is read only by verifying host controller
+  present state register
+
+  @retval  Returns the card read only or not as TRUE/FALSE
+
+**/
+BOOLEAN
+IsCardReadOnly (
+  IN VOID
+  )
+{
+  struct SdxcRegs *Regs;
+
+  Regs = (VOID *)PcdGet64 (PcdSdxcBaseAddr);
+
+  if (MmcRead ((UINTN)&Regs->Prsstat) & PRSSTATE_WPSPL) {
+    return FALSE;
+  } else {
+    DEBUG ((DEBUG_ERROR, "SD/MMC : Write Protection PIN is high\n"));
+    return TRUE;
+  }
+}
+
+/**
+  Function to prepare state(Wait for bus,Set up host controller
+  data,Transfer type)  for command to be send
+
+  @param  Cmd  Command to be used
+  @param  Data Data with command
+
+  @retval  Returns the command status
+
+**/
+EFI_STATUS
+SendCmd (
+  IN  struct SdCmd *Cmd,
+  IN  struct SdData *Data
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      Xfertype;
+  UINT32      Irqstat;
+  INT32       Timeout;
+  struct SdxcRegs *Regs;
+
+  Status = 0;
+  Timeout = 100000;
+  Regs = (VOID *)PcdGet64 (PcdSdxcBaseAddr);
+
+  DEBUG_MSG ("0x%x : Cmd.Id %d, Arg 0x%x SdCmd.RespType 0x%x \n",
+              Regs, Cmd->CmdIdx, Cmd->CmdArg, Cmd->RespType);
+
+  MmcWrite ((UINTN)&Regs->Irqstat, 0xFFFFFFFF);
+
+  asm ("Dmb :");
+
+  // Wait for The Bus To Be Idle
+  while ((MmcRead ((UINTN)&Regs->Prsstat) & PRSSTATE_CICHB) ||
+        (MmcRead ((UINTN)&Regs->Prsstat) & PRSSTATE_CIDHB))
+    NanoSecondDelay (10);
+
+  // Wait for data line to be active
+  while (MmcRead ((UINTN)&Regs->Prsstat) & PRSSTATE_DLA)
+    NanoSecondDelay (10);
+
+  // Wait Before The Next Command
+  MicroSecondDelay (1000);
+
+  // Set Up for A Data Transfer if We Have One
+  if (Data) {
+    Status = SdxcSetupData (Data);
+    if (Status) {
+      return Status;
+    }
+  }
+
+  // Figure Out The Transfer Arguments
+  Xfertype = SdxcXfertype (Cmd, Data);
+
+  // Mask All Irqs
+  MmcWrite ((UINTN)&Regs->Irqsigen, 0);
+
+  // Send The Command
+  MmcWrite ((UINTN)&Regs->CmdArg, Cmd->CmdArg);
+  MmcWrite ((UINTN)&Regs->Xfertype, Xfertype);
+
+  // Wait for The Command To Complete
+  Timeout = 100000;
+  while ((!(MmcRead ((UINTN)&Regs->Irqstat) & (IRQSTATE_CC | IRQSTATE_CTOE)))
+        && Timeout--);
+
+  if (Timeout <= 0) {
+    DEBUG ((DEBUG_ERROR, "Command not completed %d\n", Cmd->CmdIdx));
+    return EFI_TIMEOUT;
+  }
+
+  Irqstat = MmcRead ((UINTN)&Regs->Irqstat);
+
+  if (Irqstat & CMD_ERR) {
+    Status = EFI_DEVICE_ERROR;
+    DEBUG ((DEBUG_ERROR, "SdxcSendCmd: Device Error(0x%x) for Cmd(%d)\n",
+                Irqstat, Cmd->CmdIdx));
+    goto Out;
+  }
+
+  if (Irqstat & IRQSTATE_CTOE) {
+    Status = EFI_TIMEOUT;
+    DEBUG ((DEBUG_ERROR, "SdxcSendCmd: Timeout for Cmd(%d)\n", Cmd->CmdIdx));
+    goto Out;
+  }
+
+Out:
+  if (Status) {
+    ResetCmdFailedData (Regs, (Data != NULL));
+  }
+  else {
+    MmcWrite ((UINTN)&Regs->Irqstat, 0xFFFFFFFF);
+  }
+  return Status;
+
+}
+
+/**
+  Function to receive command response
+
+  @param  RespType Type of response
+  @param  Data     Data of response
+
+  @param  Response Pointer to response buffer
+
+  @retval  Returns the command response status
+
+**/
+EFI_STATUS
+RcvResp (
+  IN   UINT32   RespType,
+  OUT  UINT32*  Response,
+  IN   UINT8    Data
+  )
+{
+  if (RespType != 0xFF) {
+    INT32 Timeout;
+    struct SdxcRegs *Regs;
+
+    Timeout = 25000;
+    Regs = (VOID *)PcdGet64(PcdSdxcBaseAddr);
+
+    // Workaround for SDXC Errata ENGcm03648
+    if (!Data && (RespType & MMC_RSP_BUSY)) {
+      Timeout = 25000;
+
+      // Poll On DATA0 Line for Cmd With Busy Signal for 250 Ms
+      while (Timeout > 0 && !(MmcRead ((UINTN)&Regs->Prsstat) &
+            PRSSTATE_DAT0)) {
+        MicroSecondDelay (100);
+        Timeout--;
+      }
+
+      if (Timeout <= 0) {
+        DEBUG ((DEBUG_ERROR, "Timeout Waiting for DAT0 To Go High!\n"));
+        ResetCmdFailedData (Regs, Data);
+        return EFI_TIMEOUT;
+      }
+    }
+
+    // Copy The Response To The Response Buffer
+    if (RespType & MMC_RSP_136) {
+      UINT32 Rspns3, Rspns2, Rspns1, Rspns0;
+
+      Rspns3 = MmcRead ((UINTN)&Regs->Rspns3);
+      Rspns2 = MmcRead ((UINTN)&Regs->Rspns2);
+      Rspns1 = MmcRead ((UINTN)&Regs->Rspns1);
+      Rspns0 = MmcRead ((UINTN)&Regs->Rspns0);
+      Response[3] = (Rspns3 << 8) | (Rspns2 >> 24);
+      Response[2] = (Rspns2 << 8) | (Rspns1 >> 24);
+      Response[1] = (Rspns1 << 8) | (Rspns0 >> 24);
+      Response[0] = (Rspns0 << 8);
+      DEBUG_MSG ("RESP : 0x%x : 0x%x : 0x%x : 0x%x \n",
+                 Response[0], Response[1], Response[2], Response[3]);
+    } else {
+      Response[0] = MmcRead ((UINTN)&Regs->Rspns0);
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Function to prepare command transfer
+
+  @param  Flags  Flags for transferType of response
+  @param  Length Length of block
+  @param  Cmd    Pointer to command structure
+
+  @retval  Returns the command status
+
+**/
+EFI_STATUS
+PrepareTransfer (
+  UINT32        Flags,
+  IN UINTN      Length,
+  IN VOID*      Buffer,
+  IN struct SdCmd   *Cmd
+  )
+{
+  EFI_STATUS Status;
+  struct SdData Data;
+
+  Data.Flags = Flags;
+
+  if (Length > MMC_MAX_BLOCK_LEN) {
+    Data.Blocks = (Length / MMC_MAX_BLOCK_LEN) +
+            ((Length % MMC_MAX_BLOCK_LEN) ? 1 : 0);
+    Data.Blocksize = MMC_MAX_BLOCK_LEN;
+  } else {
+    Data.Blocks = 1;
+    Data.Blocksize = Length;
+  }
+
+  Data.Addr = Buffer;
+
+  Status = SendCmd (Cmd, &Data);
+
+  return Status;
+}
+
+/**
+  Function to Read MMC Block
+
+  @param  Offset Offset to read from
+  @param  Length Length of block
+  @param  Cmd    Pointer to command structure
+
+  @param  Buffer Pointer to buffer for data read
+
+  @retval  Returns the read block command status
+
+**/
+EFI_STATUS
+ReadBlock (
+  IN UINTN      Offset,
+  IN UINTN      Length,
+  OUT UINT32*   Buffer,
+  IN struct SdCmd      Cmd
+  )
+{
+  EFI_STATUS Status;
+  struct DmaData DmaData;
+  VOID * Temp;
+
+  Temp = NULL;
+
+  DmaData.Bytes = Length;
+  DmaData.MapOperation = MapOperationBusMasterRead;
+
+  Temp = GetDmaBuffer (&DmaData);
+  if (Temp == NULL) {
+    DEBUG ((DEBUG_ERROR,"Mmc Read : Failed to get DMA buffer \n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = PrepareTransfer (MMC_DATA_READ, Length, Temp, &Cmd);
+  if (Status) {
+    DEBUG((DEBUG_ERROR,"Mmc Read: Fail to setup controller 0x%x \n", Status));
+    FreeDmaBuffer (&DmaData);
+    return Status;
+  }
+
+  Status = Transfer ();
+  if (Status) {
+    DEBUG ((DEBUG_ERROR,"Mmc Read Failed (0x%x) \n", Status));
+    FreeDmaBuffer (&DmaData);
+    return Status;
+  }
+
+  InternalMemCopyMem (Buffer, Temp , DmaData.Bytes);
+
+  Status = FreeDmaBuffer (&DmaData);
+  if (Status) {
+    DEBUG ((DEBUG_ERROR,"Mmc Read : Failed to release DMA buffer \n"));
+    return Status;
+  }
+
+  return Status;
+}
+
+/**
+  Function to Write MMC Block
+
+  @param  Offset Offset to write to
+  @param  Length Length of block
+  @param  Buffer Pointer to buffer for data to be written
+  @param  Cmd    Pointer to command structure
+
+  @retval  Returns the write block command status
+
+**/
+EFI_STATUS
+WriteBlock (
+  IN UINTN      Offset,
+  IN UINTN      Length,
+  IN UINT32*    Buffer,
+  IN struct SdCmd      Cmd
+  )
+{
+  EFI_STATUS  Status;
+  struct DmaData DmaData;
+  VOID * Temp;
+
+  Temp = NULL;
+
+  DmaData.Bytes = Length;
+  DmaData.MapOperation = MapOperationBusMasterWrite;
+
+  Temp = GetDmaBuffer (&DmaData);
+  if (Temp == NULL) {
+    DEBUG ((DEBUG_ERROR,"Mmc Write : Failed to get DMA buffer \n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  InternalMemCopyMem (Temp, Buffer, DmaData.Bytes);
+
+  Status = PrepareTransfer (MMC_DATA_WRITE, Length, Temp, &Cmd);
+  if (Status) {
+    DEBUG ((DEBUG_ERROR,"Mmc Write: Fail to setup controller 0x%x \n", Status));
+    FreeDmaBuffer (&DmaData);
+    return Status;
+  }
+
+  Status = Transfer ();
+  if (Status) {
+    DEBUG((DEBUG_ERROR,"Mmc Write Failed (0x%x) \n", Status));
+    FreeDmaBuffer (&DmaData);
+    return Status;
+  }
+
+  Status = FreeDmaBuffer (&DmaData);
+  if (Status) {
+    DEBUG ((DEBUG_ERROR,"Mmc Write : Failed to release DMA buffer \n"));
+    return Status;
+  }
+
+  return Status;
+}
+
+/**
+  Function to Initialize MMC
+
+  // Set Bus width
+  // Set protocol register
+
+  @retval  Returns the initialization status
+
+**/
+EFI_STATUS
+InitMmc (
+  IN  VOID
+  )
+{
+  EFI_STATUS Status;
+  struct SdxcRegs *Regs;
+
+  Regs = (VOID *)PcdGet64 (PcdSdxcBaseAddr);
+
+  Status = SdxcInit (mMmc);
+  if (Status) {
+    return Status;
+  }
+
+  mMmc->DdrMode = 0;
+  SdxcSetBusWidth (mMmc, 1);
+
+  MmcAnd ((UINTN)&Regs->Proctl, ~PRCTL_BE);
+
+  return Status;
+}
+
+/**
+  Function to set MMC clock speed
+
+  @param  BusClockFreq Bus clock frequency to be set Offset to write to
+  @param  BusWidth     Bus width
+  @param  TimingMode   Timing mode to be set
+
+**/
+VOID
+SetIos (
+  IN  UINT32   BusClockFreq,
+  IN  UINT32   BusWidth,
+  IN  UINT32   TimingMode
+  )
+{
+  struct SdxcRegs *Regs;
+
+  Regs = (VOID *)PcdGet64 (PcdSdxcBaseAddr);
+
+  DEBUG_MSG ("BusClockFreq %d, BusWidth %d\n", BusClockFreq, BusWidth);
+
+  // Set The Clock Speed
+  if (BusClockFreq) {
+    SetSysctl (BusClockFreq);
+  }
+
+  // Set The Bus Width
+  if (BusWidth) {
+    MmcAnd ((UINTN)&Regs->Proctl, ~(PRCTL_DTW_4 | PRCTL_DTW_8));
+  }
+
+  if (BusWidth == 4) {
+    MmcOr ((UINTN)&Regs->Proctl, PRCTL_DTW_4);
+  }
+  else if (BusWidth == 8) {
+    MmcOr ((UINTN)&Regs->Proctl, PRCTL_DTW_8);
+  }
+}
+
+/**
+  Helper Function to initialize MMC
+
+  // Reset MMC controller
+  // Set host voltage capabilities
+  // Set MMC clock
+
+**/
+EFI_STATUS
+MmcInitialize (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  struct SdxcRegs *Regs;
+
+  UINT32 Caps, VoltageCaps;
+  UINTN Voltages;
+
+  Regs = (VOID *)PcdGet64 (PcdSdxcBaseAddr);
+
+  // First Reset The SDXC Controller
+  SdxcReset (Regs);
+
+  VoltageCaps = 0;
+  Caps = MmcRead ((UINTN)&Regs->Hostcapblt);
+
+  Caps = Caps | SDXC_HOSTCAPBLT_VS33;
+
+  if (Caps & SDXC_HOSTCAPBLT_VS30) {
+    VoltageCaps |= MMC_VDD_29_30 | MMC_VDD_30_31;
+  }
+  if (Caps & SDXC_HOSTCAPBLT_VS33) {
+    VoltageCaps |= MMC_VDD_32_33 | MMC_VDD_33_34;
+  }
+  if (Caps & SDXC_HOSTCAPBLT_VS18) {
+    VoltageCaps |= MMC_VDD_165_195;
+  }
+
+  Voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+  if ((Voltages & VoltageCaps) == 0) {
+    DEBUG ((DEBUG_ERROR, "Voltage Not Supported By Controller\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  mMmc = (struct Mmc*)AllocatePool (sizeof (struct Mmc));
+  if (mMmc == NULL) {
+    DEBUG ((DEBUG_ERROR, "Memory Allocation failed for gMMC\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  InternalMemZeroMem (mMmc, sizeof (struct Mmc));
+
+  mMmc->SdhcClk = GetSdxcFrequency ();
+
+  mMmc->HostCaps = MMC_MODE_4_BIT | MMC_MODE_8_BIT | MMC_MODE_HC;
+
+  if (Caps & SDXC_HOSTCAPBLT_HSS) {
+    mMmc->HostCaps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
+  }
+
+  mMmc->FMin = MIN_CLK_FREQUENCY;
+  mMmc->FMax = MIN ((UINT32)mMmc->SdhcClk, MAX_CLK_FREQUENCY);
+
+  Status = InitMmc ();
+  if (Status != EFI_SUCCESS) {
+      DEBUG ((DEBUG_ERROR,"Failed to initialize MMC\n"));
+      return Status;
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/Platform/NXP/Library/MmcLib/MmcInternal.h b/Platform/NXP/Library/MmcLib/MmcInternal.h
new file mode 100644
index 0000000..0e56764
--- /dev/null
+++ b/Platform/NXP/Library/MmcLib/MmcInternal.h
@@ -0,0 +1,350 @@
+/** @file
+  Header Defining The MMC Memory Controller Constants, Function Prototype, Structures Etc
+
+  Copyright 2017 NXP
+
+  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 __MMC_INTERNAL_H__
+#define __MMC_INTERNAL_H__
+
+#include <Library/DmaLib.h>
+
+#define MIN_CLK_FREQUENCY          400000
+#define MAX_CLK_FREQUENCY          52000000
+
+#define ENABLE_CACHE_SNOOPING      0x00000040
+#define CMD_STOP_TRANSMISSION      12
+/**
+  Pre Div factor for DDR mode
+**/
+#define DIV_2  2
+#define DIV_1  1
+
+/**
+  SDXC-Specific Constants
+**/
+#define SYSCTL              0x0002e02c
+#define SYSCTL_INITA        0x08000000
+#define SYSCTL_TIMEOUT_MASK 0x000f0000
+#define SYSCTL_CLOCK_MASK   0x0000fff0
+#define SYSCTL_CKEN         0x00000008
+#define SYSCTL_PEREN        0x00000004
+#define SYSCTL_HCKEN        0x00000002
+#define SYSCTL_IPGEN        0x00000001
+#define SYSCTL_RSTA         0x01000000
+#define SYSCTL_RSTC         0x02000000
+#define SYSCTL_RSTD         0x04000000
+
+/**
+  Host Capabilities
+**/
+#define SDXC_HOSTCAPBLT_VS18      0x04000000
+#define SDXC_HOSTCAPBLT_VS30      0x02000000
+#define SDXC_HOSTCAPBLT_VS33      0x01000000
+#define SDXC_HOSTCAPBLT_SRS       0x00800000
+#define SDXC_HOSTCAPBLT_DMAS      0x00400000
+#define SDXC_HOSTCAPBLT_HSS       0x00200000
+
+/**
+  VDD Voltage Range
+**/
+#define MMC_VDD_165_195            0x00000080    // VDD Voltage 1.65 - 1.95
+#define MMC_VDD_20_21              0x00000100    // VDD Voltage 2.0 ~ 2.1
+#define MMC_VDD_21_22              0x00000200    // VDD Voltage 2.1 ~ 2.2
+#define MMC_VDD_22_23              0x00000400    // VDD Voltage 2.2 ~ 2.3
+#define MMC_VDD_23_24              0x00000800    // VDD Voltage 2.3 ~ 2.4
+#define MMC_VDD_24_25              0x00001000    // VDD Voltage 2.4 ~ 2.5
+#define MMC_VDD_25_26              0x00002000    // VDD Voltage 2.5 ~ 2.6
+#define MMC_VDD_26_27              0x00004000    // VDD Voltage 2.6 ~ 2.7
+#define MMC_VDD_27_28              0x00008000    // VDD Voltage 2.7 ~ 2.8
+#define MMC_VDD_28_29              0x00010000    // VDD Voltage 2.8 ~ 2.9
+#define MMC_VDD_29_30              0x00020000    // VDD Voltage 2.9 ~ 3.0
+#define MMC_VDD_30_31              0x00040000    // VDD Voltage 3.0 ~ 3.1
+#define MMC_VDD_31_32              0x00080000    // VDD Voltage 3.1 ~ 3.2
+#define MMC_VDD_32_33              0x00100000    // VDD Voltage 3.2 ~ 3.3
+#define MMC_VDD_33_34              0x00200000    // VDD Voltage 3.3 ~ 3.4
+#define MMC_VDD_34_35              0x00400000    // VDD Voltage 3.4 ~ 3.5
+#define MMC_VDD_35_36              0x00800000    // VDD Voltage 3.5 ~ 3.6
+
+/**
+  MMC Operating Modes
+**/
+#define MMC_MODE_HS         (1 << 0)
+#define MMC_MODE_HS_52MHz   (1 << 1)
+#define MMC_MODE_4_BIT      (1 << 2)
+#define MMC_MODE_8_BIT      (1 << 3)
+#define MMC_MODE_SPI        (1 << 4)
+#define MMC_MODE_HC         (1 << 5)
+#define MMC_MODE_DDR_52MHz  (1 << 6)
+
+#define MMC_DATA_READ        1
+#define MMC_DATA_WRITE       2
+
+/**
+  Maximum Block Size for MMC
+**/
+#define MMC_MAX_BLOCK_LEN   512
+
+#define WML_RD_MAX      0x10
+#define WML_WR_MAX      0x80
+#define WML_RD_MAX_VAL  0x00
+#define WML_WR_MAX_VAL  0x80
+#define WML_RD_MASK     0xff
+#define WML_WR_MASK     0xff0000
+
+#define XFERTYPE                    0x0002e00c
+#define XFERTYPE_CMD(X)             ((X & 0x3f) << 24)
+#define XFERTYPE_CMDTYP_NORMAL      0x0
+#define XFERTYPE_CMDTYP_SUSPEND     0x00400000
+#define XFERTYPE_CMDTYP_RESUME      0x00800000
+#define XFERTYPE_CMDTYP_ABORT       0x00c00000
+#define XFERTYPE_DPSEL              0x00200000
+#define XFERTYPE_CICEN              0x00100000
+#define XFERTYPE_CCCEN              0x00080000
+#define XFERTYPE_RSPTYP_NONE        0
+#define XFERTYPE_RSPTYP_136         0x00010000
+#define XFERTYPE_RSPTYP_48          0x00020000
+#define XFERTYPE_RSPTYP_48_BUSY     0x00030000
+#define XFERTYPE_MSBSEL             0x00000020
+#define XFERTYPE_DTDSEL             0x00000010
+#define XFERTYPE_AC12EN             0x00000004
+#define XFERTYPE_BCEN               0x00000002
+#define XFERTYPE_DMAEN              0x00000001
+
+/**
+  IRQSTAT bits
+**/
+#define IRQSTAT              (0x0002e030)
+#define IRQSTATE_DMAE        (0x10000000)
+#define IRQSTATE_AC12E       (0x01000000)
+#define IRQSTATE_DEBE        (0x00400000)
+#define IRQSTATE_DCE         (0x00200000)
+#define IRQSTATE_DTOE        (0x00100000)
+#define IRQSTATE_CIE         (0x00080000)
+#define IRQSTATE_CEBE        (0x00040000)
+#define IRQSTATE_CCE         (0x00020000)
+#define IRQSTATE_CTOE        (0x00010000)
+#define IRQSTATE_CINT        (0x00000100)
+#define IRQSTATE_CRM         (0x00000080)
+#define IRQSTATE_CINS        (0x00000040)
+#define IRQSTATE_BRR         (0x00000020)
+#define IRQSTATE_BWR         (0x00000010)
+#define IRQSTATE_DINT        (0x00000008)
+#define IRQSTATE_BGE         (0x00000004)
+#define IRQSTATE_TC          (0x00000002)
+#define IRQSTATE_CC          (0x00000001)
+
+#define CMD_ERR             (IRQSTATE_CIE | IRQSTATE_CEBE | IRQSTATE_CCE)
+#define DATA_ERR            (IRQSTATE_DEBE | IRQSTATE_DCE | IRQSTATE_DTOE | \
+                            IRQSTATE_DMAE)
+#define DATA_COMPLETE       (IRQSTATE_TC | IRQSTATE_DINT)
+
+#define IRQSTATE_EN           (0x0002e034)
+#define IRQSTATE_EN_DMAE      (0x10000000)
+#define IRQSTATE_EN_AC12E     (0x01000000)
+#define IRQSTATE_EN_DEBE      (0x00400000)
+#define IRQSTATE_EN_DCE       (0x00200000)
+#define IRQSTATE_EN_DTOE      (0x00100000)
+#define IRQSTATE_EN_CIE       (0x00080000)
+#define IRQSTATE_EN_CEBE      (0x00040000)
+#define IRQSTATE_EN_CCE       (0x00020000)
+#define IRQSTATE_EN_CTOE      (0x00010000)
+#define IRQSTATE_EN_CINT      (0x00000100)
+#define IRQSTATE_EN_CRM       (0x00000080)
+#define IRQSTATE_EN_CINS      (0x00000040)
+#define IRQSTATE_EN_BRR       (0x00000020)
+#define IRQSTATE_EN_BWR       (0x00000010)
+#define IRQSTATE_EN_DINT      (0x00000008)
+#define IRQSTATE_EN_BGE       (0x00000004)
+#define IRQSTATE_EN_TC        (0x00000002)
+#define IRQSTATE_EN_CC        (0x00000001)
+
+#define PRSSTATE             (0x0002e024)
+#define PRSSTATE_DAT0        (0x01000000)
+#define PRSSTATE_CLSL        (0x00800000)
+#define PRSSTATE_WPSPL       (0x00080000)
+#define PRSSTATE_CDPL        (0x00040000)
+#define PRSSTATE_CINS        (0x00010000)
+#define PRSSTATE_BREN        (0x00000800)
+#define PRSSTATE_BWEN        (0x00000400)
+#define PRSSTATE_DLA         (0x00000004)
+#define PRSSTATE_CICHB       (0x00000002)
+#define PRSSTATE_CIDHB       (0x00000001)
+
+#define PRCTL              0x0002e028
+#define PRCTL_INIT         0x00000020
+#define PRCTL_DTW_4        0x00000002
+#define PRCTL_DTW_8        0x00000004
+#define PRCTL_BE           0x00000030
+
+struct SdxcRegs {
+       UINT32    Dsaddr;      // SDMA System Address Register
+       UINT32    Blkattr;     // Block Attributes Register
+       UINT32    CmdArg;      // Command Argument Register
+       UINT32    Xfertype;     // Transfer Type Register
+       UINT32    Rspns0;     // Command Response 0 Register
+       UINT32    Rspns1;     // Command Response 1 Register
+       UINT32    Rspns2;     // Command Response 2 Register
+       UINT32    Rspns3;     // Command Response 3 Register
+       UINT32    Datport;     // Buffer Data Port Register
+       UINT32    Prsstat;     // Present State Register
+       UINT32    Proctl;      // Protocol Control Register
+       UINT32    Sysctl;      // System Control Register
+       UINT32    Irqstat;     // Interrupt Status Register
+       UINT32    Irqstaten;   // Interrupt Status Enable Register
+       UINT32    Irqsigen;    // Interrupt Signal Enable Register
+       UINT32    Autoc12err;  // Auto CMD Error Status Register
+       UINT32    Hostcapblt;  // Host Controller Capabilities Register
+       UINT32    Wml;         // Watermark Level Register
+       UINT32    Mixctrl;     // for USDHC
+       CHAR8     Reserved1[4]; // Reserved
+       UINT32    Fevt;        // Force Event Register
+       UINT32    Admaes;      // ADMA Error Status Register
+       UINT32    Adsaddr;     // ADMA System Address Register
+       CHAR8     Reserved2[100];// Reserved
+       UINT32    VendorSpec;  //Vendor Specific Register
+       CHAR8     Reserved3[56];// Reserved
+       UINT32    Hostver;     // Host Controller Version Register
+       CHAR8     Reserved4[4];// Reserved
+       UINT32    Dmaerraddr;  // DMA Error Address Register
+       CHAR8     Reserved5[4];// Reserved
+       UINT32    Dmaerrattr;  // DMA Error Attribute Register
+       CHAR8     Reserved6[4];// Reserved
+       UINT32    Hostcapblt2; // Host Controller Capabilities Register 2
+       CHAR8     Reserved7[8];// Reserved
+       UINT32    Tcr;         // Tuning Control Register
+       CHAR8     Reserved8[28];// Reserved
+       UINT32    Sddirctl;    // SD Direction Control Register
+       CHAR8     Reserved9[712];// Reserved
+       UINT32    Scr;         // SDXC Control Register
+};
+
+struct DmaData {
+  VOID *DmaAddr;
+  UINTN Bytes;
+  VOID *Mapping;
+  DMA_MAP_OPERATION MapOperation;
+};
+
+struct Mmc {
+       UINT32 SdhcClk;
+       UINT32 HostCaps;
+       UINT32 HasInit;
+       UINT32 FMin;
+       UINT32 FMax;
+       UINT32 BusWidth;
+       UINT32 Clock;
+       UINT32 CardCaps;
+       INT32  DdrMode;
+};
+
+VOID
+SdxcSetClock (
+  IN  struct Mmc *Mmc,
+  IN  UINT32 Clock
+  );
+
+EFI_STATUS
+SdxcInit (
+  IN  struct Mmc *Mmc
+  );
+
+EFI_STATUS
+SdxcGoIdle (
+  IN  struct Mmc *Mmc
+  );
+
+VOID
+SdxcReset (
+  IN struct SdxcRegs *Regs
+  );
+
+VOID *
+GetDmaBuffer (
+  IN struct DmaData *DmaData
+  );
+
+EFI_STATUS
+FreeDmaBuffer (
+  IN struct DmaData *DmaData
+  );
+
+EFI_STATUS
+SdxcSetupData (
+  IN  struct SdData *Data
+  );
+
+UINT32
+SdxcXfertype (
+  IN  struct SdCmd *Cmd,
+  IN  struct SdData *Data
+  );
+
+VOID
+ResetCmdFailedData (
+  IN  struct SdxcRegs *Regs,
+  IN  UINT8  Data
+  );
+
+VOID
+SdxcSetBusWidth (
+  IN  struct Mmc *Mmc,
+  IN  UINT32 BWidth
+  );
+
+EFI_STATUS
+Transfer (
+  IN  VOID
+  );
+
+VOID
+SetSysctl (
+  UINT32 Clock
+  );
+
+UINT32
+EFIAPI
+MmcRead (
+  IN  UINTN     Address
+  );
+
+UINT32
+EFIAPI
+MmcWrite (
+  IN  UINTN     Address,
+  IN  UINT32    Value
+  );
+
+UINT32
+EFIAPI
+MmcAndThenOr (
+  IN  UINTN     Address,
+  IN  UINT32    AndData,
+  IN  UINT32    OrData
+  );
+
+UINT32
+EFIAPI
+MmcOr (
+  IN  UINTN     Address,
+  IN  UINT32    OrData
+  );
+
+UINT32
+EFIAPI
+MmcAnd (
+  IN  UINTN     Address,
+  IN  UINT32    AndData
+  );
+
+#endif
diff --git a/Platform/NXP/Library/MmcLib/MmcLib.c b/Platform/NXP/Library/MmcLib/MmcLib.c
new file mode 100644
index 0000000..83b12c9
--- /dev/null
+++ b/Platform/NXP/Library/MmcLib/MmcLib.c
@@ -0,0 +1,597 @@
+/**@file
+
+  Copyright 2017 NXP
+
+  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/BeIoLib.h>
+#include <Library/IoLib.h>
+#include <Library/MmcLib.h>
+#include <Library/TimerLib.h>
+#include "MmcInternal.h"
+
+extern struct Mmc *mMmc;
+
+/**
+  Function to read from MMC depending upon pcd
+
+  @param   Address  MMC register to read
+
+  @retval  Read Value from register
+
+**/
+UINT32
+EFIAPI
+MmcRead (
+  IN  UINTN     Address
+  )
+{
+  if (FixedPcdGetBool (PcdMmcBigEndian)) {
+    return BeMmioRead32(Address);
+  } else {
+    return MmioRead32 (Address);
+  }
+}
+
+/**
+  Function to write on MMC depeding upon pcd
+
+  @param   Address  MMC register to write
+
+**/
+UINT32
+EFIAPI
+MmcWrite (
+  IN  UINTN     Address,
+  IN  UINT32    Value
+  )
+{
+  if (FixedPcdGetBool (PcdMmcBigEndian)) {
+    return BeMmioWrite32 (Address, Value);
+  } else {
+    return MmioWrite32 (Address, Value);
+  }
+}
+
+/**
+  Function to call MmioAndThenOr32 depending upon pcd
+
+  @param   Address MMC register
+  @param   AndData The value to AND with the read value from the MMC register
+  @param   OrData  The value to OR with the result of the AND operation.
+
+  @retval  Value written back to register
+
+**/
+UINT32
+EFIAPI
+MmcAndThenOr (
+  IN  UINTN     Address,
+  IN  UINT32    AndData,
+  IN  UINT32    OrData
+  )
+{
+  if (FixedPcdGetBool (PcdMmcBigEndian)) {
+    return BeMmioAndThenOr32 (Address, AndData, OrData);
+  } else {
+    return MmioAndThenOr32 (Address, AndData, OrData);
+  }
+}
+
+/**
+  Function to call MmioOr32 depending upon pcd
+
+  @param   Address MMC register
+  @param   OrData  The value to OR with the result of the AND operation.
+
+  @retval  Value written back to register
+
+**/
+UINT32
+EFIAPI
+MmcOr (
+  IN  UINTN     Address,
+  IN  UINT32    OrData
+  )
+{
+  if (FixedPcdGetBool (PcdMmcBigEndian)) {
+    return BeMmioOr32 (Address, OrData);
+  } else {
+    return MmioOr32 (Address, OrData);
+  }
+}
+
+/**
+  Function to call MmioAnd32 depending upon pcd
+
+  @param   Address MMC register
+  @param   AndData The value to AND with the read value from the MMC register
+
+  @retval  Value written back to register
+
+**/
+UINT32
+EFIAPI
+MmcAnd (
+  IN  UINTN     Address,
+  IN  UINT32    AndData
+  )
+{
+  if (FixedPcdGetBool (PcdMmcBigEndian)) {
+    return BeMmioAnd32 (Address, AndData);
+  } else {
+    return MmioAnd32 (Address, AndData);
+  }
+}
+
+/**
+  Function to Dump MMC Controller register
+**/
+VOID
+DumpMmcRegs (
+  IN VOID
+  )
+{
+  struct SdxcRegs *Regs;
+
+  Regs = (VOID *)PcdGet64(PcdSdxcBaseAddr);
+
+  DEBUG ((DEBUG_ERROR, "Dsaddr : 0x%x \n", Regs->Dsaddr));
+  DEBUG ((DEBUG_ERROR, "Blkattr : 0x%x \n", Regs->Blkattr));
+  DEBUG ((DEBUG_ERROR, "CmdArg : 0x%x \n", Regs->CmdArg));
+  DEBUG ((DEBUG_ERROR, "Xfertype : 0x%x \n", Regs->Xfertype));
+  DEBUG ((DEBUG_ERROR, "Rspns0 : 0x%x \n", Regs->Rspns0));
+  DEBUG ((DEBUG_ERROR, "Rspns1 : 0x%x \n", Regs->Rspns1));
+  DEBUG ((DEBUG_ERROR, "Rspns1 : 0x%x \n", Regs->Rspns1));
+  DEBUG ((DEBUG_ERROR, "Rspns3 : 0x%x \n", Regs->Rspns3));
+  DEBUG ((DEBUG_ERROR, "Datport : 0x%x \n", Regs->Datport));
+  DEBUG ((DEBUG_ERROR, "Prsstat : 0x%x \n", Regs->Prsstat));
+  DEBUG ((DEBUG_ERROR, "Proctl : 0x%x \n", Regs->Proctl));
+  DEBUG ((DEBUG_ERROR, "Sysctl : 0x%x \n", Regs->Sysctl));
+  DEBUG ((DEBUG_ERROR, "Irqstat : 0x%x \n", Regs->Irqstat));
+  DEBUG ((DEBUG_ERROR, "Irqstaten : 0x%x \n", Regs->Irqstaten));
+  DEBUG ((DEBUG_ERROR, "Irqsigen : 0x%x \n", Regs->Irqsigen));
+  DEBUG ((DEBUG_ERROR, "Autoc12err : 0x%x \n", Regs->Autoc12err));
+  DEBUG ((DEBUG_ERROR, "Hostcapblt : 0x%x \n", Regs->Hostcapblt));
+  DEBUG ((DEBUG_ERROR, "Wml : 0x%x \n", Regs->Wml));
+  DEBUG ((DEBUG_ERROR, "Mixctrl : 0x%x \n", Regs->Mixctrl));
+  DEBUG ((DEBUG_ERROR, "Fevt : 0x%x \n", Regs->Fevt));
+  DEBUG ((DEBUG_ERROR, "Admaes : 0x%x \n", Regs->Admaes));
+  DEBUG ((DEBUG_ERROR, "Adsaddr : 0x%x \n", Regs->Adsaddr));
+  DEBUG ((DEBUG_ERROR, "Hostver : 0x%x \n", Regs->Hostver));
+  DEBUG ((DEBUG_ERROR, "Dmaerraddr : 0x%x \n", Regs->Dmaerraddr));
+  DEBUG ((DEBUG_ERROR, "Dmaerrattr : 0x%x \n", Regs->Dmaerrattr));
+  DEBUG ((DEBUG_ERROR, "Hostcapblt2 : 0x%x \n", Regs->Hostcapblt2));
+  DEBUG ((DEBUG_ERROR, "Tcr : 0x%x \n", Regs->Tcr));
+  DEBUG ((DEBUG_ERROR, "Sddirctl : 0x%x \n", Regs->Sddirctl));
+  DEBUG ((DEBUG_ERROR, "Scr : 0x%x \n", Regs->Scr));
+}
+
+/**
+  Function to create dma map for read/write operation
+
+  @param   DmaData Pointer to Dma data Structure
+
+  @retval  Address of dma map
+
+**/
+VOID *
+GetDmaBuffer (
+  IN struct DmaData *DmaData
+  )
+{
+  EFI_STATUS Status;
+  EFI_PHYSICAL_ADDRESS PhyAddr;
+
+  Status = DmaAllocateBuffer (EfiBootServicesData,
+                              EFI_SIZE_TO_PAGES (DmaData->Bytes),
+                              &(DmaData->DmaAddr));
+  if (Status) {
+    DEBUG((DEBUG_ERROR,"DmaAllocateBuffer failed\n"));
+    return NULL;
+  }
+
+  Status = DmaMap (DmaData->MapOperation, DmaData->DmaAddr,
+                  &DmaData->Bytes, &PhyAddr, &DmaData->Mapping);
+  if (Status) {
+    DEBUG((DEBUG_ERROR,"DmaMap failed %d \n", Status));
+
+    DmaFreeBuffer(EFI_SIZE_TO_PAGES (DmaData->Bytes), DmaData->DmaAddr);
+
+    return NULL;
+  }
+  return (VOID *)PhyAddr;
+}
+
+/**
+  Function to free dma map
+
+  @param   DmaData Pointer to Dma data Structure
+
+  @retval  Address of dma map
+
+**/
+EFI_STATUS
+FreeDmaBuffer (
+  IN struct DmaData *DmaData
+  )
+{
+  EFI_STATUS Status;
+
+  Status = DmaUnmap (DmaData->Mapping);
+  if (Status) {
+    DEBUG((DEBUG_ERROR,"DmaUnmap failed 0x%x\n", Status));
+  }
+
+  Status = DmaFreeBuffer (EFI_SIZE_TO_PAGES (DmaData->Bytes), DmaData->DmaAddr);
+  if (Status) {
+    DEBUG((DEBUG_ERROR,"DmaFreeBuffer failed 0x%x\n", Status));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Function to select the transfer type flags depending upon given
+  command and data packet
+
+  @param   Cmd  Pointer to MMC command
+  @param   Data Pointer to MMC data
+
+  @retval  Returns the XFERTYPE flags
+
+**/
+UINT32
+SdxcXfertype (
+  IN  struct SdCmd *Cmd,
+  IN  struct SdData *Data
+  )
+{
+  UINT32 Xfertype;
+
+  Xfertype = 0;
+
+  if (Data) {
+    Xfertype |= XFERTYPE_DPSEL;
+    Xfertype |= XFERTYPE_DMAEN; //DMA Support
+
+    if (Data->Blocks > 1) {
+      Xfertype |= XFERTYPE_MSBSEL;
+      Xfertype |= XFERTYPE_BCEN;
+    }
+
+    if (Data->Flags & MMC_DATA_READ) {
+      Xfertype |= XFERTYPE_DTDSEL;
+    }
+  }
+
+  if (Cmd->RespType & MMC_RSP_CRC) {
+    Xfertype |= XFERTYPE_CCCEN;
+  }
+  if (Cmd->RespType & MMC_RSP_OPCODE) {
+    Xfertype |= XFERTYPE_CICEN;
+  }
+  if (Cmd->RespType & MMC_RSP_136) {
+    Xfertype |= XFERTYPE_RSPTYP_136;
+  }
+  else if (Cmd->RespType & MMC_RSP_BUSY) {
+    Xfertype |= XFERTYPE_RSPTYP_48_BUSY;
+  }
+  else if (Cmd->RespType & MMC_RSP_PRESENT) {
+    Xfertype |= XFERTYPE_RSPTYP_48;
+  }
+
+  if (Cmd->CmdIdx == CMD_STOP_TRANSMISSION) {
+    Xfertype |= XFERTYPE_CMDTYP_ABORT;
+  }
+
+  return XFERTYPE_CMD (Cmd->CmdIdx) | Xfertype;
+}
+
+/**
+  Function to set up MMC data(timeout value,watermark level,
+  system address,block attributes etc.)
+
+  @param   Data Pointer to MMC data
+
+**/
+EFI_STATUS
+SdxcSetupData (
+  IN  struct SdData *Data
+  )
+{
+  struct SdxcRegs *Regs;
+  INT32 Timeout;
+  UINT32 WmlVal;
+
+  Regs = (VOID *)PcdGet64 (PcdSdxcBaseAddr);
+  Timeout = 0;
+  WmlVal = 0;
+
+  WmlVal = Data->Blocksize/4;
+
+  if (Data->Flags & MMC_DATA_READ) {
+
+    if (WmlVal > WML_RD_MAX) {
+      WmlVal = WML_RD_MAX_VAL;
+    }
+
+    MmcAndThenOr ((UINTN)&Regs->Wml, ~WML_RD_MASK, WmlVal);
+
+  } else {
+    if (WmlVal > WML_WR_MAX) {
+      WmlVal = WML_WR_MAX_VAL;
+    }
+
+    if ((MmcRead ((UINTN)&Regs->Prsstat) & PRSSTATE_WPSPL) == 0) {
+      DEBUG ((DEBUG_ERROR, "The SD Card Is Locked. Can Not Write To A Locked Card.\n"));
+      return EFI_TIMEOUT;
+    }
+
+    MmcAndThenOr ((UINTN)&Regs->Wml, ~WML_WR_MASK, WmlVal << 16);
+  }
+
+  EFI_PHYSICAL_ADDRESS Addr = (EFI_PHYSICAL_ADDRESS)Data->Addr;
+  MmcWrite ((UINTN)&Regs->Dsaddr, Addr);
+
+  MmcWrite ((UINTN)&Regs->Blkattr, Data->Blocks << 16 | Data->Blocksize);
+
+  // Calculate The Timeout Period for Data Transactions
+  Timeout = GenericFls (mMmc->Clock/4);
+  Timeout -= 13;
+
+  if (Timeout > 14) {
+    Timeout = 14;
+  }
+
+  if (Timeout < 0) {
+    Timeout = 0;
+  }
+
+  MmcAndThenOr ((UINTN)&Regs->Sysctl, ~SYSCTL_TIMEOUT_MASK, Timeout << 16);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Function to peform reset of MMC command and data
+
+**/
+VOID
+ResetCmdFailedData (
+  IN  struct SdxcRegs *Regs,
+  IN  UINT8  Data
+  )
+{
+  INT32 Timeout;
+
+  Timeout = 10000;
+
+  // Reset CMD And DATA Portions On Error
+  MmcWrite ((UINTN)&Regs->Sysctl, MmcRead ((UINTN)&Regs->Sysctl) |
+           SYSCTL_RSTC);
+
+  while ((MmcRead((UINTN)&Regs->Sysctl) & SYSCTL_RSTC) && Timeout--);
+  if (Timeout <= 0) {
+    DEBUG((DEBUG_ERROR, "Failed to reset CMD Portion On Error\n"));
+    return;
+  }
+
+  Timeout = 10000;
+  if (Data) {
+    MmcWrite ((UINTN)&Regs->Sysctl,
+           MmcRead ((UINTN)&Regs->Sysctl) | SYSCTL_RSTD);
+    while ((MmcRead ((UINTN)&Regs->Sysctl) & SYSCTL_RSTD) && Timeout--);
+    if (Timeout <= 0) {
+      DEBUG ((DEBUG_ERROR, "Failed to reset DATA Portion On Error\n"));
+    }
+  }
+
+  MmcWrite ((UINTN)&Regs->Irqstat, 0xFFFFFFFF);
+}
+
+/**
+  Function to do MMC read/write transfer using DMA and checks
+  whether transfer is completed or not
+
+**/
+EFI_STATUS
+Transfer (
+  IN  VOID
+  )
+{
+  UINT32        Irqstat;
+  UINT32        Timeout;
+  struct SdxcRegs *Regs;
+
+  Regs = (VOID *)PcdGet64 (PcdSdxcBaseAddr);
+  Timeout = 10000000;
+  do {
+    Irqstat = MmcRead ((UINTN)&Regs->Irqstat);
+
+    if (Irqstat & IRQSTATE_DTOE) {
+      DumpMmcRegs ();
+      ResetCmdFailedData (Regs, 1);
+      return EFI_TIMEOUT;
+    }
+
+    if (Irqstat & DATA_ERR) {
+      ResetCmdFailedData (Regs, 1);
+      return EFI_DEVICE_ERROR;
+    }
+
+   MicroSecondDelay (10);
+
+  } while ((!(Irqstat & DATA_COMPLETE)) && Timeout--);
+
+  if (Timeout <= 0) {
+    DEBUG ((DEBUG_ERROR, "Timeout Waiting for DATA_COMPLETE to set\n"));
+    ResetCmdFailedData (Regs, 1);
+    return EFI_TIMEOUT;
+  }
+
+  MmcWrite ((UINTN)&Regs->Irqstat, 0xFFFFFFFF);
+  return EFI_SUCCESS;
+}
+
+/**
+  Function to set MMC host controller system control register
+
+  @param  Clock Clock value for setting the register
+
+**/
+VOID
+SetSysctl (
+  UINT32 Clock
+  )
+{
+  INT32 Div, PreDiv;
+  struct SdxcRegs *Regs;
+  INT32 SdhcClk;
+  UINT32 Clk;
+
+  Regs = (VOID *)PcdGet64(PcdSdxcBaseAddr);
+  SdhcClk = mMmc->SdhcClk;
+
+  if (Clock < mMmc->FMin) {
+    Clock = mMmc->FMin;
+  } else if (Clock > mMmc->FMax) {
+    Clock = mMmc->FMax;
+  }
+
+  mMmc->Clock = Clock;
+
+  if (SdhcClk / 16 > Clock) {
+    for (PreDiv = 2; PreDiv < 256; PreDiv *= 2)
+      if ((SdhcClk / PreDiv) <= (Clock * 16)) {
+        break;
+      }
+  } else {
+    PreDiv = 2;
+  }
+
+  for (Div = 1; Div <= 16; Div++)
+    if ((SdhcClk / (Div * PreDiv)) <= Clock) {
+      break;
+    }
+
+  PreDiv >>= mMmc->DdrMode ? DIV_2 : DIV_1;
+  Div -= 1;
+
+  Clk = (PreDiv << 8) | (Div << 4);
+
+  MmcAnd ((UINTN)&Regs->Sysctl, ~SYSCTL_CKEN);
+
+  MmcAndThenOr ((UINTN)&Regs->Sysctl, ~SYSCTL_CLOCK_MASK, Clk);
+
+  MicroSecondDelay (100);
+
+  Clk = SYSCTL_PEREN | SYSCTL_CKEN;
+
+  MmcOr ((UINTN)&Regs->Sysctl, Clk);
+}
+
+/**
+  Function to set MMC host controller bus width
+
+  @param  Mmc    Pointer to MMC data structure
+  @param  BWidth Bus width to be set
+
+**/
+VOID
+SdxcSetBusWidth (
+  IN  struct Mmc *Mmc,
+  IN  UINT32 BWidth
+  )
+{
+  Mmc->BusWidth = BWidth;
+
+  SetIos (Mmc->Clock, Mmc->BusWidth, 0);
+}
+
+/**
+  Function to Initialize MMC host controller
+
+  @param  Mmc Pointer to MMC data structure
+
+**/
+EFI_STATUS
+SdxcInit (
+  IN  struct Mmc *Mmc
+  )
+{
+  struct SdxcRegs *Regs;
+  INT32 Timeout;
+
+  Regs = (VOID *)PcdGet64(PcdSdxcBaseAddr);
+  Timeout = 1000;
+
+  // Reset The Entire Host Controller
+  MmcOr ((UINTN)&Regs->Sysctl, SYSCTL_RSTA);
+
+  // Wait Until The Controller Is Available
+  while ((MmcRead ((UINTN)&Regs->Sysctl) & SYSCTL_RSTA) && --Timeout)
+    MicroSecondDelay (1000);
+
+  if (Timeout <= 0) {
+    DEBUG ((DEBUG_ERROR, "Host controller failed to reset \n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  // Enable Cache Snooping
+  MmcWrite ((UINTN)&Regs->Scr, ENABLE_CACHE_SNOOPING);
+
+  MmcOr ((UINTN)&Regs->Sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN);
+
+  // Set The Initial Clock Speed
+  SetIos (MIN_CLK_FREQUENCY, Mmc->BusWidth, 0);
+
+  // Disable The BRR And BWR Bits In IRQSTAT
+  MmcAnd ((UINTN)&Regs->Irqstaten,
+          ~(IRQSTATE_EN_BRR | IRQSTATE_EN_BWR));
+
+  // Set Little Endian mode for data Buffer
+  MmcWrite ((UINTN)&Regs->Proctl, PRCTL_INIT);
+
+  // Set Timeout To The Maximum Value
+  MmcAndThenOr ((UINTN)&Regs->Sysctl,
+          ~SYSCTL_TIMEOUT_MASK, 14 << 16);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Function to reset MMC host controller
+
+  @param   Regs Pointer to MMC host Controller
+
+**/
+VOID
+SdxcReset (
+  IN struct SdxcRegs *Regs
+  )
+{
+  UINT64 Timeout;
+
+  Timeout = 100;
+
+  // Reset The Controller
+  MmcWrite ((UINTN)&Regs->Sysctl, SYSCTL_RSTA);
+
+  // Hardware Clears The Bit When It Is Done
+  while ((MmcRead ((UINTN)&Regs->Sysctl) & SYSCTL_RSTA) && --Timeout)
+    MicroSecondDelay (10);
+
+  if (!Timeout) {
+    DEBUG((DEBUG_ERROR, "MMC/SD: Reset Never Completed.\n"));
+  }
+}
diff --git a/Platform/NXP/Library/MmcLib/MmcLib.inf b/Platform/NXP/Library/MmcLib/MmcLib.inf
new file mode 100644
index 0000000..017c6ad
--- /dev/null
+++ b/Platform/NXP/Library/MmcLib/MmcLib.inf
@@ -0,0 +1,39 @@
+##@file
+#
+#  Copyright 2017 NXP
+#
+#  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                    = 0x0001001A
+  BASE_NAME                      = MmcLib
+  FILE_GUID                      = c0f5dfa0-7599-11e0-9866-0002a5d5c61b
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = MmcLib
+
+[Sources.common]
+  MmcLib.c
+  MmcInterface.c
+
+[LibraryClasses]
+  BaseMemoryLib
+  BeIoLib
+  DmaLib
+
+[Packages]
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdePkg/MdePkg.dec
+  Platform/NXP/NxpQoriqLs.dec
+
+[FixedPcd]
+  gNxpQoriqLsTokenSpaceGuid.PcdSdxcBaseAddr
+  gNxpQoriqLsTokenSpaceGuid.PcdMmcBigEndian
-- 
1.9.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel