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
© 2016 - 2024 Red Hat, Inc.