From: Chris Co <Christopher.Co@microsoft.com>
To: "edk2-devel@lists.01.org" <edk2-devel@lists.01.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>,
Leif Lindholm <leif.lindholm@linaro.org>,
Michael D Kinney <michael.d.kinney@intel.com>
Subject: [PATCH edk2-platforms 1/3] Platform/Microsoft: Add SdMmc Dxe Driver
Date: Tue, 17 Jul 2018 02:05:42 +0000 [thread overview]
Message-ID: <20180717020529.19496-2-christopher.co@microsoft.com> (raw)
In-Reply-To: <20180717020529.19496-1-christopher.co@microsoft.com>
This SdMmc driver adds support to boot Windows from SD and eMMC.
It implements RPMB protocol support for eMMC, unique device path
creation for each slot on the SD bus, high speed modes,
eMMC bus width auto-detection, and support for high capacity
SDXC cards.
Derived from: EmbeddedPkg\Universal\MmcDxe
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Christopher Co <christopher.co@microsoft.com>
---
Platform/Microsoft/Drivers/SdMmcDxe/BlockIo.c | 526 ++++++
Platform/Microsoft/Drivers/SdMmcDxe/Debug.c | 358 ++++
Platform/Microsoft/Drivers/SdMmcDxe/Protocol.c | 1774 ++++++++++++++++++++
Platform/Microsoft/Drivers/SdMmcDxe/Protocol.h | 231 +++
Platform/Microsoft/Drivers/SdMmcDxe/RpmbIo.c | 611 +++++++
Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.c | 892 ++++++++++
Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.h | 529 ++++++
Platform/Microsoft/Drivers/SdMmcDxe/SdMmcDxe.inf | 50 +
Platform/Microsoft/Drivers/SdMmcDxe/SdMmcHw.h | 506 ++++++
Platform/Microsoft/Include/Protocol/RpmbIo.h | 262 +++
Platform/Microsoft/Include/Protocol/Sdhc.h | 197 +++
11 files changed, 5936 insertions(+)
diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/BlockIo.c b/Platform/Microsoft/Drivers/SdMmcDxe/BlockIo.c
new file mode 100644
index 000000000000..07acd7b7b3f7
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/BlockIo.c
@@ -0,0 +1,526 @@
+/** @file
+*
+* Copyright (c) Microsoft Corporation. All rights reserved.
+* Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Sdhc.h>
+#include <Protocol/RpmbIo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include "SdMmcHw.h"
+#include "SdMmc.h"
+#include "Protocol.h"
+
+VOID
+BenchmarkIo (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN SD_TRANSFER_DIRECTION TransferDirection,
+ IN UINT32 MediaId,
+ IN UINTN BufferSize,
+ IN UINT32 Iterations
+ );
+
+EFI_STATUS
+IoBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN SD_TRANSFER_DIRECTION TransferDirection,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ );
+
+VOID
+SortIoReadStatsByTotalTransferTime (
+ IN IoReadStatsEntry* Table,
+ IN UINT32 NumEntries
+ )
+{
+ // Using the simple insertion sort
+ UINT32 Idx;
+ for (Idx = 1; Idx < NumEntries; ++Idx) {
+ IoReadStatsEntry CurrEntry = Table[Idx];
+ UINT32 J = Idx;
+ while (J > 0 &&
+ Table[J - 1].TotalTransferTimeUs < CurrEntry.TotalTransferTimeUs) {
+ Table[J] = Table[J - 1];
+ --J;
+ }
+ Table[J] = CurrEntry;
+ }
+}
+
+VOID
+BenchmarkIo (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN SD_TRANSFER_DIRECTION TransferDirection,
+ IN UINT32 MediaId,
+ IN UINTN BufferSize,
+ IN UINT32 Iterations
+ )
+{
+ ASSERT (Iterations > 0);
+
+ EFI_STATUS Status;
+ UINT32 BufferSizeKB = INT_DIV_ROUND (BufferSize, 1024);
+ VOID* Buffer = AllocateZeroPool (BufferSize);
+ if (Buffer == NULL) {
+ LOG_ERROR ("BenchmarkIo() : No enough memory to allocate %dKB buffer", BufferSizeKB);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ UINT32 CurrIteration = Iterations;
+ UINT64 TotalTransfersTimeUs = 0;
+
+ while (CurrIteration--) {
+ UINT64 StartTime = GetPerformanceCounter ();
+
+ Status = IoBlocks (
+ This,
+ TransferDirection,
+ MediaId,
+ 0, // Lba
+ BufferSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ UINT64 EndTime = GetPerformanceCounter ();
+ TotalTransfersTimeUs += (((EndTime - StartTime) * 1000000UL) / gHpcTicksPerSeconds);
+ }
+
+ UINT32 KBps = (UINT32) (((UINT64) BufferSizeKB * (UINT64) Iterations * 1000000UL) / TotalTransfersTimeUs);
+ LOG_INFO (
+ "- BenchmarkIo(%a, %dKB)\t: Xfr Avg:%dus\t%dKBps\t%dMBps",
+ (TransferDirection == SdTransferDirectionRead) ? "Read" : "Write",
+ BufferSizeKB,
+ (UINT32) (TotalTransfersTimeUs / Iterations),
+ KBps,
+ INT_DIV_ROUND (KBps, 1024));
+
+Exit:
+ if (Buffer != NULL) {
+ FreePool (Buffer);
+ }
+}
+
+EFI_STATUS
+IoBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN SD_TRANSFER_DIRECTION TransferDirection,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ )
+{
+ SDHC_INSTANCE *HostInst;
+ EFI_STATUS Status;
+ CONST SD_COMMAND *Cmd;
+ UINT32 BlockCount;
+
+ HostInst = SDHC_INSTANCE_FROM_BLOCK_IO_THIS (This);
+ ASSERT (HostInst);
+ ASSERT (HostInst->HostExt);
+
+ if (This->Media->MediaId != MediaId) {
+ Status = EFI_MEDIA_CHANGED;
+ goto Exit;
+ }
+
+ if (Buffer == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ // Check if a Card is Present
+ if (!HostInst->BlockIo.Media->MediaPresent) {
+ Status = EFI_NO_MEDIA;
+ goto Exit;
+ }
+
+ // Reading 0 Byte is valid
+ if (BufferSize == 0) {
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+
+ if ((TransferDirection == SdTransferDirectionWrite) && (This->Media->ReadOnly == TRUE)) {
+ Status = EFI_WRITE_PROTECTED;
+ goto Exit;
+ }
+
+ // The buffer size must be an exact multiple of the block size
+ if ((BufferSize % This->Media->BlockSize) != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Exit;
+ }
+
+ BlockCount = BufferSize / This->Media->BlockSize;
+
+ // All blocks must be within the device
+ if ((Lba + BlockCount - 1) > (This->Media->LastBlock)) {
+ LOG_ERROR (
+ "Data span is out of media address range. (Media Last Block LBA = 0x%lx"
+ "Data Last Block LBA = 0x%lx)",
+ This->Media->LastBlock,
+ (Lba + BlockCount - 1));
+
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ // Check the alignment
+ if ((This->Media->IoAlign > 2) && (((UINTN) Buffer & (This->Media->IoAlign - 1)) != 0)) {
+ LOG_ERROR (
+ "Invalid buffer address alignment (Buffer = %p, IoAlign = %d)",
+ Buffer,
+ This->Media->IoAlign);
+
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ if (TransferDirection == SdTransferDirectionRead) {
+ if (BlockCount == 1) {
+ Cmd = &CmdReadSingleBlock;
+ } else {
+ Cmd = &CmdReadMultiBlock;
+ }
+ } else {
+ if (BlockCount == 1) {
+ Cmd = &CmdWriteSingleBlock;
+ } else {
+ Cmd = &CmdWriteMultiBlock;
+ }
+ }
+
+ CONST UINT32 DataCommandRetryCount = 3;
+ CONST UINT32 MaxTransferSize =
+ HostInst->HostCapabilities.MaximumBlockCount * This->Media->BlockSize;
+ UINT32 Retry;
+ UINT32 BytesRemaining = BufferSize;
+ UINTN CurrentBufferSize;
+ VOID *CurrentBuffer = Buffer;
+ UINT32 CurrentLba = (UINT32) Lba;
+
+ for (; BytesRemaining > 0;) {
+ if (BytesRemaining < MaxTransferSize) {
+ CurrentBufferSize = BytesRemaining;
+ } else {
+ CurrentBufferSize = MaxTransferSize;
+ }
+
+ for (Retry = 0; Retry < DataCommandRetryCount; ++Retry) {
+ Status = SdhcSendDataCommand (
+ HostInst,
+ Cmd,
+ CurrentLba,
+ CurrentBufferSize,
+ CurrentBuffer);
+
+ if (!EFI_ERROR (Status)) {
+ if (Retry > 0) {
+ LOG_TRACE ("SdhcSendDataCommand succeeded after %d retry", Retry);
+ }
+ break;
+ }
+
+ // On SdhcSendDataCommand return, proper error recovery has been performed
+ // and it should be safe to retry the same transfer.
+
+ LOG_ERROR ("SdhcSendDataCommand failed on retry %d", Retry);
+ }
+
+ BytesRemaining -= CurrentBufferSize;
+ CurrentLba += CurrentBufferSize / This->Media->BlockSize;
+ CurrentBuffer = (VOID*) ((UINTN) CurrentBuffer + CurrentBufferSize);
+ }
+
+Exit:
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "IoBlocks(%c, LBA:0x%08lx, Size(B):0x%x): SdhcSendDataCommand() failed. %r",
+ ((TransferDirection == SdTransferDirectionRead) ? 'R' : 'W'),
+ Lba,
+ BufferSize,
+ Status);
+ }
+
+ return Status;
+}
+
+// EFI_BLOCK_IO Protocol Callbacks
+
+/**
+ Reset the block device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.Reset().
+ It resets the block device hardware.
+ ExtendedVerification is ignored in this implementation.
+
+ @param This Indicates a pointer to the calling context.
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive
+ verification operation of the device during reset.
+
+ @retval EFI_SUCCESS The block device was reset.
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ LOG_TRACE ("BlockIoReset()");
+
+ SDHC_INSTANCE *HostInst = SDHC_INSTANCE_FROM_BLOCK_IO_THIS (This);
+ return SoftReset (HostInst);
+}
+
+/**
+ Reads the requested number of blocks from the device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks().
+ It reads the requested number of blocks from the device.
+ All the blocks are read, or an error is returned.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the read request is for.
+ @param Lba The starting logical block address to read from on the device.
+ @param BufferSize The size of the Buffer in bytes.
+ This must be a multiple of the intrinsic block size of the device.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ LOG_TRACE ("BlockIoReadBlocks()");
+
+#if SDMMC_BENCHMARK_IO
+ static BOOLEAN BenchmarkDone = FALSE;
+ if (!BenchmarkDone) {
+
+ LOG_INFO ("Benchmarking BlockIo Read");
+
+ UINT32 CurrByteSize = 512;
+ CONST UINT32 MaxByteSize = 8388608; // 8MB Max
+ for (; CurrByteSize <= MaxByteSize; CurrByteSize *= 2) {
+ BenchmarkIo (This, SdTransferDirectionRead, MediaId, CurrByteSize, 10);
+ }
+
+ BenchmarkDone = TRUE;
+ }
+#endif // SDMMC_BENCHMARK_IO
+
+#if SDMMC_COLLECT_STATISTICS
+ UINT32 NumBlocks = BufferSize / This->Media->BlockSize;
+ SDHC_INSTANCE *HostInst = SDHC_INSTANCE_FROM_BLOCK_IO_THIS (This);
+ CONST UINT32 TableSize = ARRAYSIZE (HostInst->IoReadStats);
+ IoReadStatsEntry *CurrentReadEntry = NULL;
+
+ UINT32 BlockIdx;
+ for (BlockIdx = 0; BlockIdx < TableSize; ++BlockIdx) {
+ IoReadStatsEntry *Entry = HostInst->IoReadStats + BlockIdx;
+ // Reached end of table and didn't find a match, append an entry
+ if (Entry->NumBlocks == 0) {
+ ++HostInst->IoReadStatsNumEntries;
+ Entry->NumBlocks = NumBlocks;
+ }
+
+ if (Entry->NumBlocks == NumBlocks) {
+ CurrentReadEntry = Entry;
+ ++Entry->Count;
+ break;
+ }
+ }
+ ASSERT (BlockIdx < TableSize);
+
+ UINT64 StartTime = GetPerformanceCounter ();
+
+ EFI_STATUS Status = IoBlocks (
+ This,
+ SdTransferDirectionRead,
+ MediaId,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ UINT64 EndTime = GetPerformanceCounter ();
+
+ ASSERT (CurrentReadEntry != NULL);
+ CurrentReadEntry->TotalTransferTimeUs +=
+ (UINT32) (((EndTime - StartTime) * 1000000UL) / gHpcTicksPerSeconds);
+
+ //
+ // Run statistics and dump updates
+ //
+ SortIoReadStatsByTotalTransferTime (
+ HostInst->IoReadStats,
+ HostInst->IoReadStatsNumEntries);
+
+ IoReadStatsEntry *MaxNumBlocksEntry = HostInst->IoReadStats;
+ IoReadStatsEntry *MaxCountEntry = HostInst->IoReadStats;
+ UINT32 TotalReadTimeUs = 0;
+ UINT32 TotalReadBlocksCount = 0;
+
+ LOG_INFO (" #Blks\tCnt\tAvg(us)\tAll(us)");
+
+ for (BlockIdx = 0; BlockIdx < HostInst->IoReadStatsNumEntries; ++BlockIdx) {
+ IoReadStatsEntry *CurrEntry = HostInst->IoReadStats + BlockIdx;
+
+ if (CurrEntry->NumBlocks > MaxNumBlocksEntry->NumBlocks) {
+ MaxNumBlocksEntry = CurrEntry;
+ }
+
+ if (CurrEntry->Count > MaxCountEntry->Count) {
+ MaxCountEntry = CurrEntry;
+ }
+
+ TotalReadTimeUs += CurrEntry->TotalTransferTimeUs;
+ TotalReadBlocksCount += (CurrEntry->NumBlocks * CurrEntry->Count);
+
+ // Show only the top 5 time consuming transfers
+ if (BlockIdx < 5) {
+ LOG_INFO (
+ " %d\t%d\t%d\t%d",
+ (UINT32) CurrEntry->NumBlocks,
+ (UINT32) CurrEntry->Count,
+ (UINT32) (CurrEntry->TotalTransferTimeUs / CurrEntry->Count),
+ (UINT32) CurrEntry->TotalTransferTimeUs);
+ }
+ }
+
+ LOG_INFO (
+ "MaxNumBlocksEntry: %d %d %dus",
+ (UINT32) MaxNumBlocksEntry->NumBlocks,
+ (UINT32) MaxNumBlocksEntry->Count,
+ (UINT32) MaxNumBlocksEntry->TotalTransferTimeUs);
+
+ LOG_INFO (
+ "MaxCountEntry: %d %d %dus",
+ (UINT32) MaxCountEntry->NumBlocks,
+ (UINT32) MaxCountEntry->Count,
+ (UINT32) MaxCountEntry->TotalTransferTimeUs);
+
+ LOG_INFO (
+ "UEFI spent %dus~%ds reading %dMB from SDCard\n",
+ TotalReadTimeUs,
+ INT_DIV_ROUND (TotalReadTimeUs, 1000000),
+ INT_DIV_ROUND (TotalReadBlocksCount * This->Media->BlockSize, (1024 * 1024)));
+Exit:
+ return Status;
+
+#else
+ return IoBlocks (This, SdTransferDirectionRead, MediaId, Lba, BufferSize, Buffer);
+#endif // SDMMC_COLLECT_STATISTICS
+}
+
+/**
+ Writes a specified number of blocks to the device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks().
+ It writes a specified number of blocks to the device.
+ All blocks are written, or an error is returned.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written.
+ @param BufferSize The size of the Buffer in bytes.
+ This must be a multiple of the intrinsic block size of the device.
+ @param Buffer Pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data were written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic
+ block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ LOG_TRACE ("BlockIoWriteBlocks()");
+
+ return IoBlocks (This, SdTransferDirectionWrite, MediaId, Lba, BufferSize, Buffer);
+}
+
+/**
+ Flushes all modified data to a physical block device.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data were written correctly to the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data.
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ LOG_TRACE ("BlockIoFlushBlocks()");
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/Debug.c b/Platform/Microsoft/Drivers/SdMmcDxe/Debug.c
new file mode 100644
index 000000000000..8fcef9f229ab
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/Debug.c
@@ -0,0 +1,358 @@
+/** @file
+*
+* Copyright (c) Microsoft Corporation. All rights reserved.
+* Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Sdhc.h>
+#include <Protocol/RpmbIo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include "SdMmcHw.h"
+#include "SdMmc.h"
+#include "Protocol.h"
+
+CONST CHAR8 *mStrUnit[] = { "100kbit/s", "1Mbit/s", "10Mbit/s", "100MBit/s",
+ "Unknown", "Unknown", "Unknown", "Unknown" };
+CONST CHAR8 *mStrValue[] = { "UNDEF", "1.0", "1.2", "1.3", "1.5", "2.0", "2.5", "3.0", "3.5", "4.0", "4.5", "5.0",
+ "Unknown", "Unknown", "Unknown", "Unknown" };
+
+VOID
+PrintCid (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ LOG_INFO ("- PrintCid");;
+
+ if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+ SD_CID *Cid = &HostInst->CardInfo.Registers.Sd.Cid;
+ LOG_INFO ("\t- Manufacturer ID: 0x%x", (UINT32) Cid->MID);
+ LOG_INFO ("\t- OEM ID: 0x%x", (UINT32) Cid->OID);
+ LOG_INFO (
+ "\t- Product name: %c%c%c%c%c",
+ Cid->PNM[4],
+ Cid->PNM[3],
+ Cid->PNM[2],
+ Cid->PNM[1],
+ Cid->PNM[0]);
+
+ LOG_INFO (
+ "\t- Manufacturing date: %d/%d",
+ (UINT32) (Cid->MDT & 0xF),
+ (UINT32) (((Cid->MDT >> 4) & 0x3F) + 2000));
+ LOG_INFO ("\t- Product serial number: 0x%X", Cid->PSN);
+ LOG_INFO ("\t- Product revision: %d", (UINT32) Cid->PRV);
+
+ LOG_INFO ("\t- OEM ID: 0x%x", (UINT32) Cid->OID);
+ LOG_INFO ("\t- Manufacturer ID: 0x%x", (UINT32) Cid->MID);
+ } else {
+ MMC_CID *Cid = &HostInst->CardInfo.Registers.Mmc.Cid;
+ LOG_INFO ("\t- Manufacturer ID: 0x%x", (UINT32) Cid->MID);
+ LOG_INFO ("\t- OEM ID: 0x%x", (UINT32) Cid->OID);
+ LOG_INFO (
+ "\t- Product name: %c%c%c%c%c%c\n",
+ Cid->PNM[5],
+ Cid->PNM[4],
+ Cid->PNM[3],
+ Cid->PNM[2],
+ Cid->PNM[1],
+ Cid->PNM[0]);
+
+ LOG_INFO (
+ "\t- Manufacturing date: %d/%d",
+ (UINT32) (Cid->MDT >> 4),
+ (UINT32) (Cid->MDT & 0xF) + 1997);
+
+ LOG_INFO ("\t- Product serial number: 0x%X", Cid->PSN);
+ LOG_INFO ("\t- Product revision: %d", (UINT32) Cid->PRV);
+ }
+}
+
+VOID
+PrintCsd (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ LOG_INFO ("- PrintCsd");
+
+ UINT32 CardSizeGB =
+ (UINT32) INT_DIV_ROUND (HostInst->CardInfo.ByteCapacity, (UINT64) (1024 * 1024 * 1024));
+
+ LOG_INFO (
+ "\t- CardSize: %ld~%dGB, BlockSize:%d LastBlock LBA:0x%08x",
+ HostInst->CardInfo.ByteCapacity,
+ CardSizeGB,
+ HostInst->BlockIo.Media->BlockSize,
+ (UINT32) HostInst->BlockIo.Media->LastBlock);
+
+ if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+ SD_CSD *Csd = &HostInst->CardInfo.Registers.Sd.Csd;
+ if (Csd->CSD_STRUCTURE == 0) {
+ LOG_INFO ("- SD CSD Version 1.01-1.10/Version 2.00/Standard Capacity");
+ } else if (Csd->CSD_STRUCTURE == 1) {
+ LOG_INFO ("- SD CSD Version 2.00/High Capacity");
+ } else {
+ LOG_INFO ("- SD CSD Version Higher than v3.3");
+ }
+
+ LOG_INFO (
+ "\t- SW Write Protect: Temp:%d Permanent:%d",
+ (UINT32) Csd->TMP_WRITE_PROTECT,
+ (UINT32) Csd->PERM_WRITE_PROTECT);
+
+ LOG_INFO ("\t- Supported card command class: 0x%X", Csd->CCC);
+
+ LOG_INFO (
+ "\t- Speed: %a %a (TRAN_SPEED:%x)",
+ mStrValue[(Csd->TRAN_SPEED >> 3) & 0xF],
+ mStrUnit[Csd->TRAN_SPEED & 7],
+ (UINT32) Csd->TRAN_SPEED);
+
+ LOG_INFO (
+ "\t- Maximum Read Data Block: %d (READ_BL_LEN:%x)",
+ (UINT32) (1 << Csd->READ_BL_LEN),
+ (UINT32) Csd->READ_BL_LEN);
+
+ LOG_INFO (
+ "\t- Maximum Write Data Block: %d (WRITE_BL_LEN:%x)",
+ (UINT32) (1 << Csd->WRITE_BL_LEN),
+ (UINT32) Csd->WRITE_BL_LEN);
+
+ if (!Csd->FILE_FORMAT_GRP) {
+ if (Csd->FILE_FORMAT == 0) {
+ LOG_INFO ("\t- Format (0): Hard disk-like file system with partition table");
+ } else if (Csd->FILE_FORMAT == 1) {
+ LOG_INFO ("\t- Format (1): DOS FAT (floppy-like) with boot sector only (no partition table)");
+ } else if (Csd->FILE_FORMAT == 2) {
+ LOG_INFO ("\t- Format (2): Universal File Format");
+ } else {
+ LOG_INFO ("\t- Format (3): Others/Unknown");
+ }
+ } else {
+ LOG_INFO ("\t- Format: Reserved");
+ }
+ } else {
+ MMC_CSD *Csd = &HostInst->CardInfo.Registers.Mmc.Csd;
+ MMC_EXT_CSD *ExtCsd = &HostInst->CardInfo.Registers.Mmc.ExtCsd;
+
+ if (ExtCsd->CardType & MmcExtCsdCardTypeNormalSpeed) {
+ LOG_INFO ("\t- Normal-Speed MMC @ 26MHz");
+ }
+
+ if (ExtCsd->CardType & MmcExtCsdCardTypeHighSpeed) {
+ LOG_INFO ("\t- High-Speed MMC @ 52MHz");
+ }
+
+ if (ExtCsd->CardType & MmcExtCsdCardTypeDdr1v8) {
+ LOG_INFO ("\t- High-Speed DDR MMC @ 52MHz - 1.8V or 3V I/O");
+ }
+
+ if (ExtCsd->CardType & MmcExtCsdCardTypeDdr1v2) {
+ LOG_INFO ("\t- High-Speed DDR MMC @ 52MHz - 1.2VI/O");
+ }
+
+ LOG_INFO (
+ "\t- SW Write Protect: Temp:%d Permenant:%d",
+ (UINT32) Csd->TMP_WRITE_PROTECT,
+ (UINT32) Csd->PERM_WRITE_PROTECT);
+
+ LOG_INFO ("\t- SpecVersion: %d.x", (UINT32) Csd->SPEC_VERS);
+ LOG_INFO ("\t- Supported card command class: 0x%X", Csd->CCC);
+
+ LOG_INFO (
+ "\t- Current Max Speed: %a %a (TRAN_SPEED:%x)",
+ mStrValue[(Csd->TRAN_SPEED >> 3) & 0xF],
+ mStrUnit[Csd->TRAN_SPEED & 7],
+ (UINT32) Csd->TRAN_SPEED);
+
+ LOG_INFO (
+ "\t- Maximum Read Data Block: %d (READ_BL_LEN:%x)",
+ (UINT32) (1 << Csd->READ_BL_LEN),
+ (UINT32) Csd->READ_BL_LEN);
+
+ LOG_INFO (
+ "\t- Maximum Write Data Block: %d (WRITE_BL_LEN:%x)",
+ (UINT32) (1 << Csd->WRITE_BL_LEN),
+ (UINT32) Csd->WRITE_BL_LEN);
+
+ if (!Csd->FILE_FORMAT_GRP) {
+ if (Csd->FILE_FORMAT == 0) {
+ LOG_INFO ("\t- Format (0): Hard disk-like file system with partition table");
+ } else if (Csd->FILE_FORMAT == 1) {
+ LOG_INFO ("\t- Format (1): DOS FAT (floppy-like) with boot sector only (no partition table)");
+ } else if (Csd->FILE_FORMAT == 2) {
+ LOG_INFO ("\t- Format (2): Universal File Format");
+ } else {
+ LOG_INFO ("\t- Format (3): Others/Unknown");
+ }
+ } else {
+ LOG_INFO ("\t- Format: Reserved");
+ }
+ }
+}
+
+VOID
+GetAndPrintCardStatus (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ CARD_STATUS CardStatus;
+ EFI_STATUS Status;
+
+ //
+ // If the card has not been selected, then we can't get its status
+ //
+ if (HostInst->CardInfo.RCA == 0x0) {
+ return;
+ }
+
+ Status = SdhcSendCommand (HostInst, &CmdSendStatus, 0);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ CardStatus.AsUint32 = HostInst->CmdResponse[0];
+ PrintCardStatus (HostInst, CardStatus);
+}
+
+VOID
+PrintCardStatus (
+ IN SDHC_INSTANCE *HostInst,
+ IN CARD_STATUS CardStatus
+ )
+{
+ switch (HostInst->CardInfo.CardFunction) {
+ case CardFunctionSd:
+ LOG_INFO (
+ "Status: APP_CMD:%d READY_FOR_DATA:%d CURRENT_STATE:%d(%a) "
+ "CARD_IS_LOCKED:%d",
+ CardStatus.Fields.APP_CMD,
+ CardStatus.Fields.READY_FOR_DATA,
+ CardStatus.Fields.CURRENT_STATE,
+ CardStateToString (CardStatus.Fields.CURRENT_STATE),
+ CardStatus.Fields.CARD_IS_LOCKED);
+
+ break;
+
+ case CardFunctionMmc:
+ LOG_INFO (
+ "Status: APP_CMD:%d URGENT_BKOPS:%d READY_FOR_DATA:%d "
+ "CURRENT_STATE:%d(%a) CARD_IS_LOCKED:%d",
+ CardStatus.Fields.APP_CMD,
+ CardStatus.Fields.URGENT_BKOPS,
+ CardStatus.Fields.READY_FOR_DATA,
+ CardStatus.Fields.CURRENT_STATE,
+ CardStateToString (CardStatus.Fields.CURRENT_STATE),
+ CardStatus.Fields.CARD_IS_LOCKED);
+
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ if (IsCardStatusError (HostInst, CardStatus)) {
+ LOG_INFO ("Errors:");
+
+ if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+ if (CardStatus.Fields.AKE_SEQ_ERROR) {
+ LOG_INFO ("\t- SWITCH_ERROR");
+ }
+ }
+
+ if (HostInst->CardInfo.CardFunction == CardFunctionMmc) {
+ if (CardStatus.Fields.SWITCH_ERROR) {
+ LOG_INFO ("\t- SWITCH_ERROR");
+ }
+
+ if (CardStatus.Fields.OVERRUN) {
+ LOG_INFO ("\t- OVERRUN");
+ }
+
+ if (CardStatus.Fields.UNDERRUN) {
+ LOG_INFO ("\t- UNDERRUN");
+ }
+ }
+
+ if (CardStatus.Fields.ERASE_RESET) {
+ LOG_INFO ("\t- ERASE_RESET");
+ }
+
+ if (CardStatus.Fields.WP_ERASE_SKIP) {
+ LOG_INFO ("\t- WP_ERASE_SKIP");
+ }
+
+ if (CardStatus.Fields.CID_CSD_OVERWRITE) {
+ LOG_INFO ("\t- CID_CSD_OVERWRITE");
+ }
+
+ if (CardStatus.Fields.ERROR) {
+ LOG_INFO ("\t- ERROR");
+ }
+
+ if (CardStatus.Fields.CC_ERROR) {
+ LOG_INFO ("\t- CC_ERROR");
+ }
+
+ if (CardStatus.Fields.CARD_ECC_FAILED) {
+ LOG_INFO ("\t- CARD_ECC_FAILED");
+ }
+
+ if (CardStatus.Fields.ILLEGAL_COMMAND) {
+ LOG_INFO ("\t- ILLEGAL_COMMAND");
+ }
+
+ if (CardStatus.Fields.COM_CRC_ERROR) {
+ LOG_INFO ("\t- COM_CRC_ERROR");
+ }
+
+ if (CardStatus.Fields.LOCK_UNLOCK_FAILED) {
+ LOG_INFO ("\t- LOCK_UNLOCK_FAILED");
+ }
+
+ if (CardStatus.Fields.WP_VIOLATION) {
+ LOG_INFO ("\t- WP_VIOLATION");
+ }
+
+ if (CardStatus.Fields.ERASE_PARAM) {
+ LOG_INFO ("\t- ERASE_PARAM");
+ }
+
+ if (CardStatus.Fields.ERASE_SEQ_ERROR) {
+ LOG_INFO ("\t- ERASE_SEQ_ERROR");
+ }
+
+ if (CardStatus.Fields.BLOCK_LEN_ERROR) {
+ LOG_INFO ("\t- BLOCK_LEN_ERROR");
+ }
+
+ if (CardStatus.Fields.ADDRESS_MISALIGN) {
+ LOG_INFO ("\t- ADDRESS_MISALIGN");
+ }
+
+ if (CardStatus.Fields.ADDRESS_OUT_OF_RANGE) {
+ LOG_INFO ("\t- ADDRESS_OUT_OF_RANGE");
+ }
+ }
+}
diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/Protocol.c b/Platform/Microsoft/Drivers/SdMmcDxe/Protocol.c
new file mode 100644
index 000000000000..d635fa6a1ef4
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/Protocol.c
@@ -0,0 +1,1774 @@
+/** @file
+*
+* Copyright (c) Microsoft Corporation. All rights reserved.
+* Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Sdhc.h>
+#include <Protocol/RpmbIo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include "SdMmcHw.h"
+#include "SdMmc.h"
+#include "Protocol.h"
+
+EFI_STATUS
+InitializeDevice (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ LOG_TRACE ("InitializDevice()");
+ ASSERT (!HostInst->SlotInitialized);
+
+#if SDMMC_BENCHMARK_IO
+ UINT64 InitializationStartTime = HpcTimerStart ();
+#endif // SDMMC_BENCHMARK_IO
+
+ EFI_SDHC_PROTOCOL *HostExt = HostInst->HostExt;
+ ASSERT (HostExt);
+ EFI_STATUS Status;
+
+ ASSERT (HostInst->BlockIo.Media->MediaPresent);
+
+ ZeroMem (&HostInst->CardInfo, sizeof (HostInst->CardInfo));
+ //
+ // SD/MMC cards on reset start in default normal speed mode
+ //
+ HostInst->CardInfo.CurrentSpeedMode = CardSpeedModeNormalSpeed;
+
+ Status = HostExt->SoftwareReset (HostExt, SdhcResetTypeAll);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("HostExt->SoftwareReset() failed. %r", Status);
+ return Status;
+ }
+
+ Status = HostExt->SetClock (HostExt, SD_IDENT_MODE_CLOCK_FREQ_HZ);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("HostExt->SetClock() failed. %r", Status);
+ return Status;
+ }
+
+ Status = SdhcQueryCardType (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcQueryCardType() failed. %r", Status);
+ return Status;
+ }
+
+ switch (HostInst->CardInfo.CardFunction) {
+ case CardFunctionComboSdSdio:
+ LOG_ERROR ("Combo SD/SDIO function is not supported");
+ return EFI_UNSUPPORTED;
+ case CardFunctionSdio:
+ LOG_ERROR ("SDIO function is not supported");
+ return EFI_UNSUPPORTED;
+ case CardFunctionSd:
+ Status = InitializeSdDevice (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("InitializeSdDevice() failed. %r", Status);
+ return Status;
+ }
+ break;
+ case CardFunctionMmc:
+ Status = InitializeMmcDevice (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("InitializeMmcDevice() failed. %r", Status);
+ return Status;
+ }
+ break;
+ default:
+ LOG_ASSERT ("Unknown device function");
+ return EFI_UNSUPPORTED;
+ }
+
+ PrintCid (HostInst);
+ PrintCsd (HostInst);
+
+ Status = SdhcSetBlockLength (HostInst, SD_BLOCK_LENGTH_BYTES);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSetBlockLength() failed. %r", Status);
+ return Status;
+ }
+
+ ASSERT (HostInst->CardInfo.CardFunction == CardFunctionSd ||
+ HostInst->CardInfo.CardFunction == CardFunctionMmc);
+
+ if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+ HostInst->BlockIo.Media->RemovableMedia = TRUE;
+ HostInst->BlockIo.Media->MediaId = HostInst->CardInfo.Registers.Sd.Cid.PSN;
+ } else {
+ //
+ // Assume BGA form factor eMMC
+ //
+ HostInst->BlockIo.Media->RemovableMedia = FALSE;
+
+ //
+ // Use the card product serial number as MediaId
+ //
+ HostInst->BlockIo.Media->MediaId = HostInst->CardInfo.Registers.Mmc.Cid.PSN;
+ }
+
+ HostInst->SlotInitialized = TRUE;
+
+#if SDMMC_BENCHMARK_IO
+ UINT64 ElapsedTimeMs = HpcTimerElapsedMilliseconds (InitializationStartTime);
+ LOG_INFO ("Initialization completed in %ldms", ElapsedTimeMs);
+#endif // SDMMC_BENCHMARK_IO
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+InitializeSdDevice (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SdhcSendOpCondSd (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSendOpCondSd() failed. %r", Status);
+ return Status;
+ }
+
+ Status = SdhcSendCidAll (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSendCidAll() failed. %r", Status);
+ return Status;
+ }
+
+ Status = SdhcSendRelativeAddr (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSendRelativeAddr() failed. %r", Status);
+ return Status;
+ }
+
+ Status = SdhcSendCid (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSendCid() failed. %r", Status);
+ return Status;
+ }
+
+ Status = SdhcSendCsd (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSendCsd() failed. %r", Status);
+ return Status;
+ }
+
+ Status = SdhcSelectDevice (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSelectDevice() failed. %r", Status);
+ return Status;
+ }
+
+ Status = SdhcSwitchBusWidthSd (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSwitchBusWidthSd() failed. %r", Status);
+ return Status;
+ }
+
+ Status = SdhcSwitchSpeedModeSd (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSwitchSpeedModeSd() failed. %r", Status);
+ return Status;
+ }
+
+ Status = SdhcSetMaxClockFrequency (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSetMaxClockFrequency() failed. %r", Status);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+InitializeMmcDevice (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SdhcSendCidAll (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSendCidAll() failed. %r", Status);
+ return Status;
+ }
+
+ Status = SdhcSendRelativeAddr (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSendRelativeAddr() failed. %r", Status);
+ return Status;
+ }
+
+ Status = SdhcSendCid (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSendCid() failed. %r", Status);
+ return Status;
+ }
+
+ Status = SdhcSendCsd (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSendCsd() failed. %r", Status);
+ return Status;
+ }
+
+ if (HostInst->CardInfo.Registers.Mmc.Csd.SPEC_VERS < MMC_MIN_SUPPORTED_SPEC_VERS) {
+ LOG_ERROR (
+ "MMC %d.x is not supported, Minimum supported is MMC %d.x",
+ HostInst->CardInfo.Registers.Mmc.Csd.SPEC_VERS,
+ MMC_MIN_SUPPORTED_SPEC_VERS);
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = SdhcSelectDevice (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSelectDevice() failed. %r", Status);
+ return Status;
+ }
+
+ Status = SdhcSendExtCsdMmc (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSendExtCsdMmc() failed. %r", Status);
+ return Status;
+ }
+
+ Status = SdhcSwitchSpeedModeMmc (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSwitchSpeedModeMmc() failed. %r", Status);
+ return Status;
+ }
+
+ Status = SdhcSwitchBusWidthMmc (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSwitchBusWidthMmc() failed. %r", Status);
+ return Status;
+ }
+
+ Status = SdhcSetMaxClockFrequency (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSetMaxClockFrequency() failed. %r", Status);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcRecoverFromErrors (
+ IN SDHC_INSTANCE *HostInst,
+ IN CONST SD_COMMAND *Cmd
+ )
+{
+ EFI_STATUS Status;
+ CARD_STATUS CardStatus;
+ EFI_SDHC_PROTOCOL *HostExt;
+
+ LOG_TRACE (
+ "*** %cCMD%d Error recovery sequence start ***",
+ (Cmd->Class == SdCommandClassApp ? 'A' : ' '),
+ (UINT32) Cmd->Index);
+
+ HostExt = HostInst->HostExt;
+ HostInst->ErrorRecoveryAttemptCount += 1;
+
+ if (HostInst->ErrorRecoveryAttemptCount > SDMMC_ERROR_RECOVERY_ATTEMPT_THRESHOLD) {
+ LOG_ERROR ("RecursiveErrorRecoveryCount exceeded the threshold. Error is unrecoverable!");
+ Status = EFI_PROTOCOL_ERROR;
+ goto Exit;
+ }
+
+ GetAndPrintCardStatus (HostInst);
+
+ LOG_TRACE ("Reseting CMD line ...");
+ Status = HostExt->SoftwareReset (HostExt, SdhcResetTypeCmd);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("HostExt->SoftwareReset(SdhcResetTypeCmd) failed. %r", Status);
+ }
+
+ if (Cmd->TransferType != SdTransferTypeNone &&
+ Cmd->TransferType != SdTransferTypeUndefined) {
+
+ LOG_TRACE ("Reseting DAT line ...");
+ Status = HostExt->SoftwareReset (HostExt, SdhcResetTypeData);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("HostExt->SoftwareReset(SdhcResetTypeData) failed. %r", Status);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ LOG_TRACE ("CMD and/or DATA normal error recovery failed, trying SDHC soft-reset");
+ Status = SoftReset (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("All trials to recover from errors failed. %r");
+ goto Exit;
+ }
+ }
+
+ if (CmdsAreEqual (Cmd, &CmdWriteMultiBlock) ||
+ CmdsAreEqual (Cmd, &CmdReadMultiBlock)) {
+
+ Status = SdhcSendStatus (HostInst, &CardStatus);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSendStatus() failed. (Status = %r)", Status);
+ goto Exit;
+ }
+
+ if (CardStatus.Fields.CURRENT_STATE != CardStateTran) {
+ LOG_TRACE ("Stopping transmission ...");
+ Status = SdhcStopTransmission (HostInst);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Multi read/write failure reason will be written in the STOP_TRANSMISSION
+ // response as part of the card status error flags.
+ //
+ CardStatus.AsUint32 = HostInst->CmdResponse[0];
+ PrintCardStatus (HostInst, CardStatus);
+ }
+ }
+
+Exit:
+
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "*** %cCMD%d Error recovery sequence failed "
+ "(Status = %r, ErrorRecoveryAttemptCount = %d) ***",
+ (Cmd->Class == SdCommandClassApp ? 'A' : ' '),
+ (UINT32) Cmd->Index,
+ Status,
+ HostInst->ErrorRecoveryAttemptCount);
+
+ } else {
+ LOG_TRACE (
+ "*** %cCMD%d Error recovery sequence completed successfully "
+ "(ErrorRecoveryAttemptCount = %d) ***",
+ (Cmd->Class == SdCommandClassApp ? 'A' : ' '),
+ (UINT32) Cmd->Index,
+ HostInst->ErrorRecoveryAttemptCount);
+ }
+
+ HostInst->ErrorRecoveryAttemptCount -= 1;
+
+ return Status;
+}
+
+EFI_STATUS
+SdhcSendCommandHelper (
+ IN SDHC_INSTANCE *HostInst,
+ IN CONST SD_COMMAND *Cmd,
+ IN UINT32 Arg,
+ IN SD_COMMAND_XFR_INFO *XfrInfo
+ )
+{
+ EFI_SDHC_PROTOCOL *HostExt = HostInst->HostExt;
+ EFI_STATUS Status;
+ CARD_STATUS CardStatus;
+
+ if (Cmd->Class == SdCommandClassApp) {
+ UINT32 CmdAppArg = HostInst->CardInfo.RCA << 16;
+ Status = HostExt->SendCommand (HostExt, &CmdAppSd, CmdAppArg, NULL);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "HostExt->SendCommand(%cCMD%d, 0x%08x) failed. %r",
+ (Cmd->Class == SdCommandClassApp ? 'A' : ' '),
+ (UINT32) Cmd->Index,
+ CmdAppArg,
+ Status);
+
+ return Status;
+ }
+ }
+
+ Status = HostExt->SendCommand (HostExt, Cmd, Arg, XfrInfo);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "HostExt->SendCommand(%cCMD%d, 0x%08x) failed. %r",
+ (Cmd->Class == SdCommandClassApp ? 'A' : ' '),
+ (UINT32) Cmd->Index,
+ Arg,
+ Status);
+
+ return Status;
+ }
+
+ Status = HostExt->ReceiveResponse (HostExt, Cmd, HostInst->CmdResponse);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("HostExt->ReceiveResponse() failed. %r", Status);
+ return Status;
+ }
+
+ if ((Cmd->ResponseType == SdResponseTypeR1) ||
+ (Cmd->ResponseType == SdResponseTypeR1B)) {
+
+ CardStatus.AsUint32 = HostInst->CmdResponse[0];
+
+ if (IsCardStatusError (HostInst, CardStatus)) {
+ LOG_ERROR (
+ "%cCMD%d card status error detected",
+ (Cmd->Class == SdCommandClassApp ? 'A' : ' '),
+ (UINT32) Cmd->Index);
+
+ PrintCardStatus (HostInst, CardStatus);
+
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ HostInst->PreLastSuccessfulCmd = HostInst->LastSuccessfulCmd;
+ HostInst->LastSuccessfulCmd = Cmd;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSendCommand (
+ IN SDHC_INSTANCE *HostInst,
+ IN CONST SD_COMMAND *Cmd,
+ IN UINT32 Arg
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SdhcSendCommandHelper (HostInst, Cmd, Arg, NULL);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("Send no-data command failed. %r", Status);
+ SdhcRecoverFromErrors (HostInst, Cmd);
+ return Status;
+ }
+
+ //
+ // SWITCH command can change card state to prog, we should wait the card to
+ // transfer back to tran state and rais the READY_FOR_DATA flag to make sure
+ // that switch operation was completed successfully
+ //
+ if (CmdsAreEqual (Cmd, &CmdSwitchMmc) ||
+ CmdsAreEqual (Cmd, &CmdSwitchSd)) {
+ Status = SdhcWaitForTranStateAndReadyForData (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "SdhcWaitForTranStateAndReadyForData() failed after successful "
+ "SWITCH command. (Status = %r)",
+ Status);
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSendDataCommand (
+ IN SDHC_INSTANCE *HostInst,
+ IN CONST SD_COMMAND *Cmd,
+ IN UINT32 Arg,
+ IN UINT32 BufferByteSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_SDHC_PROTOCOL *HostExt = HostInst->HostExt;
+ SD_COMMAND_XFR_INFO XfrInfo;
+ EFI_STATUS Status;
+
+ ASSERT (BufferByteSize % SD_BLOCK_LENGTH_BYTES == 0);
+ XfrInfo.BlockCount = BufferByteSize / SD_BLOCK_LENGTH_BYTES;
+ XfrInfo.BlockSize = SD_BLOCK_LENGTH_BYTES;
+ XfrInfo.Buffer = Buffer;
+
+ Status = SdhcSendCommandHelper (HostInst, Cmd, Arg, &XfrInfo);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ if (Cmd->TransferDirection == SdTransferDirectionRead) {
+ Status = HostExt->ReadBlockData (
+ HostExt,
+ BufferByteSize,
+ (UINT32*) Buffer);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "HostExt->ReadBlockData(Size: 0x%xB) failed. %r",
+ BufferByteSize,
+ Status);
+ goto Exit;
+ }
+ } else {
+ ASSERT (Cmd->TransferDirection == SdTransferDirectionWrite);
+ Status = HostExt->WriteBlockData (
+ HostExt,
+ BufferByteSize,
+ (UINT32*) Buffer);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "HostExt->WriteBlockData(Size: 0x%xB) failed. %r",
+ BufferByteSize,
+ Status);
+ goto Exit;
+ }
+ }
+
+ //
+ // If this is an open-ended multi-block read/write then explicitly send
+ // STOP_TRANSMISSION. A multi-block read/write with pre-defined block count
+ // will be preceeded with SET_BLOCK_COUNT.
+ //
+ if ((CmdsAreEqual (Cmd, &CmdWriteMultiBlock) ||
+ CmdsAreEqual (Cmd, &CmdReadMultiBlock)) &&
+ ((HostInst->LastSuccessfulCmd == NULL) ||
+ !CmdsAreEqual (HostInst->PreLastSuccessfulCmd, &CmdSetBlockCount))) {
+
+ Status = SdhcStopTransmission (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcStopTransmission() failed. (Status = %r)", Status);
+ goto Exit;
+ }
+ }
+
+ Status = SdhcWaitForTranStateAndReadyForData (HostInst);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+Exit:
+
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("Send data command failed. %r", Status);
+ SdhcRecoverFromErrors (HostInst, Cmd);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+SdhcGoIdleState (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ return SdhcSendCommand (HostInst, &CmdGoIdleState, 0);
+}
+
+EFI_STATUS
+SdhcQueryCardType (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ EFI_STATUS Status = SdhcGoIdleState (HostInst);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HostInst->CardInfo.CardFunction = CardFunctionUnknown;
+
+ Status = SdhcSendIfCondSd (HostInst);
+ if (!EFI_ERROR (Status)) {
+ HostInst->CardInfo.CardFunction = CardFunctionSd;
+ }
+
+ Status = SdhcSendOpCondSdio (HostInst);
+ if (!EFI_ERROR (Status)) {
+ if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+ //
+ // SD/SDIO Combo Device
+ //
+ HostInst->CardInfo.CardFunction = CardFunctionComboSdSdio;
+ } else {
+ HostInst->CardInfo.CardFunction = CardFunctionSdio;
+ }
+ }
+
+ if (HostInst->CardInfo.CardFunction != CardFunctionSd &&
+ HostInst->CardInfo.CardFunction != CardFunctionSdio &&
+ HostInst->CardInfo.CardFunction != CardFunctionComboSdSdio) {
+ Status = SdhcGoIdleState (HostInst);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdhcSendOpCondMmc (HostInst);
+ if (!EFI_ERROR (Status)) {
+ HostInst->CardInfo.CardFunction = CardFunctionMmc;
+ }
+ }
+
+ if (HostInst->CardInfo.CardFunction == CardFunctionUnknown) {
+ return EFI_NO_MEDIA;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcWaitForTranStateAndReadyForData (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Retry;
+ CARD_STATUS CardStatus;
+
+ Status = SdhcSendStatus (HostInst, &CardStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Retry = SDMMC_POLL_WAIT_COUNT;
+
+ while (((!CardStatus.Fields.READY_FOR_DATA && Retry) ||
+ (CardStatus.Fields.CURRENT_STATE != CardStateTran)) &&
+ Retry) {
+
+ gBS->Stall (SDMMC_POLL_WAIT_TIME_US);
+ --Retry;
+
+ Status = SdhcSendStatus (HostInst, &CardStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (!Retry) {
+ LOG_ERROR ("Time-out waiting for card READY_FOR_DATA status flag");
+ PrintCardStatus (HostInst, CardStatus);
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSendCid (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ UINT32 CmdArg = HostInst->CardInfo.RCA << 16;
+
+ EFI_STATUS Status = SdhcSendCommand (HostInst, &CmdSendCid, CmdArg);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+ gBS->CopyMem (
+ (VOID*) &HostInst->CardInfo.Registers.Sd.Cid,
+ (VOID*) HostInst->CmdResponse,
+ sizeof (SD_CID));
+
+ } else if (HostInst->CardInfo.CardFunction == CardFunctionMmc) {
+ gBS->CopyMem (
+ (VOID*) &HostInst->CardInfo.Registers.Mmc.Cid,
+ (VOID*) HostInst->CmdResponse,
+ sizeof (MMC_CID));
+
+ C_ASSERT (sizeof (HostInst->RpmbIo.Cid) == EFI_RPMB_CID_SIZE);
+ gBS->CopyMem (
+ (VOID*) &HostInst->RpmbIo.Cid,
+ (VOID*) HostInst->CmdResponse,
+ EFI_RPMB_CID_SIZE);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSendCsd (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ UINT32 CmdArg = HostInst->CardInfo.RCA << 16;
+
+ EFI_STATUS Status = SdhcSendCommand (HostInst, &CmdSendCsd, CmdArg);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ UINT32 MaxBlockLen;
+ UINT64 ByteCapacity = 0;
+
+ if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+ gBS->CopyMem (
+ (VOID*) &HostInst->CardInfo.Registers.Sd.Csd,
+ (VOID*) HostInst->CmdResponse,
+ sizeof (SD_CSD));
+ if (HostInst->CardInfo.Registers.Sd.Csd.CSD_STRUCTURE == 0) {
+ SD_CSD* Csd = (SD_CSD*) &HostInst->CardInfo.Registers.Sd.Csd;
+ UINT32 DeviceSize = ((Csd->C_SIZEHigh10 << 2) | Csd->C_SIZELow2);
+ UINT32 MULT = 1 << (Csd->C_SIZE_MULT + 2);
+ UINT32 BLOCKNR = (DeviceSize + 1) * MULT;
+ MaxBlockLen = 1 << Csd->READ_BL_LEN;
+ ByteCapacity = BLOCKNR * MaxBlockLen;
+ } else {
+ SD_CSD_2* Csd2 = (SD_CSD_2*) &HostInst->CardInfo.Registers.Sd.Csd;
+ MaxBlockLen = 1 << Csd2->READ_BL_LEN;
+ ByteCapacity = (UINT64) (Csd2->C_SIZE + 1) * 512llu * 1024llu;
+ }
+ } else if (HostInst->CardInfo.CardFunction == CardFunctionMmc) {
+ gBS->CopyMem (
+ (VOID*) &HostInst->CardInfo.Registers.Mmc.Csd,
+ (VOID*) HostInst->CmdResponse,
+ sizeof (MMC_CSD));
+ //
+ // HighCapacity MMC requires reading EXT_CSD to calculate capacity
+ //
+ if (!HostInst->CardInfo.HighCapacity) {
+ MMC_CSD* Csd = (MMC_CSD*) &HostInst->CardInfo.Registers.Mmc.Csd;
+ UINT32 DeviceSize = ((Csd->C_SIZEHigh10 << 2) | Csd->C_SIZELow2);
+ UINT32 MULT = 1 << (Csd->C_SIZE_MULT + 2);
+ UINT32 BLOCKNR = (DeviceSize + 1) * MULT;
+ MaxBlockLen = 1 << Csd->READ_BL_LEN;
+ ByteCapacity = BLOCKNR * MaxBlockLen;
+ }
+ }
+
+ HostInst->CardInfo.ByteCapacity = ByteCapacity;
+ HostInst->BlockIo.Media->BlockSize = SD_BLOCK_LENGTH_BYTES;
+ UINT64 NumBlocks = (ByteCapacity / SD_BLOCK_LENGTH_BYTES);
+
+ if (NumBlocks > 0) {
+ HostInst->BlockIo.Media->LastBlock = (NumBlocks - 1);
+ } else {
+ HostInst->BlockIo.Media->LastBlock = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSelectDevice (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ UINT32 CmdArg = HostInst->CardInfo.RCA << 16;
+ return SdhcSendCommand (HostInst, &CmdSelect, CmdArg);
+}
+
+EFI_STATUS
+SdhcDeselectDevice (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ return SdhcSendCommand (HostInst, &CmdDeselect, 0);
+}
+
+EFI_STATUS
+SdhcSendAppCmd (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ UINT32 CmdArg = HostInst->CardInfo.RCA << 16;
+ return SdhcSendCommand (HostInst, &CmdAppSd, CmdArg);
+}
+
+EFI_STATUS
+SdhcStopTransmission (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ UINT32 CmdArg = HostInst->CardInfo.RCA << 16;
+ return SdhcSendCommand (HostInst, &CmdStopTransmission, CmdArg);
+}
+
+EFI_STATUS
+SdhcSendCidAll (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ return SdhcSendCommand (HostInst, &CmdSendCidAll, 0);
+}
+
+EFI_STATUS
+SdhcSendRelativeAddr (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ UINT32 CmdArg = 0;
+
+ //
+ // Unlike SD memory, MMC cards don't publish their RCA, instead it should be
+ // manually assigned by the SDHC
+ //
+ if (HostInst->CardInfo.CardFunction == CardFunctionMmc) {
+ HostInst->CardInfo.RCA = 0xCCCC;
+ CmdArg = HostInst->CardInfo.RCA << 16;
+ }
+
+ EFI_STATUS Status = SdhcSendCommand (HostInst, &CmdSendRelativeAddr, CmdArg);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (HostInst->CardInfo.CardFunction != CardFunctionMmc) {
+ HostInst->CardInfo.RCA = (HostInst->CmdResponse[0] >> 16);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+CalculateCardMaxFreq (
+ IN SDHC_INSTANCE *HostInst,
+ OUT UINT32* MaxClkFreqHz
+ )
+{
+ ASSERT (HostInst != NULL);
+ ASSERT (MaxClkFreqHz != NULL);
+
+ SD_CSD *Csd = &HostInst->CardInfo.Registers.Sd.Csd;
+ UINT32 TransferRateBitPerSecond = 0;
+ UINT32 TimeValue = 0;
+ UINT32 TRAN_SPEED;
+
+ if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+ TRAN_SPEED = HostInst->CardInfo.Registers.Sd.Csd.TRAN_SPEED;
+ } else {
+ TRAN_SPEED = HostInst->CardInfo.Registers.Mmc.Csd.TRAN_SPEED;
+ }
+
+ // Calculate Transfer rate unit (Bits 2:0 of TRAN_SPEED)
+ switch (TRAN_SPEED & 0x7) { // 2
+ case 0: // 100kbit/s
+ TransferRateBitPerSecond = 100 * 1000;
+ break;
+
+ case 1: // 1Mbit/s
+ TransferRateBitPerSecond = 1 * 1000 * 1000;
+ break;
+
+ case 2: // 10Mbit/s
+ TransferRateBitPerSecond = 10 * 1000 * 1000;
+ break;
+
+ case 3: // 100Mbit/s
+ TransferRateBitPerSecond = 100 * 1000 * 1000;
+ break;
+
+ default:
+ LOG_ERROR ("Invalid parameter");
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //Calculate Time value (Bits 6:3 of TRAN_SPEED)
+ switch ((TRAN_SPEED >> 3) & 0xF) { // 6
+ case 0x1:
+ TimeValue = 10;
+ break;
+
+ case 0x2:
+ TimeValue = 12;
+ break;
+
+ case 0x3:
+ TimeValue = 13;
+ break;
+
+ case 0x4:
+ TimeValue = 15;
+ break;
+
+ case 0x5:
+ TimeValue = 20;
+ break;
+
+ case 0x6:
+ if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+ TimeValue = 25;
+ } else {
+ TimeValue = 26;
+ }
+ break;
+
+ case 0x7:
+ TimeValue = 30;
+ break;
+
+ case 0x8:
+ TimeValue = 35;
+ break;
+
+ case 0x9:
+ TimeValue = 40;
+ break;
+
+ case 0xA:
+ TimeValue = 45;
+ break;
+
+ case 0xB:
+ if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+ TimeValue = 50;
+ } else {
+ TimeValue = 52;
+ }
+ break;
+
+ case 0xC:
+ TimeValue = 55;
+ break;
+
+ case 0xD:
+ TimeValue = 60;
+ break;
+
+ case 0xE:
+ TimeValue = 70;
+ break;
+
+ case 0xF:
+ TimeValue = 80;
+ break;
+
+ default:
+ LOG_ERROR ("Invalid parameter");
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *MaxClkFreqHz = (TransferRateBitPerSecond * TimeValue) / 10;
+
+ LOG_TRACE (
+ "TransferRateUnitId=%d TimeValue*10=%d, CardFrequency=%dKHz",
+ (Csd->TRAN_SPEED & 0x7),
+ TimeValue,
+ *MaxClkFreqHz / 1000);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSetMaxClockFrequency (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ EFI_SDHC_PROTOCOL *HostExt = HostInst->HostExt;
+ EFI_STATUS Status;
+ UINT32 MaxClkFreqHz = 0;
+
+ //
+ // Currently only NormalSpeed and HighSpeed supported
+ //
+ ASSERT (HostInst->CardInfo.CurrentSpeedMode == CardSpeedModeNormalSpeed ||
+ HostInst->CardInfo.CurrentSpeedMode == CardSpeedModeHighSpeed);
+
+ if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+ Status = CalculateCardMaxFreq (HostInst, &MaxClkFreqHz);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ if (HostInst->CardInfo.CurrentSpeedMode == CardSpeedModeNormalSpeed) {
+ Status = CalculateCardMaxFreq (HostInst, &MaxClkFreqHz);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else if (HostInst->CardInfo.CurrentSpeedMode == CardSpeedModeHighSpeed) {
+ MaxClkFreqHz = MMC_HIGH_SPEED_MODE_CLOCK_FREQ_HZ;
+ }
+ }
+
+ Status = HostExt->SetClock (HostExt, MaxClkFreqHz);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSetBlockLength (
+ IN SDHC_INSTANCE *HostInst,
+ IN UINT32 BlockByteLength
+ )
+{
+ LOG_TRACE ("SdhcSetBlockLength(BlockByteLength=%d)", BlockByteLength);
+
+ return SdhcSendCommand (HostInst, &CmdSetBlockLength, BlockByteLength);
+}
+
+EFI_STATUS
+SdhcSetBlockCount (
+ IN SDHC_INSTANCE *HostInst,
+ IN UINT32 BlockCount,
+ IN BOOLEAN ReliableWrite
+ )
+{
+ UINT32 CmdArg;
+
+ LOG_TRACE (
+ "SdhcSetBlockCount(BlockCount=%d, ReliableWrite=%d)",
+ BlockCount,
+ ReliableWrite);
+
+ //
+ // JEDEC Standard No. 84-A441, Page 76
+ //
+ // Set bit[31] as 1 to indicate Reliable Write type of programming access.
+ //
+
+ if (ReliableWrite) {
+ CmdArg = BlockCount | (1 << 31);
+ } else {
+ CmdArg = BlockCount;
+ }
+
+ return SdhcSendCommand (HostInst, &CmdSetBlockCount, CmdArg);
+}
+
+EFI_STATUS
+SdhcSendStatus (
+ IN SDHC_INSTANCE *HostInst,
+ OUT CARD_STATUS *CardStatus
+ )
+{
+ EFI_STATUS Status;
+ UINT32 CmdArg;
+
+ LOG_TRACE ("SdhcSendStatus()");
+
+ CmdArg = HostInst->CardInfo.RCA << 16;
+
+ Status = SdhcSendCommand (HostInst, &CmdSendStatus, CmdArg);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CardStatus->AsUint32 = HostInst->CmdResponse[0];
+
+ return EFI_SUCCESS;
+}
+
+//
+// SD Specific Functions
+//
+
+EFI_STATUS
+SdhcSendScrSd (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ UINT32 CmdArg = HostInst->CardInfo.RCA << 16;
+ EFI_STATUS Status;
+
+ Status = SdhcSendDataCommand (
+ HostInst,
+ &CmdAppSendScrSd,
+ CmdArg,
+ sizeof (HostInst->BlockBuffer),
+ HostInst->BlockBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CopyMem (
+ &HostInst->CardInfo.Registers.Sd.Scr,
+ HostInst->BlockBuffer,
+ sizeof (SD_SCR));
+
+ SD_SCR *Scr = (SD_SCR*) &HostInst->BlockBuffer;
+ LOG_TRACE ("SD_SCR:");
+ LOG_TRACE (" SD_SPEC=%d", (UINT32) Scr->SD_SPEC);
+ LOG_TRACE (" SD_SPEC3=%d", (UINT32) Scr->SD_SPEC3);
+ LOG_TRACE (
+ " SD_BUS_WIDTHS=%x, 1-Bit?%d, 4-Bit?%d",
+ (UINT32) Scr->SD_BUS_WIDTH,
+ (UINT32) ((Scr->SD_BUS_WIDTH & BIT1) ? 1 : 0),
+ (UINT32) ((Scr->SD_BUS_WIDTH & BIT2) ? 1 : 0));
+ LOG_TRACE (
+ " CMD_SUPPORT=%x, CMD23?%d, CMD20?%d",
+ (UINT32) Scr->CMD_SUPPORT,
+ (UINT32) ((Scr->CMD_SUPPORT & BIT2) ? 1 : 0),
+ (UINT32) ((Scr->CMD_SUPPORT & BIT1) ? 1 : 0));
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSendIfCondSd (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ SEND_IF_COND_ARG CmdArg = { 0 };
+
+ //
+ // Recommended check pattern per SD Specs
+ //
+ CmdArg.Fields.CheckPattern = 0xAA;
+
+ //
+ // Our current implementation does not support more than HighSpeed voltage 2V7-3V6 (i.e no 1V8)
+ //
+ CmdArg.Fields.VoltageSupplied = SD_CMD8_VOLTAGE_27_36;
+
+ EFI_STATUS Status = SdhcSendCommand (HostInst, &CmdSendIfCondSd, CmdArg.AsUint32);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SEND_IF_COND_CMD_RESPONSE CmdStatus;
+ CmdStatus.AsUint32 = HostInst->CmdResponse[0];
+
+ if (CmdStatus.Fields.CheckPattern != CmdArg.Fields.CheckPattern ||
+ CmdStatus.Fields.VoltageSupplied != CmdArg.Fields.VoltageSupplied) {
+ return EFI_UNSUPPORTED;
+ }
+
+ HostInst->CardInfo.HasExtendedOcr = TRUE;
+
+ return EFI_SUCCESS;;
+}
+
+EFI_STATUS
+SdhcSendOpCondSd (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // With arg set to 0, it means read OCR
+ //
+ Status = SdhcSendCommand (HostInst, &CmdAppSendOpCondSd, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HostInst->CardInfo.Registers.Sd.Ocr.AsUint32 = HostInst->CmdResponse[0];
+
+ SD_SEND_OP_COND_ARG CmdArg = { 0 };
+ UINT32 Retry = SDMMC_POLL_WAIT_COUNT;
+ SD_OCR Ocr;
+ SD_OCR_EX *OcrEx;
+
+ CmdArg.Fields.VoltageWindow = HostInst->CardInfo.Registers.Sd.Ocr.Fields.VoltageWindow;
+ //
+ // Host support for High Capacity is assumed
+ //
+ CmdArg.Fields.HCS = 1;
+
+ while (Retry) {
+ Status = SdhcSendCommand (HostInst, &CmdAppSendOpCondSd, CmdArg.AsUint32);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Ocr.AsUint32 = HostInst->CmdResponse[0];
+
+ if (Ocr.Fields.PowerUp) {
+ LOG_TRACE ("SD Card PowerUp Complete");
+ if (HostInst->CardInfo.HasExtendedOcr) {
+ OcrEx = (SD_OCR_EX*) &Ocr;
+ if (OcrEx->Fields.CCS) {
+ LOG_TRACE ("Card is SD2.0 or later HighCapacity SDHC or SDXC");
+ HostInst->CardInfo.HighCapacity = TRUE;
+ } else {
+ LOG_TRACE ("Card is SD2.0 or later StandardCapacity SDSC");
+ HostInst->CardInfo.HighCapacity = FALSE;
+ }
+ }
+ break;
+ }
+ gBS->Stall (SDMMC_POLL_WAIT_TIME_US);
+ --Retry;
+ }
+
+ if (!Retry) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+SdhcSwitchBusWidthSd (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ EFI_SDHC_PROTOCOL *HostExt = HostInst->HostExt;
+ EFI_STATUS Status;
+ UINT32 CmdArg;
+
+ //Status = SdhcSendScrSd(HostInst);
+ //if (EFI_ERROR(Status)) {
+ // return Status;
+ //}
+
+ CmdArg = 0x2; // 4-bit
+ Status = SdhcSendCommand (HostInst, &CmdAppSetBusWidthSd, CmdArg);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = HostExt->SetBusWidth (HostExt, SdBusWidth4Bit);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSwitchSpeedModeSd (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ return EFI_SUCCESS;
+}
+
+//
+// SDIO Specific Functions
+//
+
+EFI_STATUS
+SdhcSendOpCondSdio (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ return SdhcSendCommand (HostInst, &CmdSendOpCondSdio, 0);
+}
+
+//
+// Mmc Specific Functions
+//
+
+EFI_STATUS
+SdhcSendOpCondMmc (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ EFI_STATUS Status;
+ MMC_SEND_OP_COND_ARG CmdArg = { 0 };
+ UINT32 Retry = SDMMC_POLL_WAIT_COUNT;
+ MMC_OCR *Ocr = &HostInst->CardInfo.Registers.Mmc.Ocr;
+
+ CmdArg.Fields.VoltageWindow = SD_OCR_HIGH_VOLTAGE_WINDOW;
+ CmdArg.Fields.AccessMode = SdOcrAccessSectorMode;
+
+ while (Retry) {
+ Status = SdhcSendCommand (HostInst, &CmdSendOpCondMmc, CmdArg.AsUint32);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HostInst->CardInfo.Registers.Mmc.Ocr.AsUint32 = HostInst->CmdResponse[0];
+
+ if (Ocr->Fields.PowerUp) {
+ LOG_TRACE ("MMC Card PowerUp Complete");
+ if (Ocr->Fields.AccessMode == SdOcrAccessSectorMode) {
+ LOG_TRACE ("Card is MMC HighCapacity");
+ HostInst->CardInfo.HighCapacity = TRUE;
+ } else {
+ LOG_TRACE ("Card is MMC StandardCapacity");
+ HostInst->CardInfo.HighCapacity = FALSE;
+ }
+
+ if ((Ocr->Fields.VoltageWindow & SD_OCR_HIGH_VOLTAGE_WINDOW) != SD_OCR_HIGH_VOLTAGE_WINDOW) {
+ LOG_ERROR (
+ "MMC Card does not support High Voltage, expected profile:%x actual profile:%x",
+ (UINT32) SD_OCR_HIGH_VOLTAGE_WINDOW,
+ (UINT32) Ocr->Fields.VoltageWindow);
+ return EFI_UNSUPPORTED;
+ }
+
+ break;
+ }
+ gBS->Stall (SDMMC_POLL_WAIT_TIME_US);
+ --Retry;
+ }
+
+ if (!Retry) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSwitchBusWidthMmc (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ EFI_SDHC_PROTOCOL *HostExt = HostInst->HostExt;
+ EFI_STATUS Status;
+ UINT32 CmdArg;
+ SD_BUS_WIDTH BusWidth = SdBusWidth8Bit;
+ MMC_EXT_CSD *ExtCsd = &HostInst->CardInfo.Registers.Mmc.ExtCsd;
+ UINT8 ExtCsdPowerClass;
+ MMC_SWITCH_CMD_ARG SwitchCmdArg;
+
+ Status = SdhcSendExtCsdMmc (HostInst);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Figure out current requirements for target bus width. An inrease in current consumption
+ // may require switching the card to a higher power class
+ //
+ if (BusWidth == SdBusWidth8Bit) {
+ if (HostInst->CardInfo.CurrentSpeedMode == CardSpeedModeHighSpeed) {
+ ExtCsdPowerClass = MMC_EXT_CSD_POWER_CLASS_8BIT (ExtCsd->PowerClass52Mhz36V);
+ } else {
+ ExtCsdPowerClass = MMC_EXT_CSD_POWER_CLASS_8BIT (ExtCsd->PowerClass26Mhz36V);
+ }
+ } else if (BusWidth == SdBusWidth4Bit) {
+ if (HostInst->CardInfo.CurrentSpeedMode == CardSpeedModeHighSpeed) {
+ ExtCsdPowerClass = MMC_EXT_CSD_POWER_CLASS_4BIT (ExtCsd->PowerClass52Mhz36V);
+ } else {
+ ExtCsdPowerClass = MMC_EXT_CSD_POWER_CLASS_4BIT (ExtCsd->PowerClass26Mhz36V);
+ }
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Only do power class switch if the target bus width requires more current than the
+ // allowed by the current power class in EXT_CSD
+ //
+ if (ExtCsdPowerClass > HostInst->CardInfo.Registers.Mmc.ExtCsd.PowerClass) {
+ CmdArg = ExtCsdPowerClass;
+ CmdArg <<= 8;
+ CmdArg |= 0x03BB0000;
+ Status = SdhcSendCommand (
+ HostInst,
+ &CmdSwitchMmc,
+ CmdArg);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("Error detected on switching PowerClass function");
+ return Status;
+ }
+
+ Status = SdhcSendExtCsdMmc (HostInst);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Sanity check that wanted power-class are set per requested
+ //
+ if (HostInst->CardInfo.Registers.Mmc.ExtCsd.PowerClass != ExtCsdPowerClass) {
+ LOG_ERROR (
+ "MMC EXT_CSD not reporting correct PowerClass after switch. Expected:%x Actual:%x",
+ (UINT32) ExtCsdPowerClass,
+ (UINT32) HostInst->CardInfo.Registers.Mmc.ExtCsd.PowerClass);
+ return EFI_PROTOCOL_ERROR;
+ }
+ }
+
+ //
+ // Switch bus width
+ //
+ SwitchCmdArg.AsUint32 = 0;
+ SwitchCmdArg.Fields.Access = MmcSwitchCmdAccessTypeWriteByte;
+ SwitchCmdArg.Fields.Index = MmcExtCsdBitIndexBusWidth;
+
+ if (BusWidth == SdBusWidth8Bit) {
+ SwitchCmdArg.Fields.Value = MmcExtCsdBusWidth8Bit;
+ } else {
+ SwitchCmdArg.Fields.Value = MmcExtCsdBusWidth4Bit;
+ }
+
+ Status = SdhcSendCommand (
+ HostInst,
+ &CmdSwitchMmc,
+ SwitchCmdArg.AsUint32);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("Error detected on switching BusWidth function");
+ return Status;
+ }
+
+ Status = HostExt->SetBusWidth (HostExt, BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSwitchSpeedModeMmc (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ EFI_STATUS Status;
+ MMC_SWITCH_CMD_ARG CmdArg;
+
+ CmdArg.AsUint32 = 0;
+ CmdArg.Fields.Access = MmcSwitchCmdAccessTypeWriteByte;
+ CmdArg.Fields.Index = MmcExtCsdBitIndexHsTiming;
+ CmdArg.Fields.Value = 1;
+
+ Status = SdhcSendCommand (
+ HostInst,
+ &CmdSwitchMmc,
+ CmdArg.AsUint32);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("Error detected on switching HighSpeed function");
+ return Status;
+ }
+
+ HostInst->CardInfo.CurrentSpeedMode = CardSpeedModeHighSpeed;
+
+ Status = SdhcSendExtCsdMmc (HostInst);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (!HostInst->CardInfo.Registers.Mmc.ExtCsd.HighSpeedTiming) {
+ LOG_ERROR ("MMC EXT_CSD not reporting HighSpeed timing after switch");
+ return EFI_PROTOCOL_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSendExtCsdMmc (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ EFI_STATUS Status;
+ UINT32 CmdArg;
+ MMC_EXT_CSD *ExtCsd;
+
+ CmdArg = HostInst->CardInfo.RCA << 16;
+ ExtCsd = &HostInst->CardInfo.Registers.Mmc.ExtCsd;
+
+ Status = SdhcSendDataCommand (
+ HostInst,
+ &CmdSendExtCsdMmc,
+ CmdArg,
+ sizeof (HostInst->BlockBuffer),
+ HostInst->BlockBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CopyMem (ExtCsd, HostInst->BlockBuffer, sizeof (MMC_EXT_CSD));
+
+ HostInst->CardInfo.ByteCapacity = (UINT64) ExtCsd->SectorCount * 512llu;
+ HostInst->BlockIo.Media->LastBlock = ExtCsd->SectorCount - 1;
+
+ HostInst->RpmbIo.ReliableSectorCount = ExtCsd->ReliableWriteSectorCount;
+ HostInst->RpmbIo.RpmbSizeMult = ExtCsd->RpmbSizeMult;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSwitchPartitionMmc (
+ IN SDHC_INSTANCE *HostInst,
+ IN MMC_EXT_CSD_PARTITION_ACCESS Partition
+ )
+{
+ EFI_STATUS Status;
+ MMC_SWITCH_CMD_ARG CmdArg;
+ MMC_EXT_CSD_PARTITION_CONFIG PartConfig;
+
+ LOG_TRACE (
+ "SdhcSwitchPartitionMmc(Partition=%a)",
+ MmcPartitionAccessToString (Partition));
+
+ PartConfig.AsUint8 = HostInst->CardInfo.Registers.Mmc.ExtCsd.PartitionConfig;
+ PartConfig.Fields.PARTITION_ACCESS = Partition;
+
+ //
+ // Write the partition type to EXT_CSD[PARTITION_CONFIG].PARTITION_ACCESS
+ //
+
+ ZeroMem (&CmdArg, sizeof (MMC_SWITCH_CMD_ARG));
+ CmdArg.Fields.Access = MmcSwitchCmdAccessTypeWriteByte;
+ CmdArg.Fields.Index = MmcExtCsdBitIndexPartitionConfig;
+ CmdArg.Fields.Value = PartConfig.AsUint8;
+
+ Status = SdhcSendCommand (HostInst, &CmdSwitchMmc, CmdArg.AsUint32);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSendCommand failed. (Status = %r)");
+ return Status;
+ }
+
+ //
+ // Re-read the EXT_CSD to verify the partition switch physically happenned
+ //
+ Status = SdhcSendExtCsdMmc (HostInst);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PartConfig.AsUint8 = HostInst->CardInfo.Registers.Mmc.ExtCsd.PartitionConfig;
+ if (PartConfig.Fields.PARTITION_ACCESS != Partition) {
+ LOG_ERROR (
+ "Current partition indicated by EXT_CSD doesn't match the "
+ "partition the MMC should have switched to. Expected:%a Actual:%a",
+ MmcPartitionAccessToString (Partition),
+ MmcPartitionAccessToString (PartConfig.Fields.PARTITION_ACCESS));
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ LOG_TRACE (
+ "Switched from partition %a to %a successfully",
+ MmcPartitionAccessToString (HostInst->CurrentMmcPartition),
+ MmcPartitionAccessToString (Partition));
+
+ HostInst->CurrentMmcPartition = Partition;
+
+ return EFI_SUCCESS;
+}
+
+//
+// SD command definitions
+//
+
+CONST SD_COMMAND CmdGoIdleState =
+{ 0,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeNone,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSendOpCondMmc =
+{ 1,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR3,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSendCidAll =
+{ 2,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR2,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSendRelativeAddr =
+{ 3,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR6,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSendOpCondSdio =
+{ 5,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR4,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSwitchSd =
+{ 6,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeSingleBlock,
+ SdTransferDirectionRead };
+
+CONST SD_COMMAND CmdSwitchMmc =
+{ 6,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1B,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdAppSetBusWidthSd =
+{ 6,
+ SdCommandTypeUndefined,
+ SdCommandClassApp,
+ SdResponseTypeR1,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSelect =
+{ 7,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1B,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdDeselect =
+{ 7,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeNone,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSendIfCondSd =
+{ 8,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR6,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSendExtCsdMmc =
+{ 8,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeSingleBlock,
+ SdTransferDirectionRead };
+
+CONST SD_COMMAND CmdSendCsd =
+{ 9,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR2,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSendCid =
+{ 10,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR2,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSwitchVoltageSd =
+{ 11,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdStopTransmission =
+{ 12,
+ SdCommandTypeAbort,
+ SdCommandClassStandard,
+ SdResponseTypeR1B,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSendStatus =
+{ 13,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdBusTestReadMmc =
+{ 14,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeSingleBlock,
+ SdTransferDirectionRead };
+
+CONST SD_COMMAND CmdSetBlockLength =
+{ 16,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdReadSingleBlock =
+{ 17,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeSingleBlock,
+ SdTransferDirectionRead };
+
+CONST SD_COMMAND CmdReadMultiBlock =
+{ 18,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeMultiBlock,
+ SdTransferDirectionRead };
+
+CONST SD_COMMAND CmdBusTestWriteMmc =
+{ 19,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeSingleBlock,
+ SdTransferDirectionWrite };
+
+CONST SD_COMMAND CmdSetBlockCount =
+{ 23,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdWriteSingleBlock =
+{ 24,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeSingleBlock,
+ SdTransferDirectionWrite };
+
+CONST SD_COMMAND CmdWriteMultiBlock =
+{ 25,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeMultiBlock,
+ SdTransferDirectionWrite };
+
+CONST SD_COMMAND CmdAppSendOpCondSd =
+{ 41,
+ SdCommandTypeUndefined,
+ SdCommandClassApp,
+ SdResponseTypeR3,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdAppSetClrCardDetectSd =
+{ 42,
+ SdCommandTypeUndefined,
+ SdCommandClassApp,
+ SdResponseTypeR1,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdAppSendScrSd =
+{ 51,
+ SdCommandTypeUndefined,
+ SdCommandClassApp,
+ SdResponseTypeR1,
+ SdTransferTypeSingleBlock,
+ SdTransferDirectionRead };
+
+CONST SD_COMMAND CmdAppSd =
+{ 55,
+ SdCommandTypeUndefined,
+ SdCommandClassApp,
+ SdResponseTypeR1,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/Protocol.h b/Platform/Microsoft/Drivers/SdMmcDxe/Protocol.h
new file mode 100644
index 000000000000..24cb9909373b
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/Protocol.h
@@ -0,0 +1,231 @@
+/** @file
+*
+* Copyright (c) Microsoft Corporation. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef __PROTOCOL_H__
+#define __PROTOCOL_H__
+
+EFI_STATUS
+InitializeDevice (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+InitializeSdDevice (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+InitializeMmcDevice (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcSendCommand (
+ IN SDHC_INSTANCE *HostInst,
+ IN CONST SD_COMMAND *Cmd,
+ IN UINT32 Arg
+ );
+
+EFI_STATUS
+SdhcSendDataCommand (
+ IN SDHC_INSTANCE *HostInst,
+ IN CONST SD_COMMAND *Cmd,
+ IN UINT32 Arg,
+ IN UINT32 BufferByteSize,
+ IN OUT VOID *Buffer
+ );
+
+// SD/SDIO/MMC Generic Functions
+
+EFI_STATUS
+SdhcRecoverFromErrors (
+ IN SDHC_INSTANCE *HostInst,
+ IN CONST SD_COMMAND *Cmd
+ );
+
+EFI_STATUS
+SdhcQueryCardType (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcGoIdleState (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcSendCidAll (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcSendRelativeAddr (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcWaitForTranStateAndReadyForData (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcSendCid (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcSendCsd (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcSendAppCmd (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcSelectDevice (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcDeselectDevice (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcStopTransmission (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcSetMaxClockFrequency (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcSetBlockLength (
+ IN SDHC_INSTANCE *HostInst,
+ IN UINT32 BlockByteLength
+ );
+
+EFI_STATUS
+SdhcSetBlockCount (
+ IN SDHC_INSTANCE *HostInst,
+ IN UINT32 BlockCount,
+ IN BOOLEAN ReliableWrite
+ );
+
+EFI_STATUS
+SdhcSendStatus (
+ IN SDHC_INSTANCE *HostInst,
+ OUT CARD_STATUS *CardStatus
+ );
+
+// SD Specific Functions
+
+EFI_STATUS
+SdhcSendScrSd (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcSendOpCondSd (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcSendIfCondSd (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcSwitchBusWidthSd (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcSwitchSpeedModeSd (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+// SDIO Specific Functions
+
+EFI_STATUS
+SdhcSendOpCondSdio (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+// MMC Specific Functions
+
+EFI_STATUS
+SdhcSendOpCondMmc (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcSwitchBusWidthMmc (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+
+EFI_STATUS
+SdhcSwitchSpeedModeMmc (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcSendExtCsdMmc (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+EFI_STATUS
+SdhcSwitchPartitionMmc (
+ IN SDHC_INSTANCE *HostInst,
+ IN MMC_EXT_CSD_PARTITION_ACCESS Partition
+ );
+
+// SD/MMC Commands
+
+extern CONST SD_COMMAND CmdGoIdleState;
+extern CONST SD_COMMAND CmdSendOpCondMmc;
+extern CONST SD_COMMAND CmdSendCidAll;
+extern CONST SD_COMMAND CmdSendRelativeAddr;
+extern CONST SD_COMMAND CmdSendOpCondSdio;
+extern CONST SD_COMMAND CmdSwitchSd;
+extern CONST SD_COMMAND CmdSwitchMmc;
+extern CONST SD_COMMAND CmdAppSetBusWidthSd;
+extern CONST SD_COMMAND CmdSelect;
+extern CONST SD_COMMAND CmdDeselect;
+extern CONST SD_COMMAND CmdSendIfCondSd;
+extern CONST SD_COMMAND CmdSendExtCsdMmc;
+extern CONST SD_COMMAND CmdSendCsd;
+extern CONST SD_COMMAND CmdSendCid;
+extern CONST SD_COMMAND CmdSwitchVoltageSd;
+extern CONST SD_COMMAND CmdStopTransmission;
+extern CONST SD_COMMAND CmdSendStatus;
+extern CONST SD_COMMAND CmdBusTestReadMmc;
+extern CONST SD_COMMAND CmdSetBlockLength;
+extern CONST SD_COMMAND CmdReadSingleBlock;
+extern CONST SD_COMMAND CmdReadMultiBlock;
+extern CONST SD_COMMAND CmdBusTestWriteMmc;
+extern CONST SD_COMMAND CmdSetBlockCount;
+extern CONST SD_COMMAND CmdWriteSingleBlock;
+extern CONST SD_COMMAND CmdWriteMultiBlock;
+extern CONST SD_COMMAND CmdAppSendOpCondSd;
+extern CONST SD_COMMAND CmdAppSetClrCardDetectSd;
+extern CONST SD_COMMAND CmdAppSendScrSd;
+extern CONST SD_COMMAND CmdAppSd;
+
+#endif // __PROTOCOL_H__
diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/RpmbIo.c b/Platform/Microsoft/Drivers/SdMmcDxe/RpmbIo.c
new file mode 100644
index 000000000000..69ca29a6aba9
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/RpmbIo.c
@@ -0,0 +1,611 @@
+/** @file
+*
+* Copyright (c) Microsoft Corporation. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Sdhc.h>
+#include <Protocol/RpmbIo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include "SdMmcHw.h"
+#include "SdMmc.h"
+#include "Protocol.h"
+
+C_ASSERT(sizeof(EFI_RPMB_DATA_PACKET) == SD_BLOCK_LENGTH_BYTES);
+
+EFI_RPMB_DATA_PACKET ResultRequest = {
+ { 0 }, // Stuff
+ { 0 }, // MAC
+ { 0 }, // Data
+ { 0 }, // Nonce
+ { 0 }, // WriteCounter
+ { 0 }, // Address
+ { 0 }, // PacketCount
+ { 0 }, // OperationResult
+ { 0x00, EFI_RPMB_REQUEST_RESULT_REQUEST } // RequestType
+};
+
+// JEDEC Standard No. 84-A441:
+// Byte order of the RPMB data frame is MSB first, e.g. Write Counter MSB [11]
+// is storing the upmost byte of the counter value.
+
+VOID
+Uint16ToRpmbBytes (
+ IN UINT16 Value,
+ OUT UINT8 *RpmbBytes
+ )
+{
+ ASSERT (RpmbBytes != NULL);
+
+ RpmbBytes[0] = (UINT8) (Value >> 8);
+ RpmbBytes[1] = (UINT8) (Value & 0xF);
+}
+
+
+UINT16
+RpmbBytesToUint16 (
+ IN CONST UINT8 *RpmbBytes
+ )
+{
+ ASSERT (RpmbBytes != NULL);
+
+ return ((UINT16) RpmbBytes[0] << 8) | ((UINT16) RpmbBytes[1]);
+}
+
+EFI_STATUS
+RpmbRead (
+ IN SDHC_INSTANCE *HostInst,
+ IN EFI_RPMB_DATA_PACKET *Request,
+ OUT EFI_RPMB_DATA_BUFFER *Response
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SdhcSetBlockCount (HostInst, 1, FALSE);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSetBlockCount() failed. (Status = %r)", Status);
+ return Status;
+ }
+
+ Status = SdhcSendDataCommand (
+ HostInst,
+ &CmdWriteMultiBlock,
+ 0, // LBA argument is ignored for RPMB access, the eMMC will use instead the Address
+ // field of the RPMB packet
+ sizeof (*Request),
+ Request);
+
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "Failed to write the Read request data packet. (Status = %r)",
+ Status);
+
+ return Status;
+ }
+
+ Status = SdhcSetBlockCount (HostInst, Response->PacketCount, FALSE);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSetBlockCount() failed. (Status = %r)", Status);
+ return Status;
+ }
+
+ Status = SdhcSendDataCommand (
+ HostInst,
+ &CmdReadMultiBlock,
+ 0, // LBA argument is ignored for RPMB access, the eMMC will use instead the Address
+ // field of the RPMB packet
+ Response->PacketCount * sizeof(*Response->Packets),
+ Response->Packets);
+
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "Failed to read the Read request data packet. (Status = %r)",
+ Status);
+
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RpmbWrite (
+ IN SDHC_INSTANCE *HostInst,
+ IN EFI_RPMB_DATA_BUFFER *Request
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SdhcSetBlockCount (HostInst, Request->PacketCount, TRUE);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SdhcSetBlockCount() failed. (Status = %r)", Status);
+ return Status;
+ }
+
+ Status = SdhcSendDataCommand (
+ HostInst,
+ &CmdWriteMultiBlock,
+ 0, // LBA argument is ignored for RPMB access, the eMMC will use instead the Address
+ // field of the RPMB packet
+ Request->PacketCount * sizeof(*Request->Packets),
+ Request->Packets);
+
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "Failed to write the Read request data packet. (Status = %r)",
+ Status);
+
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RpmbQueryResult (
+ IN SDHC_INSTANCE *HostInst,
+ OUT EFI_RPMB_DATA_PACKET *Response
+ )
+{
+ EFI_STATUS Status;
+ EFI_RPMB_DATA_BUFFER ResponseBuffer;
+
+ ResponseBuffer.PacketCount = 1;
+ ResponseBuffer.Packets = Response;
+
+ Status = RpmbRead (HostInst, &ResultRequest, &ResponseBuffer);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("RpmbRead() failed. (Status = %r)", Status);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RpmbProgramKeyRequest (
+ IN SDHC_INSTANCE *HostInst,
+ IN EFI_RPMB_DATA_PACKET *Request,
+ OUT EFI_RPMB_DATA_PACKET *Response
+ )
+{
+ EFI_STATUS Status;
+ EFI_RPMB_DATA_BUFFER RequestBuffer;
+
+ RequestBuffer.PacketCount = 1;
+ RequestBuffer.Packets = Request;
+
+ Status = RpmbWrite (HostInst, &RequestBuffer);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("RpmbWrite() failed. (Status = %r)", Status);
+ return Status;
+ }
+
+ Status = RpmbQueryResult (HostInst, Response);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("RpmbQueryResult() failed. (Status = %r)", Status);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RpmbReadCounterRequest (
+ IN SDHC_INSTANCE *HostInst,
+ IN EFI_RPMB_DATA_PACKET *Request,
+ OUT EFI_RPMB_DATA_PACKET *Response
+ )
+{
+ EFI_STATUS Status;
+ EFI_RPMB_DATA_BUFFER ResponseBuffer;
+
+ ResponseBuffer.PacketCount = 1;
+ ResponseBuffer.Packets = Response;
+
+ Status = RpmbRead (HostInst, Request, &ResponseBuffer);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("RpmbRead() failed. (Status = %r)", Status);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RpmbAuthenticatedWriteRequest (
+ IN SDHC_INSTANCE *HostInst,
+ IN EFI_RPMB_DATA_BUFFER *Request,
+ OUT EFI_RPMB_DATA_PACKET *Response
+ )
+{
+ EFI_STATUS Status;
+
+ Status = RpmbWrite (HostInst, Request);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("RpmbWrite() failed. (Status = %r)", Status);
+ return Status;
+ }
+
+ Status = RpmbQueryResult (HostInst, Response);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("RpmbQueryResult() failed. (Status = %r)", Status);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RpmbAuthenticatedReadRequest (
+ IN SDHC_INSTANCE *HostInst,
+ IN EFI_RPMB_DATA_PACKET *Request,
+ OUT EFI_RPMB_DATA_BUFFER *Response
+ )
+{
+ EFI_STATUS Status;
+
+ Status = RpmbRead (HostInst, Request, Response);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("RpmbRead() failed. (Status = %r)", Status);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+VOID
+RpmbHexDump (
+ IN CONST UINT8 *Bytes,
+ IN UINTN Len
+ )
+{
+ UINTN i;
+
+ for (i = 0; i < Len; i++) {
+ if ((i > 0) && (i % 16) == 0) {
+ LOG_VANILLA_TRACE ("\n");
+ }
+ LOG_VANILLA_TRACE ("%02x ", *Bytes);
+ ++Bytes;
+ }
+ LOG_VANILLA_TRACE ("\n");
+}
+
+VOID
+RpmbDumpPacket (
+ IN EFI_RPMB_DATA_PACKET *Packet
+ )
+{
+ LOG_TRACE ("*** RPMB Packet Dump (Packet = %p) ***", Packet);
+ LOG_TRACE ("- Write Counter");
+ RpmbHexDump (Packet->WriteCounter, EFI_RPMB_PACKET_WCOUNTER_SIZE);
+ LOG_TRACE ("- Address:");
+ RpmbHexDump (Packet->Address, EFI_RPMB_PACKET_ADDRESS_SIZE);
+ LOG_TRACE ("- Block Count:");
+ RpmbHexDump (Packet->BlockCount, EFI_RPMB_PACKET_BLOCKCOUNT_SIZE);
+ LOG_TRACE ("- Result:");
+ RpmbHexDump (Packet->OperationResult, EFI_RPMB_PACKET_RESULT_SIZE);
+ LOG_TRACE ("- Req/Res Type:");
+ RpmbHexDump (Packet->RequestOrResponseType, EFI_RPMB_PACKET_TYPE_SIZE);
+}
+
+EFI_STATUS
+RpmbRequest (
+ IN EFI_RPMB_IO_PROTOCOL *This,
+ IN EFI_RPMB_DATA_BUFFER *Request,
+ OUT EFI_RPMB_DATA_BUFFER *Response
+ )
+{
+ EFI_STATUS Status;
+ SDHC_INSTANCE *HostInst;
+ MMC_EXT_CSD_PARTITION_ACCESS CurrentPartition;
+ EFI_STATUS SwitchStatus;
+ BOOLEAN SwitchPartition;
+ UINT16 RequestType;
+
+ SwitchPartition = FALSE;
+ Status = EFI_SUCCESS;
+ SwitchStatus = EFI_SUCCESS;
+
+ ASSERT (This);
+ ASSERT (Request);
+ ASSERT (Response);
+
+ HostInst = SDHC_INSTANCE_FROM_RPMB_IO_THIS (This);
+ ASSERT (HostInst);
+ ASSERT (HostInst->HostExt);
+
+ CurrentPartition = HostInst->CurrentMmcPartition;
+
+ SwitchStatus = SdhcSwitchPartitionMmc (HostInst, MmcExtCsdPartitionAccessRpmb);
+ if (EFI_ERROR (SwitchStatus)) {
+
+ LOG_ERROR (
+ "SdhcSwitchPartitionMmc() failed. (SwitchStatus = %r)",
+ SwitchStatus);
+
+ goto Exit;
+ }
+
+ SwitchPartition = TRUE;
+
+ ASSERT (Request->PacketCount > 0);
+ ASSERT (Request->Packets != NULL);
+ RequestType = RpmbBytesToUint16 (Request->Packets[0].RequestOrResponseType);
+
+ switch (RequestType) {
+ case EFI_RPMB_REQUEST_PROGRAM_KEY:
+ Status = RpmbProgramKeyRequest (HostInst, Request->Packets, Response->Packets);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("RpmbProgramKeyRequest() failed. (Status = %r)", Status);
+ goto Exit;
+ }
+ break;
+
+ case EFI_RPMB_REQUEST_COUNTER_VALUE:
+ Status = RpmbReadCounterRequest (HostInst, Request->Packets, Response->Packets);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("RpmbReadCounterRequest() failed. (Status = %r)", Status);
+ goto Exit;
+ }
+ break;
+
+ case EFI_RPMB_REQUEST_AUTH_READ:
+ Status = RpmbAuthenticatedReadRequest (HostInst, Request->Packets, Response);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("RpmbAuthenticatedReadRequest() failed. (Status = %r)", Status);
+ goto Exit;
+ }
+ break;
+
+ case EFI_RPMB_REQUEST_AUTH_WRITE:
+ Status = RpmbAuthenticatedWriteRequest (HostInst, Request, Response->Packets);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("RpmbAuthenticatedWriteRequest() failed. (Status = %r)", Status);
+ goto Exit;
+ }
+ break;
+
+ default:
+
+ ASSERT (FALSE);
+ }
+
+Exit:
+
+ if (SwitchPartition) {
+ SwitchStatus = SdhcSwitchPartitionMmc (HostInst, CurrentPartition);
+ if (EFI_ERROR (SwitchStatus)) {
+
+ LOG_ERROR (
+ "SdhcSwitchPartitionMmc() failed. (SwitchStatus = %r)",
+ SwitchStatus);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ } else {
+ return SwitchStatus;
+ }
+}
+
+/** Authentication key programming request.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ProgrammingRequest A data packet describing a key programming request.
+ @param[out] ResultResponse A caller allocated data packet which will receive the
+ key programming result.
+
+ @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+ according to specs, other values are returned in case of any protocol error.
+ Failure during key programming any other eMMC internal failure is reported
+ in the Result field of the returned response data packet.
+**/
+EFI_STATUS
+EFIAPI
+RpmbIoProgramKey (
+ IN EFI_RPMB_IO_PROTOCOL *This,
+ IN EFI_RPMB_DATA_PACKET *ProgrammingRequest,
+ OUT EFI_RPMB_DATA_PACKET *ResultResponse
+ )
+{
+ EFI_STATUS Status;
+ EFI_RPMB_DATA_BUFFER RequestBuffer;
+ EFI_RPMB_DATA_BUFFER ResponseBuffer;
+
+ LOG_TRACE ("RpmbIoProgramKey()");
+
+ if ((This == NULL) || (ProgrammingRequest == NULL) || (ResultResponse == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (RpmbBytesToUint16 (ProgrammingRequest->RequestOrResponseType) != EFI_RPMB_REQUEST_PROGRAM_KEY) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RequestBuffer.PacketCount = 1;
+ RequestBuffer.Packets = ProgrammingRequest;
+
+ ResponseBuffer.PacketCount = 1;
+ ResponseBuffer.Packets = ResultResponse;
+
+ Status = RpmbRequest (This, &RequestBuffer, &ResponseBuffer);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("RpmbRequest() failed. (Status = %r)", Status);
+ return Status;
+ }
+
+ return Status;
+}
+
+/** Reading of the write counter value request.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ReadRequest A data packet describing a read counter value request.
+ @param[out] ReadResponse A caller allocated data packet which will receive
+ the counter value read response. If counter has expired bit 7 is set to 1 in
+ returned Result.
+
+ @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+ according to specs, other values are returned in case of any protocol error.
+ Failure during counter read or any other eMMC internal failure is reported
+ in the Result field of the returned response data packet.
+**/
+EFI_STATUS
+EFIAPI
+RpmbIoReadCounter (
+ IN EFI_RPMB_IO_PROTOCOL *This,
+ IN EFI_RPMB_DATA_PACKET *ReadRequest,
+ OUT EFI_RPMB_DATA_PACKET *ReadResponse
+ )
+{
+ EFI_STATUS Status;
+ EFI_RPMB_DATA_BUFFER RequestBuffer;
+ EFI_RPMB_DATA_BUFFER ResponseBuffer;
+
+ LOG_TRACE ("RpmbIoReadCounter()");
+
+ if ((This == NULL) || (ReadRequest == NULL) || (ReadResponse == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (RpmbBytesToUint16 (ReadRequest->RequestOrResponseType) != EFI_RPMB_REQUEST_COUNTER_VALUE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RequestBuffer.PacketCount = 1;
+ RequestBuffer.Packets = ReadRequest;
+
+ ResponseBuffer.PacketCount = 1;
+ ResponseBuffer.Packets = ReadResponse;
+
+ Status = RpmbRequest (This, &RequestBuffer, &ResponseBuffer);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("RpmbRequest() failed. (Status = %r)", Status);
+ return Status;
+ }
+
+ return Status;
+}
+
+/** Authenticated data write request.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] WriteRequest A sequence of data packets describing data write
+ requests and holds the data to be written.
+ @param[out] ResultResponse A caller allocated data packet which will receive
+ the data write programming result.
+
+ @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+ according to specs, other values are returned in case of any protocol error.
+ Failure during data programming or any other eMMC internal failure is reported
+ in the Result field of the returned data packet.
+**/
+EFI_STATUS
+EFIAPI
+RpmbIoAuthenticatedWrite (
+ IN EFI_RPMB_IO_PROTOCOL *This,
+ IN EFI_RPMB_DATA_BUFFER *Request,
+ OUT EFI_RPMB_DATA_PACKET *Response
+ )
+{
+ EFI_STATUS Status;
+ EFI_RPMB_DATA_BUFFER ResponseBuffer;
+
+ LOG_TRACE ("RpmbIoAuthenticatedWrite()");
+
+ if ((This == NULL) || (Request == NULL) || (Response == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Request->Packets == NULL) || (Request->PacketCount == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (RpmbBytesToUint16 (Request->Packets->RequestOrResponseType) != EFI_RPMB_REQUEST_AUTH_WRITE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ResponseBuffer.PacketCount = 1;
+ ResponseBuffer.Packets = Response;
+
+ Status = RpmbRequest (This, Request, &ResponseBuffer);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("RpmbRequest() failed. (Status = %r)", Status);
+ return Status;
+ }
+
+ return Status;
+}
+
+/** Authenticated data read request.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ReadRequest A data packet that describes a data read request.
+ @param[out] ReadResponse A caller allocated data packets which will receive
+ the data read.
+
+ @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+ according to specs, other values are returned in case of any protocol error.
+ Failure during data fetch from the eMMC or any other eMMC internal failure
+ is reported in the Result field of the returned data packet.
+**/
+EFI_STATUS
+EFIAPI
+RpmbIoAuthenticatedRead (
+ IN EFI_RPMB_IO_PROTOCOL *This,
+ IN EFI_RPMB_DATA_PACKET *ReadRequest,
+ OUT EFI_RPMB_DATA_BUFFER *ReadResponse
+ )
+{
+ EFI_STATUS Status;
+ EFI_RPMB_DATA_BUFFER RequestBuffer;
+
+ LOG_TRACE ("RpmbIoAuthenticatedRead()");
+
+ if ((This == NULL) || (ReadRequest == NULL) || (ReadResponse == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((ReadResponse->Packets == NULL) || (ReadResponse->PacketCount == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (RpmbBytesToUint16 (ReadRequest->RequestOrResponseType) != EFI_RPMB_REQUEST_AUTH_READ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RequestBuffer.PacketCount = 1;
+ RequestBuffer.Packets = ReadRequest;
+
+ Status = RpmbRequest (This, &RequestBuffer, ReadResponse);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("RpmbRequest() failed. (Status = %r)", Status);
+ return Status;
+ }
+
+ return Status;
+}
diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.c b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.c
new file mode 100644
index 000000000000..bf4ec4ba8954
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.c
@@ -0,0 +1,892 @@
+/** @file
+*
+* Copyright (c) Microsoft Corporation. All rights reserved.
+* Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Sdhc.h>
+#include <Protocol/RpmbIo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include "SdMmcHw.h"
+#include "SdMmc.h"
+#include "Protocol.h"
+
+// A template EFI_BLOCK_IO media to use for creating new EFI_BLOCK_IO protocols
+// for new SDHC instances.
+EFI_BLOCK_IO_MEDIA gSdhcMediaTemplate = {
+ 0, // MediaId
+ TRUE, // RemovableMedia
+ FALSE, // MediaPresent
+ FALSE, // LogicalPartition
+ FALSE, // ReadOnly
+ FALSE, // WriteCaching
+ SD_BLOCK_LENGTH_BYTES, // BlockSize
+ 4, // IoAlign
+ 0, // Pad
+ 0 // LastBlock
+};
+
+// This structure is serviced as a header.Its next field points to the first root
+// bridge device node.
+LIST_ENTRY gSdhcInstancePool;
+UINT32 gNextSdhcInstanceId = 0;
+
+// Event triggered by the timer to check if any cards have been removed
+// or if new ones have been plugged in.
+EFI_EVENT gCheckCardsEvent;
+
+// The ARM high-performance counter frequency.
+UINT64 gHpcTicksPerSeconds = 0;
+
+VOID
+EFIAPI
+CheckCardsCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+EFI_STATUS
+EFIAPI
+UninstallAllProtocols (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+BOOLEAN
+EFIAPI
+IsRpmbInstalledOnTheSystem (
+ VOID
+ );
+
+/** Initialize the SDHC Pool to support multiple SD/MMC devices.
+**/
+VOID
+InitializeSdhcPool (
+ VOID
+ )
+{
+ InitializeListHead (&gSdhcInstancePool);
+}
+
+/** Insert a new SDHC instance in the host pool.
+
+ @param[in] HostInst The SDHC instance context data.
+**/
+VOID
+InsertSdhcInstance (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ InsertTailList (&gSdhcInstancePool, &(HostInst->Link));
+}
+
+/** Removes an existing SDHC instance context data from the host pool.
+
+ @param[in] HostInst The SDHC instance data.
+**/
+VOID
+RemoveSdhcInstance (
+ IN SDHC_INSTANCE *HostInst
+)
+{
+ RemoveEntryList (&(HostInst->Link));
+}
+
+/** Creates a new SDHC instance context data.
+
+ It initializes the context data but does not attempt to perform any hardware
+ access nor install any EFI protocol. This happens later on when a card presence
+ state changes during the card check callback.
+
+ @param[in] HostExt The EFI_SDHC_PROTOCOL instance data to use as the basis for
+ SDHC instance context data creation.
+
+ @retval An SDHC instance context data on successful instance creation and return
+ NULL otherwise.
+**/
+SDHC_INSTANCE*
+CreateSdhcInstance (
+ IN EFI_SDHC_PROTOCOL *HostExt
+ )
+{
+ EFI_STATUS Status;
+ SDHC_INSTANCE *HostInst = NULL;
+
+ HostInst = AllocateZeroPool (sizeof (SDHC_INSTANCE));
+ if (HostInst == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ HostInst->Signature = SDHC_INSTANCE_SIGNATURE;
+ HostInst->InstanceId = gNextSdhcInstanceId;
+ HostInst->HostExt = HostExt;
+
+ HostExt->GetCapabilities (HostExt, &HostInst->HostCapabilities);
+ ASSERT (HostInst->HostCapabilities.MaximumBlockSize > 0);
+ ASSERT (HostInst->HostCapabilities.MaximumBlockCount > 0);
+
+ // We will support 512 byte blocks only.
+ if (HostInst->HostCapabilities.MaximumBlockSize < SD_BLOCK_LENGTH_BYTES) {
+ LOG_ERROR (
+ "Unsupported max block size of %d bytes",
+ HostInst->HostCapabilities.MaximumBlockSize);
+ Status = EFI_UNSUPPORTED;
+ goto Exit;
+ }
+
+ LOG_TRACE (
+ "Host Capabilities: MaximumBlockSize:%d MaximumBlockCount:%d",
+ HostInst->HostCapabilities.MaximumBlockSize,
+ HostInst->HostCapabilities.MaximumBlockCount);
+
+ HostInst->DevicePathProtocolInstalled = FALSE;
+ HostInst->BlockIoProtocolInstalled = FALSE;
+ HostInst->RpmbIoProtocolInstalled = FALSE;
+
+ // Initialize BlockIo Protocol.
+
+ HostInst->BlockIo.Media = AllocateCopyPool (sizeof (EFI_BLOCK_IO_MEDIA), &gSdhcMediaTemplate);
+ if (HostInst->BlockIo.Media == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ HostInst->BlockIo.Revision = EFI_BLOCK_IO_INTERFACE_REVISION;
+ HostInst->BlockIo.Reset = BlockIoReset;
+ HostInst->BlockIo.ReadBlocks = BlockIoReadBlocks;
+ HostInst->BlockIo.WriteBlocks = BlockIoWriteBlocks;
+ HostInst->BlockIo.FlushBlocks = BlockIoFlushBlocks;
+
+ // Initialize DevicePath Protocol.
+
+ SDHC_DEVICE_PATH *DevicePath = &HostInst->DevicePath;
+
+ // Initialize device path based on SDHC DeviceId and delay SlotNode initialization
+ // until the card in Slot0 is type identified.
+
+ DevicePath->SdhcNode.Header.Type = HARDWARE_DEVICE_PATH;
+ DevicePath->SdhcNode.Header.SubType = HW_VENDOR_DP;
+ *((UINT16*) &DevicePath->SdhcNode.Header.Length) = SDHC_NODE_PATH_LENGTH;
+ DevicePath->SdhcId = HostInst->HostExt->SdhcId;
+ GUID SdhcDevicePathGuid = SDHC_DEVICE_PATH_GUID;
+ CopyGuid (&DevicePath->SdhcNode.Guid, &SdhcDevicePathGuid);
+
+ SetDevicePathEndNode (&DevicePath->EndNode);
+
+ // Initialize RpmbIo Protocol.
+
+ HostInst->RpmbIo.Revision = EFI_RPMB_IO_PROTOCOL_REVISION;
+ HostInst->RpmbIo.AuthenticatedRead = RpmbIoAuthenticatedRead;
+ HostInst->RpmbIo.AuthenticatedWrite = RpmbIoAuthenticatedWrite;
+ HostInst->RpmbIo.ProgramKey = RpmbIoProgramKey;
+ HostInst->RpmbIo.ReadCounter = RpmbIoReadCounter;
+
+ // Don't publish any protocol yet, until the SDHC device is fully initialized and
+ // ready for IO.
+
+ ++gNextSdhcInstanceId;
+
+ Status = EFI_SUCCESS;
+
+Exit:
+ if (EFI_ERROR (Status)) {
+ if (HostInst != NULL && HostInst->BlockIo.Media != NULL) {
+ FreePool (HostInst->BlockIo.Media);
+ HostInst->BlockIo.Media = NULL;
+ }
+
+ if (HostInst != NULL) {
+ FreePool (HostInst);
+ HostInst = NULL;
+ }
+ }
+
+ return HostInst;
+}
+
+/** Destroys an existing SDHC instance context data.
+
+ It uninstalls all protocols installed on that instance, free allocated memory
+ and invokes the SDHC clean-up callback.
+
+ @param[in] HostInst The SDHC instance context data to destroy.
+
+ @retval EFI_SUCCESS on successful destruction and cleanup, return an EFI error
+ code otherwise.
+**/
+EFI_STATUS
+DestroySdhcInstance (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UninstallAllProtocols (HostInst);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Free Memory allocated for the EFI_BLOCK_IO protocol
+ if (HostInst->BlockIo.Media) {
+ FreePool (HostInst->BlockIo.Media);
+ }
+
+ HostInst->HostExt->Cleanup (HostInst->HostExt);
+ HostInst->HostExt = NULL;
+
+ FreePool (HostInst);
+
+ return EFI_SUCCESS;
+}
+
+// UEFI Driver Model EFI_DRIVER_BINDING_PROTOCOL Callbacks
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param ControllerHandle The handle of the controller to test. This handle must support a protocol
+ interface that supplies an I/O abstraction to the driver. Sometimes
+ just the presence of this I/O abstraction is enough for the driver to
+ determine if it supports ControllerHandle. Sometimes, the driver may
+ use the services of the I/O abstraction to determine if this driver
+ supports ControllerHandle.
+ @param RemainingDevicePath A pointer to the remaining portion of a device path. For bus drivers,
+ if this parameter is not NULL, then the bus driver must determine if
+ the bus controller specified by ControllerHandle and the child controller
+ specified by RemainingDevicePath
+**/
+EFI_STATUS
+EFIAPI
+SdMmcDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SDHC_PROTOCOL *HostExt;
+ EFI_DEV_PATH_PTR Node;
+
+ // Check RemainingDevicePath validation.
+ if (RemainingDevicePath != NULL) {
+
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, go on checking other conditions.
+ if (!IsDevicePathEnd (RemainingDevicePath)) {
+
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // check its validation.
+
+ Node.DevPath = RemainingDevicePath;
+ if (Node.DevPath->Type != HARDWARE_DEVICE_PATH ||
+ Node.DevPath->SubType != HW_VENDOR_DP ||
+ DevicePathNodeLength (Node.DevPath) != sizeof (VENDOR_DEVICE_PATH)) {
+ Status = EFI_UNSUPPORTED;
+ goto Exit;
+ }
+ }
+ }
+
+ // Check if SDHC protocol is installed by platform.
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSdhcProtocolGuid,
+ (VOID **) &HostExt,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER);
+ if (Status == EFI_ALREADY_STARTED) {
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ // Close the SDHC used to perform the supported test.
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSdhcProtocolGuid,
+ This->DriverBindingHandle,
+ Controller);
+
+Exit:
+ return Status;
+}
+
+/**
+ Starts a device controller or a bus controller. The Start() and Stop() services of the
+ EFI_DRIVER_BINDING_PROTOCOL mirror each other.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param ControllerHandle The handle of the controller to start. This handle must support a
+ protocol interface that supplies an I/O abstraction to the driver.
+ @param RemainingDevicePath A pointer to the remaining portion of a device path. For a bus driver,
+ if this parameter is NULL, then handles for all the children of Controller
+ are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is not
+ the End of Device Path Node, then only the handle for the child device
+ specified by the first Device Path Node of RemainingDevicePath is created
+ by this driver.
+ If the first Device Path Node of RemainingDevicePath is the End of Device
+ Path Node, no child handle is created by this driver.
+**/
+EFI_STATUS
+EFIAPI
+SdMmcDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ SDHC_INSTANCE *HostInst;
+ EFI_SDHC_PROTOCOL *HostExt;
+
+ LOG_TRACE ("SdMmcDriverStart()");
+
+ // Check RemainingDevicePath validation.
+ if (RemainingDevicePath != NULL) {
+
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, return EFI_SUCCESS.
+ if (IsDevicePathEnd (RemainingDevicePath)) {
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+
+ // Get the SDHC protocol.
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSdhcProtocolGuid,
+ (VOID **) &HostExt,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_ALREADY_STARTED) {
+ Status = EFI_SUCCESS;
+ }
+ goto Exit;
+ }
+
+ HostInst = CreateSdhcInstance (HostExt);
+ if (HostInst != NULL) {
+ HostInst->MmcHandle = Controller;
+ InsertSdhcInstance (HostInst);
+
+ LOG_INFO (
+ "SDHC%d instance creation completed. Detecting card presence...",
+ HostInst->HostExt->SdhcId);
+
+ // Detect card presence now which will initialize the SDHC.
+ CheckCardsCallback (NULL, NULL);
+ } else {
+ LOG_ERROR ("CreateSdhcInstance failed. %r", Status);
+ }
+
+Exit:
+ return Status;
+}
+
+/**
+ Stops a device controller or a bus controller. The Start() and Stop() services of the
+ EFI_DRIVER_BINDING_PROTOCOL mirror each other.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ Type EFI_DRIVER_BINDING_PROTOCOL is defined in Section 10.1.
+ @param ControllerHandle A handle to the device being stopped. The handle must support a bus
+ specific I/O protocol for the driver to use to stop the device.
+ @param NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param ChildHandleBuffer An array of child handles to be freed. May be NULL if NumberOfChildren is 0.
+**/
+EFI_STATUS
+EFIAPI
+SdMmcDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ LIST_ENTRY *CurrentLink;
+ SDHC_INSTANCE *HostInst;
+
+ LOG_TRACE ("SdMmcDriverStop()");
+
+ // For each registered SDHC instance.
+ CurrentLink = gSdhcInstancePool.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &gSdhcInstancePool && (Status == EFI_SUCCESS)) {
+ HostInst = SDHC_INSTANCE_FROM_LINK (CurrentLink);
+ ASSERT (HostInst != NULL);
+
+ // Close gEfiMmcHostProtocolGuid opened on the SDHC.
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiSdhcProtocolGuid,
+ (VOID **) &HostInst->HostExt,
+ This->DriverBindingHandle);
+
+ // Remove SDHC instance from the pool.
+ RemoveSdhcInstance (HostInst);
+
+ // Destroy SDHC instance.
+ DestroySdhcInstance (HostInst);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+SoftReset (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ EFI_SDHC_PROTOCOL *HostExt = HostInst->HostExt;
+ EFI_STATUS Status;
+ CHAR16 *DevicePathText = NULL;
+
+ ASSERT (HostInst->HostExt != NULL);
+ LOG_TRACE ("Performing Soft-Reset for SDHC%d", HostExt->SdhcId);
+
+ Status = UninstallAllProtocols (HostInst);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ HostInst->SlotInitialized = FALSE;
+
+ // Clear all media settings regardless of card presence.
+ HostInst->BlockIo.Media->MediaId = 0;
+ HostInst->BlockIo.Media->RemovableMedia = FALSE;
+ HostInst->BlockIo.Media->MediaPresent = FALSE;
+ HostInst->BlockIo.Media->LogicalPartition = FALSE;
+ HostInst->BlockIo.Media->WriteCaching = FALSE;
+ HostInst->BlockIo.Media->BlockSize = 0;
+ HostInst->BlockIo.Media->IoAlign = 4;
+ HostInst->BlockIo.Media->LastBlock = 0;
+ HostInst->BlockIo.Media->LowestAlignedLba = 0;
+ HostInst->BlockIo.Media->LogicalBlocksPerPhysicalBlock = 0;
+ HostInst->BlockIo.Media->OptimalTransferLengthGranularity = 0;
+ HostInst->BlockIo.Media->ReadOnly = FALSE;
+
+ HostInst->RpmbIo.ReliableSectorCount = 0;
+ HostInst->RpmbIo.RpmbSizeMult = 0;
+ ZeroMem (HostInst->RpmbIo.Cid, sizeof (HostInst->RpmbIo.Cid));
+
+ HostInst->BlockIo.Media->MediaPresent = HostInst->HostExt->IsCardPresent (HostInst->HostExt);
+ if (!HostInst->BlockIo.Media->MediaPresent) {
+ // Even if the media is not present, we`d like to communicate that status up
+ // to the storage stack by means of installing the BlockIo protocol.
+ Status =
+ gBS->InstallMultipleProtocolInterfaces (
+ &HostInst->MmcHandle,
+ &gEfiBlockIoProtocolGuid,
+ &HostInst->BlockIo,
+ NULL);
+
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "SoftReset(): Failed installing EFI_BLOCK_IO_PROTOCOL interface. %r",
+ Status);
+
+ goto Exit;
+ }
+
+ HostInst->BlockIoProtocolInstalled = TRUE;
+ LOG_INFO ("SDHC%d media not present, skipping device initialization", HostExt->SdhcId);
+ goto Exit;
+ } else {
+ HostInst->BlockIo.Media->ReadOnly = HostExt->IsReadOnly (HostExt);
+ if (HostInst->BlockIo.Media->ReadOnly) {
+ LOG_INFO ("SDHC%d media is read-only", HostExt->SdhcId);
+ }
+ }
+
+ Status = InitializeDevice (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SoftReset(): InitializeDevice() failed. %r", Status);
+ goto Exit;
+ }
+
+ // Update SlotNode subtype based on the card type identified.
+ // Note that we only support 1 slot per SDHC, i.e It is assumed that no more
+ // than 1 SD/MMC card connected to the same SDHC block on the system.
+ SDHC_DEVICE_PATH *DevicePath = &HostInst->DevicePath;
+ if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+ DevicePath->SlotNode.SD.Header.Type = MESSAGING_DEVICE_PATH;
+ DevicePath->SlotNode.SD.Header.SubType = MSG_SD_DP;
+ *((UINT16*) &DevicePath->SlotNode.SD.Header.Length) = sizeof (SD_DEVICE_PATH);
+ DevicePath->SlotNode.SD.SlotNumber = 0;
+ } else {
+ ASSERT (HostInst->CardInfo.CardFunction == CardFunctionMmc);
+ DevicePath->SlotNode.MMC.Header.Type = MESSAGING_DEVICE_PATH;
+ DevicePath->SlotNode.MMC.Header.SubType = MSG_EMMC_DP;
+ *((UINT16*) &DevicePath->SlotNode.MMC.Header.Length) = sizeof (EMMC_DEVICE_PATH);
+ DevicePath->SlotNode.MMC.SlotNumber = 0;
+ }
+
+ // Print a text representation of the Slot device path.
+ DevicePathText = ConvertDevicePathToText ((EFI_DEVICE_PATH_PROTOCOL*) DevicePath, FALSE, FALSE);
+
+ if (DevicePathText == NULL) {
+ LOG_ERROR ("SoftReset(): ConvertDevicePathToText() failed.");
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ LOG_INFO ("Recognized device: %s", DevicePathText);
+
+ Status =
+ gBS->InstallMultipleProtocolInterfaces (
+ &HostInst->MmcHandle,
+ &gEfiBlockIoProtocolGuid,
+ &HostInst->BlockIo,
+ NULL);
+
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "SoftReset(): Failed installing EFI_BLOCK_IO_PROTOCOL interface. %r",
+ Status);
+
+ goto Exit;
+ }
+
+ HostInst->BlockIoProtocolInstalled = TRUE;
+
+ Status =
+ gBS->InstallMultipleProtocolInterfaces (
+ &HostInst->MmcHandle,
+ &gEfiDevicePathProtocolGuid,
+ &HostInst->DevicePath,
+ NULL);
+
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "SoftReset(): Failed installing EFI_DEVICE_PATH_PROTOCOL interface. %r",
+ Status);
+
+ goto Exit;
+ }
+
+ HostInst->DevicePathProtocolInstalled = TRUE;
+
+ if (HostInst->CardInfo.CardFunction == CardFunctionMmc) {
+
+ if (!IsRpmbInstalledOnTheSystem ()) {
+ Status =
+ gBS->InstallMultipleProtocolInterfaces (
+ &HostInst->MmcHandle,
+ &gEfiRpmbIoProtocolGuid,
+ &HostInst->RpmbIo,
+ NULL);
+
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "SoftReset(): Failed installing EFI_RPMB_IO_PROTOCOL interface. %r",
+ Status);
+
+ goto Exit;
+ }
+
+ LOG_INFO ("RpmbIo protocol installed for MMC: %s", DevicePathText);
+
+ HostInst->RpmbIoProtocolInstalled = TRUE;
+
+ // Track current partition in a separate variable to void having to
+ // ready the MMC EXT_CSD everytime we do partition switch to have
+ // an updated current partition. SdhostSwitchPartitionMmc will keep
+ // track of that variable.
+
+ MMC_EXT_CSD_PARTITION_CONFIG partConfig;
+ partConfig.AsUint8 = HostInst->CardInfo.Registers.Mmc.ExtCsd.PartitionConfig;
+ HostInst->CurrentMmcPartition =
+ (MMC_EXT_CSD_PARTITION_ACCESS) partConfig.Fields.PARTITION_ACCESS;
+
+ } else {
+ LOG_ERROR (
+ "SoftReset(): RpmbIo protocol is already installed on the system. "
+ "The requirement is that only 1 MMC on the system should have RpmbIo "
+ "protocol installed. Skipping RpmbIo protocol installation for %s",
+ DevicePathText);
+ }
+ }
+
+ LOG_TRACE ("All required protocols installed successfully for %s", DevicePathText);
+
+Exit:
+
+ // On error we should uninstall all protocols except BlockIo, it should
+ // always be present since it represents the SDHC physical existance not
+ // the card, other protocols are card dependant and are pure representation
+ // of one or more card features
+ if (EFI_ERROR (Status)) {
+ if (HostInst->RpmbIoProtocolInstalled) {
+ Status =
+ gBS->UninstallMultipleProtocolInterfaces (
+ HostInst->MmcHandle,
+ &gEfiRpmbIoProtocolGuid,
+ &HostInst->RpmbIo,
+ NULL);
+
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "SoftReset(): Failed to uninstall EFI_RPMB_IO_PROTOCOL interface. %r",
+ Status);
+ } else {
+ HostInst->RpmbIoProtocolInstalled = FALSE;
+ }
+ }
+
+ if (HostInst->DevicePathProtocolInstalled) {
+ Status =
+ gBS->UninstallMultipleProtocolInterfaces (
+ HostInst->MmcHandle,
+ &gEfiDevicePathProtocolGuid,
+ &HostInst->DevicePath,
+ NULL);
+
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "SoftReset(): Failed to uninstall EFI_DEVICE_PATH_PROTOCOL interface. %r",
+ Status);
+ } else {
+ HostInst->DevicePathProtocolInstalled = FALSE;
+ }
+ }
+ }
+
+ if (DevicePathText != NULL) {
+ FreePool (DevicePathText);
+ }
+
+ return Status;
+}
+
+VOID
+EFIAPI
+CheckCardsCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ SDHC_INSTANCE *HostInst;
+ EFI_STATUS Status;
+ BOOLEAN IsCardPresent;
+ BOOLEAN CardEjected;
+ BOOLEAN CardInserted;
+
+ // For each registered SDHC instance
+ CurrentLink = gSdhcInstancePool.ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != &gSdhcInstancePool) {
+ HostInst = SDHC_INSTANCE_FROM_LINK (CurrentLink);
+ ASSERT (HostInst != NULL);
+
+ IsCardPresent = HostInst->HostExt->IsCardPresent (HostInst->HostExt);
+
+ // If card is present and not initialized or card no more present but was previously
+ // initialized, then reset the instance
+ //
+ // Present Initialized Outcome
+ // T T No action
+ // T F Reset
+ // F T Reset
+ // F F No action
+
+ CardEjected = HostInst->BlockIo.Media->MediaPresent && !IsCardPresent;
+ if (CardEjected) {
+ LOG_INFO ("Card ejected from SDHC%d slot", HostInst->HostExt->SdhcId);
+ }
+
+ CardInserted = !HostInst->BlockIo.Media->MediaPresent && IsCardPresent;
+ if (CardInserted) {
+ LOG_INFO ("Card inserted into SDHC%d slot", HostInst->HostExt->SdhcId);
+ }
+
+ if (CardEjected || CardInserted) {
+ Status = SoftReset (HostInst);
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR ("SoftReset() failed. %r", Status);
+ }
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+}
+
+BOOLEAN
+EFIAPI
+IsRpmbInstalledOnTheSystem (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_RPMB_IO_PROTOCOL rpmbIo;
+
+ Status = gBS->LocateProtocol (
+ &gEfiRpmbIoProtocolGuid,
+ NULL,
+ (VOID **) &rpmbIo);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+EFI_STATUS
+EFIAPI
+UninstallAllProtocols (
+ IN SDHC_INSTANCE *HostInst
+ )
+{
+ EFI_STATUS Status;
+
+ LOG_TRACE ("Uninstalling SDHC%d all protocols", HostInst->HostExt->SdhcId);
+
+ if (HostInst->BlockIoProtocolInstalled) {
+ Status =
+ gBS->UninstallMultipleProtocolInterfaces (
+ HostInst->MmcHandle,
+ &gEfiBlockIoProtocolGuid,
+ &HostInst->BlockIo,
+ NULL);
+
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "UninstallAllProtocols(): Failed to uninstall EFI_BLOCK_IO_PROTOCOL. "
+ "(Status = %r)",
+ Status);
+
+ return Status;
+ }
+
+ HostInst->BlockIoProtocolInstalled = FALSE;
+ }
+
+ if (HostInst->RpmbIoProtocolInstalled) {
+ Status =
+ gBS->UninstallMultipleProtocolInterfaces (
+ HostInst->MmcHandle,
+ &gEfiRpmbIoProtocolGuid,
+ &HostInst->RpmbIo,
+ NULL);
+
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "UninstallAllProtocols(): Failed to uninstall EFI_RPMB_IO_PROTOCOL. "
+ "(Status = %r)",
+ Status);
+
+ return Status;
+ }
+
+ HostInst->RpmbIoProtocolInstalled = FALSE;
+ }
+
+ if (HostInst->DevicePathProtocolInstalled) {
+ Status =
+ gBS->UninstallMultipleProtocolInterfaces (
+ HostInst->MmcHandle,
+ &gEfiDevicePathProtocolGuid,
+ &HostInst->DevicePath,
+ NULL);
+
+ if (EFI_ERROR (Status)) {
+ LOG_ERROR (
+ "UninstallAllProtocols(): Failed to uninstall EFI_DEVICE_PATH_PROTOCOL. "
+ "(Status = %r)",
+ Status);
+
+ return Status;
+ }
+
+ HostInst->DevicePathProtocolInstalled = FALSE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_DRIVER_BINDING_PROTOCOL gSdMmcDriverBindingCallbacks = {
+ SdMmcDriverSupported,
+ SdMmcDriverStart,
+ SdMmcDriverStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+EFI_STATUS
+EFIAPI
+SdMmcDxeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ LOG_TRACE ("SdMmcDxeInitialize");
+
+ InitializeSdhcPool ();
+
+ // Install driver model protocols.
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gSdMmcDriverBindingCallbacks,
+ ImageHandle,
+ NULL,
+ NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ // Use a timer to detect if a card has been plugged in or removed.
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL | EVT_TIMER,
+ TPL_CALLBACK,
+ CheckCardsCallback,
+ NULL,
+ &gCheckCardsEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->SetTimer (
+ gCheckCardsEvent,
+ TimerPeriodic,
+ (UINT64) (10 * 1000 * SDMMC_CHECK_CARD_INTERVAL_MS)); // 200 ms
+ ASSERT_EFI_ERROR (Status);
+
+ gHpcTicksPerSeconds = GetPerformanceCounterProperties (NULL, NULL);
+ ASSERT (gHpcTicksPerSeconds != 0);
+
+ return Status;
+}
diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.h b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.h
new file mode 100644
index 000000000000..c5c363fb963c
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.h
@@ -0,0 +1,529 @@
+/** @file
+*
+* Copyright (c) Microsoft Corporation. All rights reserved.
+* Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef __SDMMC_H__
+#define __SDMMC_H__
+
+// Define with non-zero to collect IO statistics and dump it to the terminal.
+#define SDMMC_COLLECT_STATISTICS 0
+
+// Define with non-zero to benchmark IO on the first MmcReadBlocks call and
+// dump to the terminal.
+#define SDMMC_BENCHMARK_IO 0
+
+// Lower bound of 2s poll wait time (200 x 10ms)
+#define SDMMC_POLL_WAIT_COUNT 200
+#define SDMMC_POLL_WAIT_TIME_US 10000
+
+// The period at which to check the presence state of each card on each
+// registered SDHC instance.
+#define SDMMC_CHECK_CARD_INTERVAL_MS 1000
+
+// The number of recursive error recoveries to reach before considering the
+// failure fatal, and not attempting more error recoveries.
+#define SDMMC_ERROR_RECOVERY_ATTEMPT_THRESHOLD 3
+
+// Logging Macros
+
+#define LOG_TRACE_FMT_HELPER(FMT, ...) "SdMmc[T]:" FMT "%a\n", __VA_ARGS__
+
+#define LOG_INFO_FMT_HELPER(FMT, ...) "SdMmc[I]:" FMT "%a\n", __VA_ARGS__
+
+#define LOG_ERROR_FMT_HELPER(FMT, ...) \
+ "SdMmc[E]:" FMT " (%a: %a, %d)\n", __VA_ARGS__
+
+#define LOG_INFO(...) \
+ DEBUG((DEBUG_INIT, LOG_INFO_FMT_HELPER(__VA_ARGS__, "")))
+
+#define LOG_VANILLA_TRACE(...) \
+ DEBUG((DEBUG_VERBOSE | DEBUG_BLKIO, __VA_ARGS__))
+
+#define LOG_TRACE(...) \
+ DEBUG((DEBUG_VERBOSE | DEBUG_BLKIO, LOG_TRACE_FMT_HELPER(__VA_ARGS__, "")))
+
+#define LOG_ERROR(...) \
+ DEBUG((DEBUG_ERROR, LOG_ERROR_FMT_HELPER(__VA_ARGS__, __FUNCTION__, __FILE__, __LINE__)))
+
+#define LOG_ASSERT(TXT) ASSERT(!"SdMmc[A]: " TXT "\n")
+
+#ifndef C_ASSERT
+#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
+#endif // C_ASSERT
+
+// Perform Integer division DIVIDEND/DIVISOR and return the result rounded up
+// or down to the nearest integer, where 3.5 and 3.75 are near 4, while 3.25
+// is near 3.
+#define INT_DIV_ROUND(DIVIDEND, DIVISOR) \
+ (((DIVIDEND) + ((DIVISOR) / 2)) / (DIVISOR))
+
+typedef struct {
+ UINT16 NumBlocks;
+ UINT16 Count;
+ UINT32 TotalTransferTimeUs;
+} IoReadStatsEntry;
+
+// Device Path Definitions
+//
+// eMMC and SD device paths got introduced in UEFI 2.6
+// Remove definitions below once code base migrates to UEFI 2.6
+
+#ifndef MSG_SD_DP
+// SD (Secure Digital) Device Path SubType.
+#define MSG_SD_DP 0x1A
+
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT8 SlotNumber;
+} SD_DEVICE_PATH;
+#endif // MSG_SD_DP
+
+#ifndef MSG_EMMC_DP
+// EMMC (Embedded MMC) Device Path SubType.
+#define MSG_EMMC_DP 0x1D
+
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT8 SlotNumber;
+} EMMC_DEVICE_PATH;
+#endif // MSG_EMMC_DP
+
+typedef struct {
+ VENDOR_DEVICE_PATH SdhcNode;
+ UINT32 SdhcId;
+ union {
+ EMMC_DEVICE_PATH MMC;
+ SD_DEVICE_PATH SD;
+ } SlotNode;
+ EFI_DEVICE_PATH EndNode;
+} SDHC_DEVICE_PATH;
+
+// GUID {AAFB8DAA-7340-43AC-8D49-0CCE14812489}
+#define SDHC_DEVICE_PATH_GUID \
+ { 0xaafb8daa, 0x7340, 0x43ac, { 0x8d, 0x49, 0xc, 0xce, 0x14, 0x81, 0x24, 0x89 } }
+
+// Size of SDHC node including the Sdhc ID field
+#define SDHC_NODE_PATH_LENGTH (sizeof(VENDOR_DEVICE_PATH) + sizeof(UINT32))
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ UINT32 InstanceId;
+ EFI_HANDLE MmcHandle;
+ BOOLEAN SlotInitialized;
+ BOOLEAN Disabled;
+ SDHC_DEVICE_PATH DevicePath;
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+ EFI_RPMB_IO_PROTOCOL RpmbIo;
+ EFI_SDHC_PROTOCOL *HostExt;
+ SDHC_CAPABILITIES HostCapabilities;
+ BOOLEAN DevicePathProtocolInstalled;
+ BOOLEAN BlockIoProtocolInstalled;
+ BOOLEAN RpmbIoProtocolInstalled;
+ MMC_EXT_CSD_PARTITION_ACCESS CurrentMmcPartition;
+ CARD_INFO CardInfo;
+ UINT32 BlockBuffer[SD_BLOCK_WORD_COUNT];
+ UINT32 CmdResponse[4];
+ CONST SD_COMMAND *PreLastSuccessfulCmd;
+ CONST SD_COMMAND *LastSuccessfulCmd;
+ UINT32 ErrorRecoveryAttemptCount;
+#ifdef MMC_COLLECT_STATISTICS
+ IoReadStatsEntry IoReadStats[1024];
+ UINT32 IoReadStatsNumEntries;
+#endif // COLLECT_IO_STATISTICS
+} SDHC_INSTANCE;
+
+#define SDHC_INSTANCE_SIGNATURE SIGNATURE_32('s', 'd', 'h', 'c')
+#define SDHC_INSTANCE_FROM_BLOCK_IO_THIS(a) \
+ CR(a, SDHC_INSTANCE, BlockIo, SDHC_INSTANCE_SIGNATURE)
+#define SDHC_INSTANCE_FROM_LINK(a) \
+ CR(a, SDHC_INSTANCE, Link, SDHC_INSTANCE_SIGNATURE)
+#define SDHC_INSTANCE_FROM_RPMB_IO_THIS(a) \
+ CR (a, SDHC_INSTANCE, RpmbIo, SDHC_INSTANCE_SIGNATURE)
+
+// The ARM high-performance counter frequency
+extern UINT64 gHpcTicksPerSeconds;
+
+// EFI_BLOCK_IO Protocol Callbacks
+
+/**
+ Reset the block device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.Reset().
+ It resets the block device hardware.
+ ExtendedVerification is ignored in this implementation.
+
+ @param This Indicates a pointer to the calling context.
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive
+ verification operation of the device during reset.
+
+ @retval EFI_SUCCESS The block device was reset.
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Reads the requested number of blocks from the device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks().
+ It reads the requested number of blocks from the device.
+ All the blocks are read, or an error is returned.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the read request is for.
+ @param Lba The starting logical block address to read from on the device.
+ @param BufferSize The size of the Buffer in bytes.
+ This must be a multiple of the intrinsic block size of the device.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes a specified number of blocks to the device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks().
+ It writes a specified number of blocks to the device.
+ All blocks are written, or an error is returned.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written.
+ @param BufferSize The size of the Buffer in bytes.
+ This must be a multiple of the intrinsic block size of the device.
+ @param Buffer Pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data were written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic
+ block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flushes all modified data to a physical block device.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data were written correctly to the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data.
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ );
+
+// EFI_RPMPB_IO Protocol Callbacks
+
+/** Authentication key programming request.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ProgrammingRequest A data packet describing a key programming request.
+ @param[out] ResultResponse A caller allocated data packet which will receive the
+ key programming result.
+
+ @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+ according to specs, other values are returned in case of any protocol error.
+ Failure during key programming any other eMMC internal failure is reported
+ in the Result field of the returned response data packet.
+**/
+EFI_STATUS
+EFIAPI
+RpmbIoProgramKey (
+ IN EFI_RPMB_IO_PROTOCOL *This,
+ IN EFI_RPMB_DATA_PACKET *Request,
+ OUT EFI_RPMB_DATA_PACKET *ResultResponse
+ );
+
+/** Reading of the write counter value request.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ReadRequest A data packet describing a read counter value request.
+ @param[out] ReadResponse A caller allocated data packet which will receive
+ the counter value read response. If counter has expired bit 7 is set to 1 in
+ returned Result.
+
+ @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+ according to specs, other values are returned in case of any protocol error.
+ Failure during counter read or any other eMMC internal failure is reported
+ in the Result field of the returned response data packet.
+**/
+EFI_STATUS
+EFIAPI
+RpmbIoReadCounter (
+ IN EFI_RPMB_IO_PROTOCOL *This,
+ IN EFI_RPMB_DATA_PACKET *ReadRequest,
+ OUT EFI_RPMB_DATA_PACKET *ReadResponse
+ );
+
+/** Authenticated data write request.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] WriteRequest A sequence of data packets describing data write
+ requests and holds the data to be written.
+ @param[out] ResultResponse A caller allocated data packet which will receive
+ the data write programming result.
+
+ @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+ according to specs, other values are returned in case of any protocol error.
+ Failure during data programming or any other eMMC internal failure is reported
+ in the Result field of the returned data packet.
+**/
+EFI_STATUS
+EFIAPI
+RpmbIoAuthenticatedWrite (
+ IN EFI_RPMB_IO_PROTOCOL *This,
+ IN EFI_RPMB_DATA_BUFFER *WriteRequest,
+ OUT EFI_RPMB_DATA_PACKET *ResultResponse
+ );
+
+/** Authenticated data read request.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ReadRequest A data packet that describes a data read request.
+ @param[out] ReadResponse A caller allocated data packets which will receive
+ the data read.
+
+ @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+ according to specs, other values are returned in case of any protocol error.
+ Failure during data fetch from the eMMC or any other eMMC internal failure
+ is reported in the Result field of the returned data packet.
+**/
+EFI_STATUS
+EFIAPI
+RpmbIoAuthenticatedRead (
+ IN EFI_RPMB_IO_PROTOCOL *This,
+ IN EFI_RPMB_DATA_PACKET *ReadRequest,
+ OUT EFI_RPMB_DATA_BUFFER *ReadResponse
+ );
+
+// Helper Functions
+
+EFI_STATUS
+EFIAPI
+SoftReset (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+// Debugging Helpers
+
+VOID
+PrintCsd (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+VOID
+PrintCid (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+VOID
+PrintCardStatus (
+ IN SDHC_INSTANCE *HostInst,
+ IN CARD_STATUS CardStatus
+ );
+
+VOID
+GetAndPrintCardStatus (
+ IN SDHC_INSTANCE *HostInst
+ );
+
+// Inlined Helper Functions
+
+__inline__
+static
+CONST CHAR8*
+MmcPartitionAccessToString (
+ IN MMC_EXT_CSD_PARTITION_ACCESS Partition
+ )
+{
+ switch (Partition) {
+ case MmcExtCsdPartitionAccessUserArea:
+ return "UserArea";
+ case MmcExtCsdPartitionAccessBootPartition1:
+ return "Boot1";
+ case MmcExtCsdPartitionAccessBootPartition2:
+ return "Boot2";
+ case MmcExtCsdPartitionAccessRpmb:
+ return "RPMB";
+ case MmcExtCsdPartitionAccessGpp1:
+ return "GeneralPurpose1";
+ case MmcExtCsdPartitionAccessGpp2:
+ return "GeneralPurpose2";
+ case MmcExtCsdPartitionAccessGpp3:
+ return "GeneralPurpose3";
+ case MmcExtCsdPartitionAccessGpp4:
+ return "GeneralPurpose4";
+ default:
+ return "Unknown";
+ }
+}
+
+__inline__
+static
+CONST CHAR8*
+CardStateToString (
+ IN CARD_STATE State
+ )
+{
+ switch (State) {
+ case CardStateIdle:
+ return "Idle";
+ case CardStateReady:
+ return "Ready";
+ case CardStateIdent:
+ return "Ident";
+ case CardStateStdby:
+ return "Stdby";
+ case CardStateTran:
+ return "Tran";
+ case CardStateData:
+ return "Data";
+ case CardStateRcv:
+ return "Rcv";
+ case CardStatePrg:
+ return "Prg";
+ case CardStateDis:
+ return "Dis";
+ case CardStateBtst:
+ return "Btst";
+ case CardStateSlp:
+ return "Slp";
+ default:
+ return "Reserved";
+ }
+}
+
+__inline__
+static
+BOOLEAN
+IsCardStatusError (
+ IN SDHC_INSTANCE *HostInst,
+ IN CARD_STATUS CardStatus
+ )
+{
+ ASSERT (HostInst != NULL);
+
+ switch (HostInst->CardInfo.CardFunction) {
+ case CardFunctionSd:
+ return CardStatus.AsUint32 & SD_CARD_STATUS_ERROR_MASK;
+ case CardFunctionMmc:
+ return CardStatus.AsUint32 & MMC_CARD_STATUS_ERROR_MASK;
+ default:
+ ASSERT (FALSE);
+ return FALSE;
+ }
+}
+
+__inline__
+static
+BOOLEAN
+CmdsAreEqual (
+ IN CONST SD_COMMAND *Left,
+ IN CONST SD_COMMAND *Right
+ )
+{
+ ASSERT (Left != NULL);
+ ASSERT (Right != NULL);
+
+ if (Left != Right) {
+ return (Left->Class == Right->Class) &&
+ (Left->Index == Right->Index) &&
+ (Left->ResponseType == Right->ResponseType) &&
+ (Left->TransferDirection == Right->TransferDirection) &&
+ (Left->TransferType == Right->TransferType) &&
+ (Left->Type == Right->Type);
+ }
+
+ return TRUE;
+}
+
+// Timing Helpers
+
+/** Gets the current high-performance counter tick count.
+
+ The returned tick count is considered as a time stamp and can used later in
+ elapsed time calculations.
+
+ @retval Current high-performance counter tick count.
+**/
+__inline__
+static
+UINT64
+HpcTimerStart (
+ VOID
+ )
+{
+ return GetPerformanceCounter ();
+}
+
+/** Calculates the elapsed milliseconds since a specific timer time stamp.
+
+ @param[in] TimerStartTimestamp The high-performance counter tick count to use
+ as the starting point in elapsed time calculation.
+
+ @retval The milliseconds elapsed.
+**/
+__inline__
+static
+UINT64
+HpcTimerElapsedMilliseconds (
+ IN UINT64 TimerStartTimestamp
+ )
+{
+ return (((GetPerformanceCounter () - TimerStartTimestamp) * 1000UL) /
+ gHpcTicksPerSeconds);
+}
+
+#endif // __SDMMC_H__
diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/SdMmcDxe.inf b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmcDxe.inf
new file mode 100644
index 000000000000..c8c45d07f1ed
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmcDxe.inf
@@ -0,0 +1,50 @@
+#
+# Copyright (c) Microsoft Corporation. All rights reserved.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SdMmcDxe
+ FILE_GUID = 16738C4A-8044-4DD8-B68E-58A53CEFF5D9
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = SdMmcDxeInitialize
+
+[Sources.common]
+ SdMmc.c
+ BlockIo.c
+ Debug.c
+ Protocol.c
+ RpmbIo.c
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ Platform/Microsoft/MsPkg.dec
+ Platform/Microsoft/OpteeClientPkg/OpteeClientPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ TimerLib
+
+[Protocols]
+ gEfiDiskIoProtocolGuid
+ gEfiBlockIoProtocolGuid
+ gEfiDevicePathProtocolGuid
+ gEfiSdhcProtocolGuid
+ gEfiRpmbIoProtocolGuid
+
+[Depex]
+ TRUE
diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/SdMmcHw.h b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmcHw.h
new file mode 100644
index 000000000000..b5683a6e260d
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmcHw.h
@@ -0,0 +1,506 @@
+/** @file
+*
+* Copyright (c) Microsoft Corporation. All rights reserved.
+* Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef __SDMMCHW_H__
+#define __SDMMCHW_H__
+
+#pragma pack(1)
+
+#define SD_BLOCK_LENGTH_BYTES 512
+#define SD_BLOCK_WORD_COUNT (SD_BLOCK_LENGTH_BYTES / sizeof (UINT32))
+#define SD_IDENT_MODE_CLOCK_FREQ_HZ 400000 // 400 KHz
+#define MMC_HIGH_SPEED_MODE_CLOCK_FREQ_HZ 52000000 // 52 MHz
+
+typedef enum {
+ CardSpeedModeUndefined = 0,
+ CardSpeedModeNormalSpeed,
+ CardSpeedModeHighSpeed
+} CARD_SPEED_MODE;
+
+typedef enum {
+ CardFunctionUnknown = 0,
+ CardFunctionSd,
+ CardFunctionSdio,
+ CardFunctionComboSdSdio,
+ CardFunctionMmc
+} CARD_FUNCTION;
+
+typedef enum {
+ CardStateIdle = 0,
+ CardStateReady,
+ CardStateIdent,
+ CardStateStdby,
+ CardStateTran,
+ CardStateData,
+ CardStateRcv,
+ CardStatePrg,
+ CardStateDis,
+ CardStateBtst,
+ CardStateSlp
+} CARD_STATE;
+
+typedef union {
+ UINT32 AsUint32;
+ struct {
+ UINT32 RESERVED_1 : 2; // [1:0]
+ UINT32 RESERVED_2 : 1; // [2]
+ UINT32 AKE_SEQ_ERROR : 1; // [3] SD
+ UINT32 RESERVED_3 : 1; // [4]
+ UINT32 APP_CMD : 1; // [5]
+ UINT32 URGENT_BKOPS : 1; // [6] MMC
+ UINT32 SWITCH_ERROR : 1; // [7] MMC
+ UINT32 READY_FOR_DATA : 1; // [8]
+ UINT32 CURRENT_STATE : 4; // [12:9]
+ UINT32 ERASE_RESET : 1; // [13]
+ UINT32 RESERVED_4 : 1; // [14]
+ UINT32 WP_ERASE_SKIP : 1; // [15]
+ UINT32 CID_CSD_OVERWRITE : 1; // [16]
+ UINT32 OVERRUN : 1; // [17] MMC
+ UINT32 UNDERRUN : 1; // [18] MMC
+ UINT32 ERROR : 1; // [19]
+ UINT32 CC_ERROR : 1; // [20]
+ UINT32 CARD_ECC_FAILED : 1; // [21]
+ UINT32 ILLEGAL_COMMAND : 1; // [22]
+ UINT32 COM_CRC_ERROR : 1; // [23]
+ UINT32 LOCK_UNLOCK_FAILED : 1; // [24]
+ UINT32 CARD_IS_LOCKED : 1; // [25]
+ UINT32 WP_VIOLATION : 1; // [26]
+ UINT32 ERASE_PARAM : 1; // [27]
+ UINT32 ERASE_SEQ_ERROR : 1; // [28]
+ UINT32 BLOCK_LEN_ERROR : 1; // [29]
+ UINT32 ADDRESS_MISALIGN : 1; // [30]
+ UINT32 ADDRESS_OUT_OF_RANGE : 1; // [31]
+ } Fields;
+} CARD_STATUS;
+
+#define MMC_CARD_STATUS_ERROR_MASK \
+ (BIT7 | BIT13 | BIT15 | BIT16 | BIT17 | BIT18 | BIT19 | BIT20 | \
+ BIT21 | BIT22 | BIT23 | BIT24 | BIT26 | BIT27 | BIT28 | BIT29 | \
+ BIT30 | BIT31)
+
+#define SD_CARD_STATUS_ERROR_MASK \
+ (BIT3 | BIT13 | BIT15 | BIT16 | BIT19 | BIT20 | \
+ BIT21 | BIT22 | BIT23 | BIT24 | BIT26 | BIT27 | BIT28 | BIT29 | \
+ BIT30 | BIT31)
+
+typedef union {
+ UINT32 AsUint32;
+ struct {
+ UINT32 CheckPattern : 8;
+ UINT32 VoltageSupplied : 4;
+ UINT32 RESERVED_1 : 16;
+ UINT32 CommandIndex : 6;
+ } Fields;
+} SEND_IF_COND_ARG;
+
+typedef SEND_IF_COND_ARG SEND_IF_COND_CMD_RESPONSE;
+
+// definition for VoltageAccepted in SD_CMD8_STATUS
+
+#define SD_CMD8_VOLTAGE_27_36 0x01
+#define SD_CMD8_VOLTAGE_LOW 0x02
+
+typedef union {
+ UINT32 AsUint32;
+ struct {
+ UINT32 VoltageWindow : 24; // [23:0] Maps to OCR[0:23]
+ UINT32 S18R : 1; // [24] Switching to 1.8V Request
+ // 0b: Use Current signal voltage, 1b: Switch to 1.8V signal voltage
+
+ UINT32 RESERVED_1 : 3; // [27:25]
+ UINT32 XPC : 1; // SDXC Power Control [28] 0b: Power Saving, 1b: Max Performance
+ UINT32 RESERVED_2 : 1; // [29]
+ UINT32 HCS : 1; // Host Capacity Support [30] 0b: SDSC, 1b: SDHC or SDXC
+ UINT32 RESERVED_3 : 1; // [31]
+ } Fields;
+} SD_SEND_OP_COND_ARG;
+
+typedef union {
+ UINT32 AsUint32;
+ struct {
+ UINT32 VoltageWindow : 24; // [23:0] Voltage profile
+ UINT32 RESERVED_1 : 5; // Reserved
+ UINT32 AccessMode : 2; // 00b (byte mode), 10b (sector mode)
+ UINT32 PowerUp : 1; // This bit is set to LOW if the card has not finished the power up routine
+ } Fields;
+} SD_OCR;
+
+typedef union {
+ UINT32 AsUint32;
+ struct {
+ UINT32 VoltageWindow : 24; // [23:0] Voltage profile
+ UINT32 S18A : 1; // [24] Switching to 1.8V Accepted
+ UINT32 RESERVED_1 : 5; // Reserved [29:25]
+ UINT32 CCS : 1; // Card Capacity Status [30]
+ UINT32 PowerUp : 1; // This bit is set to LOW if the card has not finished the power up routine [31]
+ } Fields;
+} SD_OCR_EX;
+
+typedef struct {
+ UINT16 MDT : 12; // Manufacturing date [19:8]
+ UINT16 RESERVED_1 : 4; // Reserved [23:20]
+ UINT32 PSN; // Product serial number [55:24]
+ UINT8 PRV; // Product revision [63:56]
+ UINT8 PNM[5]; // Product name [64:103]
+ UINT16 OID; // OEM/Application ID [119:104]
+ UINT8 MID; // Manufacturer ID [127:120]
+} SD_CID;
+
+typedef struct {
+ UINT16 MDT : 8; // Manufacturing date [15:8]
+ UINT32 PSN; // Product serial number [47:16]
+ UINT8 PRV; // Product revision [55:48]
+ UINT8 PNM[6]; // Product name [103:56]
+ UINT8 OID; // OEM/Application ID [111:104]
+ UINT8 CBX : 2; // Card/BGA [113:112]
+ UINT8 RESERVED_1 : 6; // [119:114]
+ UINT8 MID; // Manufacturer ID [127:120]
+} MMC_CID;
+
+typedef struct {
+ UINT8 RESERVED_1 : 2; // Reserved [9:8]
+ UINT8 FILE_FORMAT : 2; // File format [11:10]
+ UINT8 TMP_WRITE_PROTECT : 1; // Temporary write protection [12:12]
+ UINT8 PERM_WRITE_PROTECT : 1; // Permanent write protection [13:13]
+ UINT8 COPY : 1; // Copy flag (OTP) [14:14]
+ UINT8 FILE_FORMAT_GRP : 1; // File format group [15:15]
+ UINT16 RESERVED_2 : 5; // Reserved [20:16]
+ UINT16 WRITE_BL_PARTIAL : 1; // Partial blocks for write allowed [21:21]
+ UINT16 WRITE_BL_LEN : 4; // Max. write data block length [25:22]
+ UINT16 R2W_FACTOR : 3; // Write speed factor [28:26]
+ UINT16 RESERVED_3 : 2; // Reserved [30:29]
+ UINT16 WP_GRP_ENABLE : 1; // Write protect group enable [31:31]
+ UINT32 WP_GRP_SIZE : 7; // Write protect group size [38:32]
+ UINT32 SECTOR_SIZE : 7; // Erase sector size [45:39]
+ UINT32 ERASE_BLK_EN : 1; // Erase single block enable [46:46]
+ UINT32 C_SIZE_MULT : 3; // Device size multiplier [49:47]
+ UINT32 VDD_W_CURR_MAX : 3; // Max. write current @ VDD max [52:50]
+ UINT32 VDD_W_CURR_MIN : 3; // Max. write current @ VDD min [55:53]
+ UINT32 VDD_R_CURR_MAX : 3; // Max. read current @ VDD max [58:56]
+ UINT32 VDD_R_CURR_MIN : 3; // Max. read current @ VDD min [61:59]
+ UINT32 C_SIZELow2 : 2; // Device size [63:62]
+ UINT32 C_SIZEHigh10 : 10; // Device size [73:64]
+ UINT32 RESERVED_4 : 2; // Reserved [75:74]
+ UINT32 DSR_IMP : 1; // DSR implemented [76:76]
+ UINT32 READ_BLK_MISALIGN : 1; // Read block misalignment [77:77]
+ UINT32 WRITE_BLK_MISALIGN : 1; // Write block misalignment [78:78]
+ UINT32 READ_BL_PARTIAL : 1; // Partial blocks for read allowed [79:79]
+ UINT32 READ_BL_LEN : 4; // Max. read data block length [83:80]
+ UINT32 CCC : 12; // Card command classes [95:84]
+ UINT8 TRAN_SPEED; // Max. bus clock frequency [103:96]
+ UINT8 NSAC; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104]
+ UINT8 TAAC; // Data read access-time 1 [119:112]
+ UINT8 RESERVED_5 : 6; // Reserved [125:120]
+ UINT8 CSD_STRUCTURE : 2; // CSD structure [127:126]
+} SD_CSD;
+
+typedef struct {
+ UINT8 RESERVED_1 : 2; // Reserved [9:8]
+ UINT8 FILE_FORMAT : 2; // File format [11:10]
+ UINT8 TMP_WRITE_PROTECT : 1; // Temporary write protection [12:12]
+ UINT8 PERM_WRITE_PROTECT : 1; // Permanent write protection [13:13]
+ UINT8 COPY : 1; // Copy flag (OTP) [14:14]
+ UINT8 FILE_FORMAT_GRP : 1; // File format group [15:15]
+ UINT16 RESERVED_2 : 5; // Reserved [20:16]
+ UINT16 WRITE_BL_PARTIAL : 1; // Partial blocks for write allowed [21:21]
+ UINT16 WRITE_BL_LEN : 4; // Max. write data block length [25:22]
+ UINT16 R2W_FACTOR : 3; // Write speed factor [28:26]
+ UINT16 RESERVED_3 : 2; // Reserved [30:29]
+ UINT16 WP_GRP_ENABLE : 1; // Write protect group enable [31:31]
+ UINT16 WP_GRP_SIZE : 7; // Write protect group size [38:32]
+ UINT16 SECTOR_SIZE : 7; // Erase sector size [45:39]
+ UINT16 ERASE_BLK_EN : 1; // Erase single block enable [46:46]
+ UINT16 RESERVED_4 : 1; // Reserved [47:47]
+ UINT32 C_SIZE : 22; // Device size [63:62]
+ UINT32 RESERVED_5 : 6; // Reserved [75:74]
+ UINT32 DSR_IMP : 1; // DSR implemented [76:76]
+ UINT32 READ_BLK_MISALIGN : 1; // Read block misalignment [77:77]
+ UINT32 WRITE_BLK_MISALIGN : 1; // Write block misalignment [78:78]
+ UINT32 READ_BL_PARTIAL : 1; // Partial blocks for read allowed [79:79]
+ UINT16 READ_BL_LEN : 4; // Max. read data block length [83:80]
+ UINT16 CCC : 12; // Card command classes [95:84]
+ UINT8 TRAN_SPEED; // Max. bus clock frequency [103:96]
+ UINT8 NSAC; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104]
+ UINT8 TAAC; // Data read access-time 1 [119:112]
+ UINT8 RESERVED_6 : 6; // Reserved [125:120]
+ UINT8 CSD_STRUCTURE : 2; // CSD structure [127:126]
+} SD_CSD_2;
+
+typedef struct {
+ UINT8 ECC : 2; // ECC code [9:8]
+ UINT8 FILE_FORMAT : 2; // File format [11:10]
+ UINT8 TMP_WRITE_PROTECT : 1; // Temporary write protection [12:12]
+ UINT8 PERM_WRITE_PROTECT : 1; // Permanent write protection [13:13]
+ UINT8 COPY : 1; // Copy flag (OTP) [14:14]
+ UINT8 FILE_FORMAT_GRP : 1; // File format group [15:15]
+ UINT16 CONTENT_PROT_APP : 1; // Content protection application [16:16]
+ UINT16 RESERVED_1 : 4; // Reserved [20:17]
+ UINT16 WRITE_BL_PARTIAL : 1; // Partial blocks for write allowed [21:21]
+ UINT16 WRITE_BL_LEN : 4; // Max. write data block length [25:22]
+ UINT16 R2W_FACTOR : 3; // Write speed factor [28:26]
+ UINT16 DEFAULT_ECC : 2; // Manufacturer default ECC [30:29]
+ UINT16 WP_GRP_ENABLE : 1; // Write protect group enable [31:31]
+ UINT32 WP_GRP_SIZE : 5; // Write protect group size [36:32]
+ UINT32 ERASE_GRP_MULT : 5; // Erase group size multiplier [41:37]
+ UINT32 ERASE_GRP_SIZE : 5; // Erase sector size [46:42]
+ UINT32 C_SIZE_MULT : 3; // Device size multiplier [49:47]
+ UINT32 VDD_W_CURR_MAX : 3; // Max. write current @ VDD max [52:50]
+ UINT32 VDD_W_CURR_MIN : 3; // Max. write current @ VDD min [55:53]
+ UINT32 VDD_R_CURR_MAX : 3; // Max. read current @ VDD max [58:56]
+ UINT32 VDD_R_CURR_MIN : 3; // Max. read current @ VDD min [61:59]
+ UINT32 C_SIZELow2 : 2; // Device size [63:62]
+ UINT32 C_SIZEHigh10 : 10; // Device size [73:64]
+ UINT32 RESERVED_4 : 2; // Reserved [75:74]
+ UINT32 DSR_IMP : 1; // DSR implemented [76:76]
+ UINT32 READ_BLK_MISALIGN : 1; // Read block misalignment [77:77]
+ UINT32 WRITE_BLK_MISALIGN : 1; // Write block misalignment [78:78]
+ UINT32 READ_BL_PARTIAL : 1; // Partial blocks for read allowed [79:79]
+ UINT32 READ_BL_LEN : 4; // Max. read data block length [83:80]
+ UINT32 CCC : 12; // Card command classes [95:84]
+ UINT8 TRAN_SPEED; // Max. bus clock frequency [103:96]
+ UINT8 NSAC; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104]
+ UINT8 TAAC; // Data read access-time 1 [119:112]
+ UINT8 RESERVED_5 : 2; // Reserved [121:120]
+ UINT8 SPEC_VERS : 4; // System specification version [125:122]
+ UINT8 CSD_STRUCTURE : 2; // CSD structure [127:126]
+} MMC_CSD;
+
+// We support spec version 4.X and higher
+// If CSD.SPEC_VERS indicates a version 4.0 or higher, the card is a high speed card and supports
+// SWITCH and SEND_EXT_CSD commands. Otherwise the card is an old MMC card.
+#define MMC_MIN_SUPPORTED_SPEC_VERS 4
+
+typedef struct {
+
+ // Host modifiable modes
+
+ UINT8 Reserved26[134];
+ UINT8 BadBlockManagement;
+ UINT8 Reserved25;
+ UINT32 EnhancedUserDataStartAddress;
+ UINT8 EnhancedUserDataAreaSize[3];
+ UINT8 GpPartSizeMult[12];
+ UINT8 PartitioningSetting;
+ UINT8 PartitionsAttribute;
+ UINT8 MaxEnhancedAreaSize[3];
+ UINT8 PartitioningSupport;
+ UINT8 Reserved24;
+ UINT8 HwResetFunc;
+ UINT8 Reserved23[5];
+ UINT8 RpmbSizeMult;
+ UINT8 FwConfig;
+ UINT8 Reserved22;
+ UINT8 UserWriteProt;
+ UINT8 Reserved21;
+ UINT8 BootWriteProt;
+ UINT8 Reserved20;
+ UINT8 EraseGroupDef;
+ UINT8 Reserved19;
+ UINT8 BootBusWidth;
+ UINT8 BootConfigProt;
+ UINT8 PartitionConfig;
+ UINT8 Reserved18;
+ UINT8 ErasedMemContent;
+ UINT8 Reserved17;
+ UINT8 BusWidth;
+ UINT8 Reserved16;
+ UINT8 HighSpeedTiming;
+ UINT8 Reserved15;
+ UINT8 PowerClass;
+ UINT8 Reserved14;
+ UINT8 CmdSetRevision;
+ UINT8 Reserved13;
+ UINT8 CmdSet;
+
+ // Non-modifiable properties
+
+ UINT8 ExtendedCsdRevision;
+ UINT8 Reserved12;
+ UINT8 CsdStructureVersion;
+ UINT8 Reserved11;
+ UINT8 CardType;
+ UINT8 Reserved10[3];
+ UINT8 PowerClass52Mhz195V;
+ UINT8 PowerClass26Mhz195V;
+ UINT8 PowerClass52Mhz36V;
+ UINT8 PowerClass26Mhz36V;
+ UINT8 Reserved9;
+ UINT8 MinReadPerf4bit26Mhz;
+ UINT8 MinWritePerf4bit26Mhz;
+ UINT8 MinReadPerf8bit26Mhz;
+ UINT8 MinWritePerf8bit26Mhz;
+ UINT8 MinReadPerf8bit52Mhz;
+ UINT8 MinWritePerf8bit52Mhz;
+ UINT8 Reserved8;
+ UINT32 SectorCount;
+ UINT8 Reserved7;
+ UINT8 SleepAwakeTimeout;
+ UINT8 Reserved6;
+ UINT8 SleepCurrentVccq;
+ UINT8 SleepCurrentVcc;
+ UINT8 HighCapacityWriteProtectSize;
+ UINT8 ReliableWriteSectorCount;
+ UINT8 HighCapacityEraseTimeout;
+ UINT8 HighCapacityEraseSize;
+ UINT8 AccessSize;
+ UINT8 BootPartitionSize;
+ UINT8 Reserved5;
+ UINT8 BootInfo;
+ UINT8 SecureTrimMultiplier;
+ UINT8 SecureEraseMultiplier;
+ UINT8 SecureFeatureSupport;
+ UINT8 TrimMultiplier;
+ UINT8 Reserved4;
+ UINT8 MinReadPerf8bit52MhzDdr;
+ UINT8 MinWritePerf8bit52MhzDdr;
+ UINT16 Reserved3;
+ UINT8 PowerClass52MhzDdr36V;
+ UINT8 PowerClass52MhzDdr195V;
+ UINT8 Reserved2;
+ UINT8 InitTimeoutAfterPartitioning;
+ UINT8 Reserved1[262];
+ UINT8 SupportedCmdSets;
+ UINT8 Reserved[7];
+} MMC_EXT_CSD;
+
+typedef enum {
+ MmcExtCsdCardTypeNormalSpeed = 0x01,
+ MmcExtCsdCardTypeHighSpeed = 0x02,
+ MmcExtCsdCardTypeDdr1v8 = 0x04,
+ MmcExtCsdCardTypeDdr1v2 = 0x08
+} MmcExtCsdCardType;
+
+typedef enum {
+ MmcExtCsdBusWidth1Bit = 0,
+ MmcExtCsdBusWidth4Bit = 1,
+ MmcExtCsdBusWidth8Bit = 2
+} MmcExtCsdBusWidth;
+
+typedef enum {
+ MmcExtCsdPartitionAccessUserArea,
+ MmcExtCsdPartitionAccessBootPartition1,
+ MmcExtCsdPartitionAccessBootPartition2,
+ MmcExtCsdPartitionAccessRpmb,
+ MmcExtCsdPartitionAccessGpp1,
+ MmcExtCsdPartitionAccessGpp2,
+ MmcExtCsdPartitionAccessGpp3,
+ MmcExtCsdPartitionAccessGpp4,
+} MMC_EXT_CSD_PARTITION_ACCESS;
+
+typedef enum {
+ MmcExtCsdBootPartitionEnableNotBootEnabled,
+ MmcExtCsdBootPartitionBootPartition1BootEnabled,
+ MmcExtCsdBootPartitionBootPartition2BootEnabled,
+ MmcExtCsdBootPartitionUserAreaBootEnabled = 7,
+} MMC_EXT_CSD_BOOT_PARTITION_ENABLE;
+
+typedef union {
+ UINT8 AsUint8;
+ struct {
+ UINT8 PARTITION_ACCESS : 3; // [2:0]
+ UINT8 BOOT_PARTITION_ENABLE : 3; // [5:3]
+ UINT8 BOOT_ACK : 1; // [6]
+ UINT8 RESERVED_1 : 1; // [7]
+ } Fields;
+} MMC_EXT_CSD_PARTITION_CONFIG;
+
+typedef enum {
+ MmcExtCsdBitIndexPartitionConfig = 179,
+ MmcExtCsdBitIndexBusWidth = 183,
+ MmcExtCsdBitIndexHsTiming = 185
+} MMC_EXT_CSD_BIT_INDEX;
+
+typedef enum {
+ MmcSwitchCmdAccessTypeCommandSet,
+ MmcSwitchCmdAccessTypeSetBits,
+ MmcSwitchCmdAccessTypeClearBits,
+ MmcSwitchCmdAccessTypeWriteByte
+} MMC_SWITCH_CMD_ACCESS_TYPE;
+
+typedef union {
+ UINT32 AsUint32;
+ struct {
+ UINT32 CmdSet : 3; // [2:0]
+ UINT32 RESERVED_1 : 5; // Set to 0 [7:3]
+ UINT32 Value : 8; // [15:8]
+ UINT32 Index : 8; // [23:16]
+ UINT32 Access : 2; // A value from MMC_SWITCH_CMD_ACCESS_TYPE [25:24]
+ UINT32 RESERVED_2 : 6; // Set to 0 [31:26]
+ } Fields;
+} MMC_SWITCH_CMD_ARG;
+
+// Bits [3:0] code the current consumption for the 4 bit bus configuration
+#define MMC_EXT_CSD_POWER_CLASS_4BIT(X) ((X) & 0xF)
+
+// Bits [7:4] code the current consumption for the 8 bit bus configuration
+#define MMC_EXT_CSD_POWER_CLASS_8BIT(X) ((X) >> 4)
+
+typedef struct {
+ UINT32 RESERVED_1;
+ UINT32 CMD_SUPPORT : 2;
+ UINT32 RESERVED_2 : 9;
+ UINT32 EX_SECURITY : 4;
+ UINT32 SD_SPEC3 : 1;
+ UINT32 SD_BUS_WIDTH : 4;
+ UINT32 SD_SECURITY : 3;
+ UINT32 DATA_STAT_AFTER_ERASE : 1;
+ UINT32 SD_SPEC : 4;
+ UINT32 SCR_STRUCTURE : 4;
+} SD_SCR;
+
+typedef SD_OCR MMC_OCR;
+typedef SD_OCR MMC_SEND_OP_COND_ARG;
+
+typedef enum {
+ SdOcrAccessByteMode = 0,
+ SdOcrAccessSectorMode = 2
+} SD_OCR_ACCESS;
+
+// Voltage window that covers from 2.8V and up to 3.6V
+#define SD_OCR_HIGH_VOLTAGE_WINDOW 0x00FF8000
+
+typedef struct {
+ SD_OCR Ocr;
+ SD_CID Cid;
+ SD_CSD Csd;
+ SD_SCR Scr;
+} SD_REGISTERS;
+
+typedef struct {
+ MMC_OCR Ocr;
+ MMC_CID Cid;
+ MMC_CSD Csd;
+ MMC_EXT_CSD ExtCsd;
+} MMC_REGISTERS;
+
+typedef struct {
+ UINT32 RCA;
+ CARD_FUNCTION CardFunction;
+ BOOLEAN HasExtendedOcr;
+ BOOLEAN HighCapacity;
+ UINT64 ByteCapacity;
+ CARD_SPEED_MODE CurrentSpeedMode;
+
+ union {
+ SD_REGISTERS Sd;
+ MMC_REGISTERS Mmc;
+ } Registers;
+
+} CARD_INFO;
+
+#pragma pack()
+
+#endif // __SDMMCHW_H__
+
diff --git a/Platform/Microsoft/Include/Protocol/RpmbIo.h b/Platform/Microsoft/Include/Protocol/RpmbIo.h
new file mode 100644
index 000000000000..ed37f7c4fc06
--- /dev/null
+++ b/Platform/Microsoft/Include/Protocol/RpmbIo.h
@@ -0,0 +1,262 @@
+/** @file
+*
+* Copyright (c) Microsoft Corporation. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+/**
+*
+* RPMB IO protocol is an interface implementation for the Replay Protected Memory
+* Block (RPMB) as defined by JEDEC Standard for MultiMediaCard specs 4.41.
+*
+* This protocol abstracts the RPMB operations to allow EFI boot services environment
+* to perform eMMC RPMB operations without specific knowledge about the card type or
+* the host controller.
+*
+**/
+
+#ifndef __RPMB_IO_H__
+#define __RPMB_IO_H__
+
+// Global ID for the RPMB IO Protocol {FBAEE5B2-08B0-41B8-B0B0-86B72EED1BB6}
+#define EFI_RPMB_IO_PROTOCOL_GUID \
+ { 0xfbaee5b2, 0x8b0, 0x41b8, { 0xb0, 0xb0, 0x86, 0xb7, 0x2e, 0xed, 0x1b, 0xb6 } };
+
+#define EFI_RPMB_IO_PROTOCOL_REVISION 0x00010000
+
+// RPMB Request Message Types
+
+#define EFI_RPMB_REQUEST_PROGRAM_KEY 0x0001 // Authentication key programming request
+#define EFI_RPMB_REQUEST_COUNTER_VALUE 0x0002 // Reading of the Write Counter value -request
+#define EFI_RPMB_REQUEST_AUTH_WRITE 0x0003 // Authenticated data write request
+#define EFI_RPMB_REQUEST_AUTH_READ 0x0004 // Authenticated data read request
+#define EFI_RPMB_REQUEST_RESULT_REQUEST 0x0005 // Result read request
+
+// RPMB Response Message Types
+
+#define EFI_RPMB_RESPONSE_PROGRAM_KEY 0x0100 // Authentication key programming response
+#define EFI_RPMB_RESPONSE_COUNTER_VALUE 0x0200 // Reading of the Write Counter value -response
+#define EFI_RPMB_RESPONSE_AUTH_WRITE 0x0300 // Authenticated data write response
+#define EFI_RPMB_RESPONSE_AUTH_READ 0x0400 // Authenticated data read response
+
+// RPMB Operation Results
+
+#define EFI_RPMB_OK 0 // Operation OK
+#define EFI_RPMB_ERROR_GENERAL 1 // General failure
+#define EFI_RPMB_ERROR_AUTH 2 // Authentication failure (MAC comparison not matching, MAC calculation failure)
+#define EFI_RPMB_ERROR_COUNTER 3 // Counter failure (counters not matching in comparison, counter incrementing failure)
+#define EFI_RPMB_ERROR_ADDRESS 4 // Address failure (address out of range, wrong address alignment)
+#define EFI_RPMB_ERROR_WRITE 5 // Write failure (data/counter/result write failure)
+#define EFI_RPMB_ERROR_READ 6 // Read failure (data/counter/result read failure)
+#define EFI_RPMB_ERROR_KEY 7 // Authentication Key not yet programmed
+
+#define EFI_RPMB_ERROR_MASK 0x7
+#define EFI_RPMB_ERROR_CNT_EXPIRED_BIT 0x80
+
+// RPMB Data Frame fields size in bytes.
+
+#define EFI_RPMB_PACKET_STUFF_SIZE 196
+#define EFI_RPMB_PACKET_KEY_MAC_SIZE 32
+#define EFI_RPMB_PACKET_DATA_SIZE 256
+#define EFI_RPMB_PACKET_NONCE_SIZE 16
+#define EFI_RPMB_PACKET_WCOUNTER_SIZE 4
+#define EFI_RPMB_PACKET_ADDRESS_SIZE 2
+#define EFI_RPMB_PACKET_BLOCKCOUNT_SIZE 2
+#define EFI_RPMB_PACKET_RESULT_SIZE 2
+#define EFI_RPMB_PACKET_TYPE_SIZE 2
+
+// Everything in the RPMB Data Frame is hashed except the Stuff and the MAC itself.
+#define EFI_RPMB_PACKET_DATA_HASH_SIZE ( \
+ sizeof(EFI_RPMB_DATA_PACKET) - \
+ offsetof(EFI_RPMB_DATA_PACKET, PacketData) \
+ )
+
+// CID register is 16 byte
+#define EFI_RPMB_CID_SIZE 16
+
+/** The data frame to access the replay protected memory area.
+
+ NOTE: Byte order of the RPMB data frame is MSB first, e.g. Write Counter MSB
+ [11] is storing the upmost byte of the counter value.
+**/
+#pragma pack(1)
+typedef struct {
+ UINT8 Stuff[EFI_RPMB_PACKET_STUFF_SIZE];
+
+ UINT8 KeyOrMAC[EFI_RPMB_PACKET_KEY_MAC_SIZE]; // The authentication key or the message authentication code (MAC) depending
+ // on the request/response type. The MAC will be delivered in the last (or the
+ // only) block of data.
+
+ UINT8 PacketData[EFI_RPMB_PACKET_DATA_SIZE]; // Data to be written or read by signed access.
+ UINT8 Nonce[EFI_RPMB_PACKET_NONCE_SIZE]; // Random number generated by the host for the Requests and copied to the
+ // Response by the eMMC Replay Protected Memory Block engine.
+
+ UINT8 WriteCounter[EFI_RPMB_PACKET_WCOUNTER_SIZE]; // Counter value for the total amount of the successful authenticated data write
+ // requests made by the host.
+
+ UINT8 Address[EFI_RPMB_PACKET_ADDRESS_SIZE]; // Address of the data to be programmed to or read from the Replay Protected
+ // Memory Block. Address is the serial number of the accessed half sector
+ // (256B). Address argument in CMD 18 and CMD 25 will be ignored.
+
+ UINT8 BlockCount[EFI_RPMB_PACKET_BLOCKCOUNT_SIZE]; // Number of blocks (half sectors, 256B) requested to be read/programmed. This
+ // value is equal to the count value in CMD23 argument.
+
+ UINT8 OperationResult[EFI_RPMB_PACKET_RESULT_SIZE]; // Includes information about the status of the write counter (valid, expired)
+ // and successfulness of the access made to the Replay Protected Memory Block.
+
+ UINT8 RequestOrResponseType[EFI_RPMB_PACKET_TYPE_SIZE]; // Defines the type of request and response to/from the memory.
+} EFI_RPMB_DATA_PACKET;
+#pragma pack()
+
+typedef struct {
+ EFI_RPMB_DATA_PACKET *Packets;
+ UINTN PacketCount; // The number of RPMB Frames/Packets which is
+ //also the number of half sectors (256Byte) to
+ // be read/programmed since each RPBM frame
+ //holds 256Bytes of data.
+} EFI_RPMB_DATA_BUFFER;
+
+typedef struct _EFI_RPMB_IO_PROTOCOL EFI_RPMB_IO_PROTOCOL;
+
+/** Authentication key programming request.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ProgrammingRequest A data packet describing a key programming request.
+ @param[out] ResultResponse A caller allocated data packet which will receive the
+ key programming result.
+
+ @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+ according to specs, other values are returned in case of any protocol error.
+ Failure during key programming any other eMMC internal failure is reported
+ in the Result field of the returned response data packet.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_RPMB_PROGRAM_KEY) (
+ IN EFI_RPMB_IO_PROTOCOL *This,
+ IN EFI_RPMB_DATA_PACKET *ProgrammingRequest,
+ OUT EFI_RPMB_DATA_PACKET *ResultResponse
+ );
+
+/** Reading of the write counter value request.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ReadRequest A data packet describing a read counter value request.
+ @param[out] ReadResponse A caller allocated data packet which will receive
+ the counter value read response. If counter has expired bit 7 is set to 1 in
+ returned Result.
+
+ @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+ according to specs, other values are returned in case of any protocol error.
+ Failure during counter read or any other eMMC internal failure is reported
+ in the Result field of the returned response data packet.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_RPMB_READ_COUNTER) (
+ IN EFI_RPMB_IO_PROTOCOL *This,
+ IN EFI_RPMB_DATA_PACKET *ReadRequest,
+ OUT EFI_RPMB_DATA_PACKET *ReadResponse
+ );
+
+/** Authenticated data write request.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] WriteRequest A sequence of data packets describing data write
+ requests and holds the data to be written.
+ @param[out] ResultResponse A caller allocated data packet which will receive
+ the data write programming result.
+
+ @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+ according to specs, other values are returned in case of any protocol error.
+ Failure during data programming or any other eMMC internal failure is reported
+ in the Result field of the returned data packet.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_RPMB_AUTHENTICATED_WRITE) (
+ IN EFI_RPMB_IO_PROTOCOL *This,
+ IN EFI_RPMB_DATA_BUFFER *WriteRequest,
+ OUT EFI_RPMB_DATA_PACKET *ResultResponse
+ );
+
+/** Authenticated data read request.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ReadRequest A data packet that describes a data read request.
+ @param[out] ReadResponse A caller allocated data packets which will receive
+ the data read.
+
+ @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+ according to specs, other values are returned in case of any protocol error.
+ Failure during data fetch from the eMMC or any other eMMC internal failure
+ is reported in the Result field of the returned data packet.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_RPMB_AUTHENTICATED_READ) (
+ IN EFI_RPMB_IO_PROTOCOL *This,
+ IN EFI_RPMB_DATA_PACKET *ReadRequest,
+ OUT EFI_RPMB_DATA_BUFFER *ReadResponse
+ );
+
+struct _EFI_RPMB_IO_PROTOCOL {
+ UINT64 Revision;
+ UINT8 Cid[EFI_RPMB_CID_SIZE]; // MMC Card IDentification (CID) register.
+
+ UINT8 ReliableSectorCount; // Reliable write sector count as defined by the REL_WR_SEC_C field of the
+ // MMC EXT_CSD register.
+
+ UINT8 RpmbSizeMult; // RPMB sector size multiplier as defined by the RPMB_SIZE_MULT field of the
+ // MMC EXT_CSD register.
+ // The RPMB partition size is calculated from the register by using the
+ // following equation: RPMB partition size = 128kB x RPMB_SIZE_MULT
+
+ // Protocol Callbacks
+
+ EFI_RPMB_PROGRAM_KEY ProgramKey;
+ EFI_RPMB_READ_COUNTER ReadCounter;
+ EFI_RPMB_AUTHENTICATED_WRITE AuthenticatedWrite;
+ EFI_RPMB_AUTHENTICATED_READ AuthenticatedRead;
+};
+
+__inline__
+static
+CONST CHAR16*
+RpmbOperationResultToString (
+ UINT16 OperationResult
+ )
+{
+ switch (OperationResult) {
+ case EFI_RPMB_OK:
+ return L"Operation OK";
+ case EFI_RPMB_ERROR_GENERAL:
+ return L"General failure";
+ case EFI_RPMB_ERROR_AUTH:
+ return L"Authentication failure";
+ case EFI_RPMB_ERROR_COUNTER:
+ return L"Counter failure";
+ case EFI_RPMB_ERROR_ADDRESS:
+ return L"Address failure";
+ case EFI_RPMB_ERROR_WRITE:
+ return L"Write failure";
+ case EFI_RPMB_ERROR_READ:
+ return L"Read failure";
+ case EFI_RPMB_ERROR_KEY:
+ return L"Authentication key not yet programmed";
+ default:
+ return L"Undefined operation result";
+ }
+}
+
+extern EFI_GUID gEfiRpmbIoProtocolGuid;
+
+#endif // __RPMB_IO_H__
diff --git a/Platform/Microsoft/Include/Protocol/Sdhc.h b/Platform/Microsoft/Include/Protocol/Sdhc.h
new file mode 100644
index 000000000000..381cd823de0c
--- /dev/null
+++ b/Platform/Microsoft/Include/Protocol/Sdhc.h
@@ -0,0 +1,197 @@
+/** @file
+*
+* Copyright (c) Microsoft Corporation. All rights reserved.
+* Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef __SDHC_H__
+#define __SDHC_H__
+
+//
+// Global ID for the SDHC Protocol {46055B0F-992A-4AD7-8F81-148186FFDF72}
+//
+#define EFI_SDHC_PROTOCOL_GUID \
+ { 0x46055b0f, 0x992a, 0x4ad7, { 0x8f, 0x81, 0x14, 0x81, 0x86, 0xff, 0xdf, 0x72 } };
+
+typedef UINT16 SD_COMMAND_INDEX;
+
+typedef enum {
+ SdCommandTypeUndefined = 0,
+ SdCommandTypeSuspend,
+ SdCommandTypeResume,
+ SdCommandTypeAbort
+} SD_COMMAND_TYPE;
+
+typedef enum {
+ SdCommandClassUndefined = 0,
+ SdCommandClassStandard,
+ SdCommandClassApp
+} SD_COMMAND_CLASS;
+
+typedef enum {
+ SdResponseTypeUndefined = 0,
+ SdResponseTypeNone,
+ SdResponseTypeR1,
+ SdResponseTypeR1B,
+ SdResponseTypeR2,
+ SdResponseTypeR3,
+ SdResponseTypeR4,
+ SdResponseTypeR5,
+ SdResponseTypeR5B,
+ SdResponseTypeR6
+} SD_RESPONSE_TYPE;
+
+typedef enum {
+ SdTransferTypeUndefined = 0,
+ SdTransferTypeNone,
+ SdTransferTypeSingleBlock,
+ SdTransferTypeMultiBlock,
+ SdTransferTypeMultiBlockNoStop
+} SD_TRANSFER_TYPE;
+
+typedef enum {
+ SdTransferDirectionUndefined = 0,
+ SdTransferDirectionRead,
+ SdTransferDirectionWrite
+} SD_TRANSFER_DIRECTION;
+
+typedef struct {
+ SD_COMMAND_INDEX Index;
+ SD_COMMAND_TYPE Type;
+ SD_COMMAND_CLASS Class;
+ SD_RESPONSE_TYPE ResponseType;
+ SD_TRANSFER_TYPE TransferType;
+ SD_TRANSFER_DIRECTION TransferDirection;
+} SD_COMMAND;
+
+typedef struct {
+ UINT32 BlockSize;
+ UINT32 BlockCount;
+ VOID* Buffer;
+} SD_COMMAND_XFR_INFO;
+
+typedef enum {
+ SdBusWidthUndefined = 0,
+ SdBusWidth1Bit = 1,
+ SdBusWidth4Bit = 4,
+ SdBusWidth8Bit = 8
+} SD_BUS_WIDTH;
+
+typedef enum {
+ SdhcResetTypeUndefined = 0,
+ SdhcResetTypeAll,
+ SdhcResetTypeCmd,
+ SdhcResetTypeData
+} SDHC_RESET_TYPE;
+
+typedef struct {
+ UINT32 MaximumBlockSize;
+ UINT32 MaximumBlockCount;
+} SDHC_CAPABILITIES;
+//
+// Forward declaration for EFI_SDHC_PROTOCOL
+//
+typedef struct _EFI_SDHC_PROTOCOL EFI_SDHC_PROTOCOL;
+
+typedef VOID (EFIAPI *SDHC_GET_CAPABILITIES) (
+ IN EFI_SDHC_PROTOCOL *This,
+ OUT SDHC_CAPABILITIES *Capabilities
+ );
+
+typedef EFI_STATUS (EFIAPI *SDHC_SOFTWARERESET) (
+ IN EFI_SDHC_PROTOCOL *This,
+ IN SDHC_RESET_TYPE ResetType
+ );
+
+typedef EFI_STATUS (EFIAPI *SDHC_SETCLOCK) (
+ IN EFI_SDHC_PROTOCOL *This,
+ IN UINT32 TargetFreqHz
+ );
+
+typedef EFI_STATUS (EFIAPI *SDHC_SETBUSWIDTH) (
+ IN EFI_SDHC_PROTOCOL *This,
+ IN SD_BUS_WIDTH BusWidth
+ );
+
+typedef BOOLEAN (EFIAPI *SDHC_ISCARDPRESENT) (
+ IN EFI_SDHC_PROTOCOL *This
+ );
+
+typedef BOOLEAN (EFIAPI *SDHC_ISREADONLY) (
+ IN EFI_SDHC_PROTOCOL *This
+ );
+
+typedef EFI_STATUS (EFIAPI *SDHC_SENDCOMMAND) (
+ IN EFI_SDHC_PROTOCOL *This,
+ IN const SD_COMMAND *Cmd,
+ IN UINT32 Argument,
+ IN OPTIONAL const SD_COMMAND_XFR_INFO *XfrInfo
+ );
+
+typedef EFI_STATUS (EFIAPI *SDHC_RECEIVERESPONSE) (
+ IN EFI_SDHC_PROTOCOL *This,
+ IN const SD_COMMAND *Cmd,
+ OUT UINT32 *Buffer
+ );
+
+typedef EFI_STATUS (EFIAPI *SDHC_READBLOCKDATA) (
+ IN EFI_SDHC_PROTOCOL *This,
+ IN UINTN LengthInBytes,
+ OUT UINT32 *Buffer
+ );
+
+typedef EFI_STATUS (EFIAPI *SDHC_WRITEBLOCKDATA) (
+ IN EFI_SDHC_PROTOCOL *This,
+ IN UINTN LengthInBytes,
+ IN const UINT32 *Buffer
+ );
+
+typedef VOID (EFIAPI *SDHC_CLEANUP) (
+ IN EFI_SDHC_PROTOCOL *This
+ );
+
+struct _EFI_SDHC_PROTOCOL {
+ UINT32 Revision;
+
+ //
+ // A unique ID that identify the SDHC device among other
+ // SDHC devices on the system
+ //
+ UINT32 SdhcId;
+
+ //
+ // Context area allocated by the SDHC driver
+ //
+ VOID *PrivateContext;
+
+ //
+ // SDHHC Callbacks
+ //
+ SDHC_GET_CAPABILITIES GetCapabilities;
+ SDHC_SOFTWARERESET SoftwareReset;
+ SDHC_SETCLOCK SetClock;
+ SDHC_SETBUSWIDTH SetBusWidth;
+ SDHC_ISCARDPRESENT IsCardPresent;
+ SDHC_ISREADONLY IsReadOnly;
+ SDHC_SENDCOMMAND SendCommand;
+ SDHC_RECEIVERESPONSE ReceiveResponse;
+ SDHC_READBLOCKDATA ReadBlockData;
+ SDHC_WRITEBLOCKDATA WriteBlockData;
+ SDHC_CLEANUP Cleanup;
+};
+
+#define SDHC_PROTOCOL_INTERFACE_REVISION 0x00010000 // 1.0
+
+extern EFI_GUID gEfiSdhcProtocolGuid;
+
+#endif // __SDHC_H__
+
--
2.16.2.gvfs.1.33.gf5370f1
next prev parent reply other threads:[~2018-07-17 2:05 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-07-17 2:05 [PATCH edk2-platforms 0/3] Add Platform-Generic Packages to support Windows IoT Core Chris Co
2018-07-17 2:05 ` Chris Co [this message]
2018-07-31 20:33 ` [PATCH edk2-platforms 1/3] Platform/Microsoft: Add SdMmc Dxe Driver Leif Lindholm
2018-08-02 0:05 ` Chris Co
2018-08-02 11:38 ` Leif Lindholm
2018-07-17 2:05 ` [PATCH edk2-platforms 2/3] Platform/Microsoft: Add MsPkg Chris Co
2018-07-31 20:38 ` Leif Lindholm
2018-07-17 2:05 ` [PATCH edk2-platforms 3/3] Platform/Microsoft: Add Lauterbach debug library Chris Co
2018-07-31 20:56 ` Leif Lindholm
2018-07-31 20:59 ` Ard Biesheuvel
2018-08-01 9:39 ` Leif Lindholm
2018-08-02 1:27 ` Chris Co
2018-08-02 11:22 ` Leif Lindholm
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=20180717020529.19496-2-christopher.co@microsoft.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