summaryrefslogtreecommitdiff
path: root/ChvRefCodePkg
diff options
context:
space:
mode:
authorGuo Mang <mang.guo@intel.com>2016-06-02 14:04:14 +0800
committerHao Wu <hao.a.wu@intel.com>2016-06-07 09:55:49 +0800
commit6d255d131a1ba172cc4ce3d659e574480b3a0047 (patch)
tree56318d7539bb3f6cc90c7b6a9e24b9551a407427 /ChvRefCodePkg
parenta9682fc88738368ae66857ab599a4e6cc9b651e5 (diff)
downloadedk2-platforms-6d255d131a1ba172cc4ce3d659e574480b3a0047.tar.xz
ChvRefCodePkg: Add SDMediaDeviceDxe driver.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang <mang.guo@intel.com>
Diffstat (limited to 'ChvRefCodePkg')
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/ComponentName.c157
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MMCSDBlockIo.c736
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MMCSDTransfer.c2493
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MediaDeviceDriver.c608
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MediaDeviceDriver.h392
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MmcMediaDeviceDxe.inf62
6 files changed, 4448 insertions, 0 deletions
diff --git a/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/ComponentName.c b/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/ComponentName.c
new file mode 100644
index 0000000000..f662de6bc9
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/ComponentName.c
@@ -0,0 +1,157 @@
+/** @file
+ Header file for ComponentName.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ 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 "MediaDeviceDriver.h"
+
+//#pragma optimize ("", off)
+//
+// EFI Component Name Protocol
+//
+EFI_COMPONENT_NAME_PROTOCOL gMediaDeviceComponentName = {
+ MediaDeviceComponentNameGetDriverName,
+ MediaDeviceComponentNameGetControllerName,
+ "eng"
+};
+
+static EFI_UNICODE_STRING_TABLE mMediaDeviceDriverNameTable[] = {
+ { "eng", L"UEFI MMC/SD Media Device Driver" },
+ { NULL , NULL }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.
+
+ @param[in] This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param[in] Language A pointer to a three character ISO 639-2 language identifier.
+ This is the language of the driver name that that the caller
+ is requesting, and it must match one of the languages specified
+ in SupportedLanguages. The number of languages supported by a
+ driver is up to the driver writer.
+ @param[out] DriverName A pointer to the Unicode string to return. This Unicode string
+ is the name of the driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by This
+ and the language specified by Language was returned
+ in DriverName.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the
+ language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString (
+ Language,
+ gMediaDeviceComponentName.SupportedLanguages,
+ mMediaDeviceDriverNameTable,
+ DriverName
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+ @param[in] This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of a controller that the driver specified by
+ This is managing. This handle specifies the controller
+ whose name is to be returned.
+ @param[in] ChildHandle The handle of the child controller to retrieve the name
+ of. This is an optional parameter that may be NULL. It
+ will be NULL for device drivers. It will also be NULL
+ for a bus drivers that wish to retrieve the name of the
+ bus controller. It will not be NULL for a bus driver
+ that wishes to retrieve the name of a child controller.
+ @param[in] Language A pointer to a three character ISO 639-2 language
+ identifier. This is the language of the controller name
+ that that the caller is requesting, and it must match one
+ of the languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up to the
+ driver writer.
+ @param[in] ControllerName A pointer to the Unicode string to return. This Unicode
+ string is the name of the controller specified by
+ ControllerHandle and ChildHandle in the language
+ specified by Language from the point of view of the
+ driver specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in the
+ language specified by Language for the driver
+ specified by This was returned in DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the
+ language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle, OPTIONAL
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ CARD_DATA *CardData;
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get the device context
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ gMediaDeviceDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CardData = CARD_DATA_FROM_THIS (BlockIo);
+
+ return LookupUnicodeString (
+ Language,
+ gMediaDeviceComponentName.SupportedLanguages,
+ CardData->ControllerNameTable,
+ ControllerName
+ );
+}
diff --git a/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MMCSDBlockIo.c b/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MMCSDBlockIo.c
new file mode 100644
index 0000000000..ec8ef5b4a5
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MMCSDBlockIo.c
@@ -0,0 +1,736 @@
+/** @file
+ Block I/O protocol for MMC/SD device.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ 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 "MediaDeviceDriver.h"
+
+/**
+ Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
+
+ @param[in] This The EFI_BLOCK_IO_PROTOCOL instance.
+ @param[in] ExtendedVerification
+ Indicates that the driver may perform a more exhaustive
+ verification operation of the device during reset.
+ (This parameter is ingored in this driver.)
+
+ @retval EFI_SUCCESS Success
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ CARD_DATA *CardData;
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo;
+#if 1
+ EFI_STATUS Status = EFI_SUCCESS;
+#endif
+
+ CardData = CARD_DATA_FROM_THIS(This);
+ SdHostIo = CardData->SdHostIo;
+
+ DEBUG ((EFI_D_INFO, "MMC SD Block: Resetting host\n"));
+
+#if 1
+ //
+ // EFI 2.3.1 spec specifies this return status only for "EFI_DEVICE_ERROR" and "EFI_SUCCESS"
+ // Others are illegal.
+ //
+ Status = SdHostIo->ResetSdHost (SdHostIo, Reset_DAT_CMD);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+#else
+ return SdHostIo->ResetSdHost (SdHostIo, Reset_DAT_CMD);
+#endif
+}
+
+/**
+ Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
+
+ @param[in] This The EFI_BLOCK_IO_PROTOCOL instance.
+ @param[in] MediaId The media id that the read request is for.
+ @param[in] LBA The starting logical block address to read from on the device.
+ @param[in] BufferSize The size of the Buffer in bytes. This must be a multiple of
+ the intrinsic block size of the device.
+ @param[out] 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_INVALID_PARAMETER Parameter is error
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Address;
+ CARD_DATA *CardData;
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo;
+ UINT32 RemainingLength;
+ UINT32 TransferLength;
+ UINT8 *BufferPointer;
+ BOOLEAN SectorAddressing;
+ UINT64 CardSize;
+ MMC_PARTITION_DATA *Partition;
+ UINTN TotalBlock;
+
+ DEBUG((EFI_D_INFO, "MMCSDBlockReadBlocks: ReadBlocks ...\n"));
+
+ Status = EFI_SUCCESS;
+ Partition = CARD_PARTITION_DATA_FROM_THIS (This);
+ CardData = Partition->CardData;
+ SdHostIo = CardData->SdHostIo;
+
+ DEBUG((EFI_D_INFO,
+ "MMCSDBlockReadBlocks: Read(PART=%d, LBA=0x%08lx, Buffer=0x%08x, Size=0x%08x)\n",
+ CARD_DATA_PARTITION_NUM (Partition), LBA, Buffer, BufferSize
+ ));
+
+#if 1
+ //
+ // Media ID has high priority that need to be verify first
+ //
+ if (MediaId != Partition->BlockIoMedia.MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+#endif
+
+ Status = MmcSelectPartition (Partition);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+#if 1
+ //
+ // BufferSize must be a multiple of the intrinsic block size of the device.
+ //
+ if (ModU64x32 (BufferSize,Partition->BlockIoMedia.BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+#endif
+
+ CardSize = MultU64x32 (CardData->BlockNumber, CardData->BlockLen);
+
+ if ((CardData->CardType == SDMemoryCard2High) || (CardSize >= SIZE_2GB)) {
+ SectorAddressing = TRUE;
+ } else {
+ SectorAddressing = FALSE;
+ }
+
+ if (SectorAddressing) {
+ //
+ // Sector Address
+ //
+ Address = (UINT32)DivU64x32 (MultU64x32 (LBA, Partition->BlockIoMedia.BlockSize), 512);
+ } else {
+ //
+ //Byte Address
+ //
+ Address = (UINT32)MultU64x32 (LBA, Partition->BlockIoMedia.BlockSize);
+ }
+
+#if 1
+
+ TotalBlock = (UINTN) DivU64x32 (BufferSize, Partition->BlockIoMedia.BlockSize);
+ //
+ // Make sure the range to read is valid.
+ //
+ if (LBA + TotalBlock > Partition->BlockIoMedia.LastBlock + 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!(Partition->BlockIoMedia.MediaPresent)) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (!Buffer) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if ((BufferSize % Partition->BlockIoMedia.BlockSize) != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Done;
+ }
+
+ if (BufferSize == 0) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+#else
+ if (!(Partition->BlockIoMedia.MediaPresent)) {
+ Status = EFI_NO_MEDIA;
+ goto Done;
+ }
+
+ if (MediaId != Partition->BlockIoMedia.MediaId ) {
+ Status = EFI_MEDIA_CHANGED;
+ goto Done;
+ }
+
+ if (Buffer == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (BufferSize == 0) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ TotalBlock = (UINTN) DivU64x32 (BufferSize, Partition->BlockIoMedia.BlockSize);
+ //
+ // Make sure the range to read is valid.
+ //
+ if (LBA + TotalBlock - 1 > Partition->BlockIoMedia.LastBlock ) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // BufferSize must be a multiple of the intrinsic block size of the device.
+ //
+ if ((BufferSize % Partition->BlockIoMedia.BlockSize) != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Done;
+ }
+#endif
+
+ BufferPointer = Buffer;
+ RemainingLength = (UINT32) BufferSize;
+
+ while (RemainingLength > 0) {
+
+#if 1
+ if ((BufferSize > Partition->BlockIoMedia.BlockSize)) {
+#else
+ if ((BufferSize >= Partition->BlockIoMedia.BlockSize)) {
+#endif
+ if (RemainingLength > SdHostIo->HostCapability.BoundarySize) {
+ TransferLength = SdHostIo->HostCapability.BoundarySize;
+ } else {
+ TransferLength = RemainingLength;
+ }
+
+ if (CardData->CardType == MMCCard) {
+ if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {
+ Status = SendCommand (
+ SdHostIo,
+ SET_BLOCKLEN,
+ Partition->BlockIoMedia.BlockSize,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ Status = SendCommand (
+ SdHostIo,
+ SET_BLOCK_COUNT,
+ TransferLength / Partition->BlockIoMedia.BlockSize,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ Status = SendCommand (
+ SdHostIo,
+ READ_MULTIPLE_BLOCK,
+ Address,
+ InData,
+ CardData->AlignedBuffer,
+ TransferLength,
+ ResponseR1,
+ TIMEOUT_DATA,
+ (UINT32*)&(CardData->CardStatus)
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_MULTIPLE_BLOCK -> Fail\n"));
+ break;
+ }
+ } else {
+ if (RemainingLength > Partition->BlockIoMedia.BlockSize) {
+ TransferLength = Partition->BlockIoMedia.BlockSize;
+ } else {
+ TransferLength = RemainingLength;
+ }
+
+ Status = SendCommand (
+ SdHostIo,
+ READ_SINGLE_BLOCK,
+ Address,
+ InData,
+ CardData->AlignedBuffer,
+ (UINT32)TransferLength,
+ ResponseR1,
+ TIMEOUT_DATA,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_SINGLE_BLOCK -> Fail\n"));
+ break;
+ }
+ }
+
+ CopyMem (BufferPointer, CardData->AlignedBuffer, TransferLength);
+
+ if (SectorAddressing) {
+ //
+ // Sector Address
+ //
+ Address += TransferLength / 512;
+ } else {
+ //
+ //Byte Address
+ //
+ Address += TransferLength;
+ }
+ BufferPointer += TransferLength;
+ RemainingLength -= TransferLength;
+ }
+
+ if (EFI_ERROR (Status)) {
+ if ((CardData->CardType == SDMemoryCard) ||
+ (CardData->CardType == SDMemoryCard2)||
+ (CardData->CardType == SDMemoryCard2High)) {
+ SendCommand (
+ SdHostIo,
+ STOP_TRANSMISSION,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1b,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ } else {
+ SendCommand (
+ SdHostIo,
+ STOP_TRANSMISSION,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ }
+
+ }
+
+Done:
+ DEBUG((EFI_D_INFO, "MMCSDBlockReadBlocks: Status = %r\n", Status));
+ return Status;
+}
+
+/**
+ Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
+
+ @param[in] This The EFI_BLOCK_IO_PROTOCOL instance.
+ @param[in] MediaId The media id that the write request is for.
+ @param[in] LBA The starting logical block address to be written.
+ The caller is responsible for writing to only legitimate locations.
+ @param[in] BufferSize The size of the Buffer in bytes. This must be a multiple of
+ the intrinsic block size of the device.
+ @param[in] Buffer A pointer to the source buffer for the data. The caller
+ is responsible for either having implicit or explicit ownership
+ of the buffer.
+
+ @retval EFI_INVALID_PARAMETER Parameter is error
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Hardware Error
+ @retval EFI_NO_MEDIA No media
+ @retval EFI_MEDIA_CHANGED Media Change
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Address;
+ CARD_DATA *CardData;
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo;
+ UINT32 RemainingLength;
+ UINT32 TransferLength;
+ UINT8 *BufferPointer;
+ BOOLEAN SectorAddressing;
+ UINT64 CardSize;
+ MMC_PARTITION_DATA *Partition;
+
+ DEBUG((EFI_D_INFO, "MMCSDBlockWriteBlocks: WriteBlocks ...\n"));
+
+ Status = EFI_SUCCESS;
+ Partition = CARD_PARTITION_DATA_FROM_THIS (This);
+ CardData = Partition->CardData;
+ SdHostIo = CardData->SdHostIo;
+
+ DEBUG((EFI_D_INFO,
+ "MMCSDBlockWriteBlocks: Write (PART=%d, LBA=0x%08lx, Buffer=0x%08x, Size=0x%08x)\n",
+ CARD_DATA_PARTITION_NUM (Partition), LBA, Buffer, BufferSize
+ ));
+
+ Status = MmcSelectPartition (Partition);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CardSize = MultU64x32 (CardData->BlockNumber, CardData->BlockLen);
+
+ if ((CardData->CardType == SDMemoryCard2High) || (CardSize >= SIZE_2GB)) {
+ SectorAddressing = TRUE;
+ } else {
+ SectorAddressing = FALSE;
+ }
+
+ if (SectorAddressing) {
+ //
+ // Sector Address
+ //
+ Address = (UINT32)DivU64x32 (MultU64x32 (LBA, Partition->BlockIoMedia.BlockSize), 512);
+ } else {
+ //
+ //Byte Address
+ //
+ Address = (UINT32)MultU64x32 (LBA, Partition->BlockIoMedia.BlockSize);
+ }
+
+ if (!Buffer) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Invalid parameter \n"));
+ goto Done;
+ }
+
+ if ((BufferSize % Partition->BlockIoMedia.BlockSize) != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Bad buffer size \n"));
+ goto Done;
+ }
+
+ if (BufferSize == 0) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ if (This->Media->ReadOnly == TRUE) {
+ Status = EFI_WRITE_PROTECTED;
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Write protected \n"));
+ goto Done;
+ }
+
+ BufferPointer = Buffer;
+ RemainingLength = (UINT32) BufferSize;
+
+ while (RemainingLength > 0) {
+
+#if 1
+ if ((BufferSize > Partition->BlockIoMedia.BlockSize) ) {
+#else
+ if ((BufferSize >= Partition->BlockIoMedia.BlockSize) ) {
+#endif
+ if (RemainingLength > SdHostIo->HostCapability.BoundarySize) {
+ TransferLength = SdHostIo->HostCapability.BoundarySize;
+ } else {
+ TransferLength = RemainingLength;
+ }
+
+#if 1
+ if (CardData->CardType == MMCCard) {
+#else
+ if ((CardData->CardType == SDMemoryCard) ||
+ (CardData->CardType == SDMemoryCard2)||
+ (CardData->CardType == SDMemoryCard2High)) {
+ //
+ // Write performance improvement
+ //
+ if ((TransferLength / Partition->BlockIoMedia.BlockSize) > 64) {
+ Status = SendAppCommand (
+ CardData,
+ SET_WR_BLK_ERASE_COUNT,
+ (UINT32)(TransferLength / Partition->BlockIoMedia.BlockSize),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ }
+ } else if (CardData->CardType == MMCCard) {
+#endif
+ if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {
+ Status = SendCommand (
+ SdHostIo,
+ SET_BLOCKLEN,
+ Partition->BlockIoMedia.BlockSize,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ Status = SendCommand (
+ SdHostIo,
+ SET_BLOCK_COUNT,
+ TransferLength / Partition->BlockIoMedia.BlockSize,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
+
+ Status = SendCommand (
+ SdHostIo,
+ WRITE_MULTIPLE_BLOCK,
+ Address,
+ OutData,
+ CardData->AlignedBuffer,
+ (UINT32)TransferLength,
+ ResponseR1,
+ TIMEOUT_DATA,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: WRITE_MULTIPLE_BLOCK -> Fail\n"));
+ break;
+ }
+ } else {
+ if (RemainingLength > Partition->BlockIoMedia.BlockSize) {
+ TransferLength = Partition->BlockIoMedia.BlockSize;
+ } else {
+ TransferLength = RemainingLength;
+ }
+
+ CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
+
+ Status = SendCommand (
+ SdHostIo,
+ WRITE_BLOCK,
+ Address,
+ OutData,
+ CardData->AlignedBuffer,
+ (UINT32)TransferLength,
+ ResponseR1,
+ TIMEOUT_DATA,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ }
+
+ if (SectorAddressing) {
+ //
+ // Sector Address
+ //
+ Address += TransferLength / 512;
+ } else {
+ //
+ //Byte Address
+ //
+ Address += TransferLength;
+ }
+ BufferPointer += TransferLength;
+ RemainingLength -= TransferLength;
+ }
+
+ if (EFI_ERROR (Status)) {
+ SendCommand (
+ SdHostIo,
+ STOP_TRANSMISSION,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1b,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+
+ }
+
+Done:
+ return Status;
+}
+
+/**
+ Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
+ (In this driver, this function just returns EFI_SUCCESS.)
+
+ @param[in] This The EFI_BLOCK_IO_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Success
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ MMC/SD card BlockIo init function.
+
+ @param[in] CardData Pointer to CARD_DATA
+
+ @retval EFI_SUCCESS Success
+
+**/
+EFI_STATUS
+MMCSDBlockIoInit (
+ IN CARD_DATA *CardData
+ )
+{
+ UINTN Loop;
+ MMC_PARTITION_DATA *Partition;
+ EXT_CSD *ExtCsd;
+ UINT64 GP_CHUNK_SIZE;
+ UINT32 GP_SIZE_MULT;
+ UINT64 GppSize;
+ UINTN GppIndex=0;
+
+ Partition = CardData->Partitions;
+
+ ExtCsd = &CardData->ExtCSDRegister;
+
+ //
+ // Determine GP partitioning chunk size
+ //
+ GP_CHUNK_SIZE = 0;
+ if (((ExtCsd->PARTITIONING_SUPPORT & BIT0) == BIT0) &&
+ ((ExtCsd->PARTITION_SETTING_COMPLETED & BIT0) == BIT0)) {
+ GP_CHUNK_SIZE = MultU64x32 (ExtCsd->HC_WP_GRP_SIZE * ExtCsd->HC_ERASE_GRP_SIZE, SIZE_512KB);
+ }
+
+ for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Partition++, Loop++) {
+ //
+ //BlockIO protocol
+ //
+ Partition->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
+ Partition->BlockIo.Media = &(Partition->BlockIoMedia);
+ Partition->BlockIo.Reset = MMCSDBlockReset;
+ Partition->BlockIo.ReadBlocks = MMCSDBlockReadBlocks ;
+ Partition->BlockIo.WriteBlocks = MMCSDBlockWriteBlocks;
+ Partition->BlockIo.FlushBlocks = MMCSDBlockFlushBlocks;
+
+ Partition->BlockIoMedia.MediaId = 0;
+ Partition->BlockIoMedia.RemovableMedia = FALSE;
+ Partition->BlockIoMedia.MediaPresent = TRUE;
+ Partition->BlockIoMedia.LogicalPartition = FALSE;
+
+ //
+ // Force the User partition to be enabled
+ //
+ if (Loop == 0) {
+ Partition->Present = TRUE;
+ }
+
+ if (CardData->CSDRegister.PERM_WRITE_PROTECT || CardData->CSDRegister.TMP_WRITE_PROTECT) {
+ Partition->BlockIoMedia.ReadOnly = TRUE;
+ } else {
+ Partition->BlockIoMedia.ReadOnly = FALSE;
+ }
+
+ Partition->BlockIoMedia.WriteCaching = FALSE;
+ Partition->BlockIoMedia.BlockSize = CardData->BlockLen;
+ Partition->BlockIoMedia.IoAlign = 1;
+ Partition->BlockIoMedia.LastBlock = (EFI_LBA)(CardData->BlockNumber - 1);
+
+ //
+ // Handle GPP partitions
+ //
+ GppSize = 0;
+ if ((GP_CHUNK_SIZE != 0) && (Loop >= 4)) {
+ Partition->BlockIoMedia.LastBlock = (EFI_LBA) 0;
+ GppIndex = Loop - 4;
+ GP_SIZE_MULT = MmcGetExtCsd24 (
+ CardData,
+ OFFSET_OF (EXT_CSD, GP_SIZE_MULT_1) + (3 * GppIndex)
+ );
+ GppSize = MultU64x32 (GP_SIZE_MULT, (UINT32)GP_CHUNK_SIZE);
+ }
+
+ if (GppSize != 0) {
+ Partition->BlockIoMedia.LastBlock =
+ DivU64x32 (GppSize, Partition->BlockIoMedia.BlockSize) - 1;
+ DEBUG ((EFI_D_INFO,
+ "GPP%d last-block: 0x%lx\n",
+ GppIndex + 1,
+ Partition->BlockIoMedia.LastBlock
+ ));
+ Partition->Present = TRUE;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "MMC SD Block I/O: Initialized\n"));
+
+ return EFI_SUCCESS;
+}
+
diff --git a/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MMCSDTransfer.c b/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MMCSDTransfer.c
new file mode 100644
index 0000000000..6aec73cdd8
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MMCSDTransfer.c
@@ -0,0 +1,2493 @@
+/** @file
+ MMC/SD transfer specific functions.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ 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 "MediaDeviceDriver.h"
+
+
+EFI_EVENT mSetEmmcWpOnEvent = NULL;
+
+#define STALL(arg) gBS->Stall (arg/10)
+
+#define NORMAL_SETUP_NAME L"Setup"
+
+/**
+ Check card status, print the debug info and check the error.
+
+ @param[in] Status Status got from card status register
+
+ @retval EFI_DEVICE_ERROR
+ @retval EFI_SUCCESS
+
+ **/
+EFI_STATUS
+CheckCardStatus (
+ IN UINT32 Status
+ )
+{
+ CARD_STATUS *CardStatus;
+ CardStatus = (CARD_STATUS*)(&Status);
+
+ if (CardStatus->ADDRESS_OUT_OF_RANGE) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_OUT_OF_RANGE\n"));
+ }
+
+ if (CardStatus->ADDRESS_MISALIGN) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_MISALIGN\n"));
+ }
+
+ if (CardStatus->BLOCK_LEN_ERROR) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: BLOCK_LEN_ERROR\n"));
+ }
+
+ if (CardStatus->ERASE_SEQ_ERROR) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_SEQ_ERROR\n"));
+ }
+
+ if (CardStatus->ERASE_PARAM) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_PARAM\n"));
+ }
+
+ if (CardStatus->WP_VIOLATION) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: WP_VIOLATION\n"));
+ }
+
+ if (CardStatus->CARD_IS_LOCKED) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: CARD_IS_LOCKED\n"));
+ }
+
+ if (CardStatus->LOCK_UNLOCK_FAILED) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: LOCK_UNLOCK_FAILED\n"));
+ }
+
+ if (CardStatus->COM_CRC_ERROR) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: COM_CRC_ERROR\n"));
+ }
+
+ if (CardStatus->ILLEGAL_COMMAND) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: ILLEGAL_COMMAND\n"));
+ }
+
+ if (CardStatus->CARD_ECC_FAILED) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: CARD_ECC_FAILED\n"));
+ }
+
+ if (CardStatus->CC_ERROR) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: CC_ERROR\n"));
+ }
+
+ if (CardStatus->ERROR) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: ERROR\n"));
+ }
+
+ if (CardStatus->UNDERRUN) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: UNDERRUN\n"));
+ }
+
+ if (CardStatus->OVERRUN) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: OVERRUN\n"));
+ }
+
+ if (CardStatus->CID_CSD_OVERWRITE) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: CID_CSD_OVERWRITE\n"));
+ }
+
+ if (CardStatus->WP_ERASE_SKIP) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: WP_ERASE_SKIP\n"));
+ }
+
+ if (CardStatus->ERASE_RESET) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_RESET\n"));
+ }
+
+ if (CardStatus->SWITCH_ERROR) {
+ DEBUG ((EFI_D_ERROR, "CardStatus: SWITCH_ERROR\n"));
+ }
+
+ if ((Status & 0xFCFFA080) != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send command by using Host IO protocol.
+
+ @param[in] This Pointer to EFI_SD_HOST_IO_PROTOCOL
+ @param[in] CommandIndex The command index to set the command index field of command register
+ @param[in] Argument Command argument to set the argument field of command register
+ @param[in] DataType TRANSFER_TYPE, indicates no data, data in or data out
+ @param[in] Buffer Contains the data read from / write to the device
+ @param[in] BufferSize The size of the buffer
+ @param[in] ResponseType RESPONSE_TYPE
+ @param[in] TimeOut Time out value in 1 ms unit
+ @param[out] ResponseData Depending on the ResponseType, such as CSD or card status
+
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_UNSUPPORTED
+ @retval EFI_DEVICE_ERROR
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+SendCommand (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN UINT16 CommandIndex,
+ IN UINT32 Argument,
+ IN TRANSFER_TYPE DataType,
+ IN UINT8 *Buffer, OPTIONAL
+ IN UINT32 BufferSize,
+ IN RESPONSE_TYPE ResponseType,
+ IN UINT32 TimeOut,
+ OUT UINT32 *ResponseData
+ )
+{
+ EFI_STATUS Status;
+
+ Status = This->SendCommand (
+ This,
+ CommandIndex,
+ Argument,
+ DataType,
+ Buffer,
+ BufferSize,
+ ResponseType,
+ TimeOut,
+ ResponseData
+ );
+ if (!EFI_ERROR (Status)) {
+ if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {
+ ASSERT(ResponseData != NULL);
+ Status = CheckCardStatus (*ResponseData);
+ }
+ } else {
+ This->ResetSdHost (This, Reset_DAT_CMD);
+ }
+
+ return Status;
+}
+
+/**
+ Send the card APP_CMD command with the following command indicated
+ by CommandIndex.
+
+ @param[in] CardData Pointer to CARD_DATA
+ @param[in] CommandIndex The command index to set the command index field of command register
+ @param[in] Argument Command argument to set the argument field of command register
+ @param[in] DataType TRANSFER_TYPE, indicates no data, data in or data out
+ @param[in] Buffer Contains the data read from / write to the device
+ @param[in] BufferSize The size of the buffer
+ @param[in] ResponseType RESPONSE_TYPE
+ @param[in] TimeOut Time out value in 1 ms unit
+ @param[out] ResponseData Depending on the ResponseType, such as CSD or card status
+
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_UNSUPPORTED
+ @retval EFI_DEVICE_ERROR
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+SendAppCommand (
+ IN CARD_DATA *CardData,
+ IN UINT16 CommandIndex,
+ IN UINT32 Argument,
+ IN TRANSFER_TYPE DataType,
+ IN UINT8 *Buffer, OPTIONAL
+ IN UINT32 BufferSize,
+ IN RESPONSE_TYPE ResponseType,
+ IN UINT32 TimeOut,
+ OUT UINT32 *ResponseData
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo;
+ UINT8 Index;
+
+ SdHostIo = CardData->SdHostIo;
+ Status = EFI_SUCCESS;
+
+ for (Index = 0; Index < 2; Index++) {
+ Status = SdHostIo->SendCommand (
+ SdHostIo,
+ APP_CMD,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = CheckCardStatus (*(UINT32*)&(CardData->CardStatus));
+ if (CardData->CardStatus.SAPP_CMD != 1) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ } else {
+ SdHostIo->ResetSdHost (SdHostIo, Reset_Auto);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdHostIo->SendCommand (
+ SdHostIo,
+ CommandIndex,
+ Argument,
+ DataType,
+ Buffer,
+ BufferSize,
+ ResponseType,
+ TimeOut,
+ ResponseData
+ );
+ if (!EFI_ERROR (Status)) {
+ if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {
+ ASSERT(ResponseData != NULL);
+ Status = CheckCardStatus (*ResponseData);
+ }
+ } else {
+ SdHostIo->ResetSdHost (SdHostIo, Reset_Auto);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+MmcDecodeOCR (
+ IN OCR *OCRReg
+ )
+{
+ DEBUG((EFI_D_INFO, "\n==========DECODE MMC OCR REGISTER==================\n"));
+ DEBUG((EFI_D_ERROR," OCR = 0x%08X\n", *((UINT32 *)OCRReg)));
+ DEBUG((EFI_D_ERROR, " CARD_NOT_BUSY = 0x%X\n",OCRReg->Busy));
+ DEBUG((EFI_D_ERROR, " ACCESS_MODE = 0x%X\n",OCRReg->AccessMode));
+ DEBUG((EFI_D_ERROR, " VDD_270_360 = 0x%X\n",OCRReg->V270_V360));
+ DEBUG((EFI_D_ERROR, " VDD_200_260 = 0x%X\n",OCRReg->V200_V260));
+ DEBUG((EFI_D_ERROR, " VDD_170_195 = 0x%X\n",OCRReg->V170_V195));
+ DEBUG((EFI_D_INFO, "==================================================\n"));
+ return 0;
+}
+
+EFI_STATUS
+MmcDecodeCID (
+ IN CID *CIDReg
+ )
+{
+ UINT32 i = 0;
+ DEBUG((EFI_D_INFO, "\n==========DECODE MMC CID REGISTER==================\n"));
+ DEBUG((EFI_D_INFO," CID = 0x%032X\n",CIDReg));
+ DEBUG((EFI_D_INFO," MANUFACTURER_ID = 0x%X\n",CIDReg->MID));
+ DEBUG((EFI_D_INFO," CARD_OR_BGA = 0x%X\n",(CIDReg->OID & 0xFF00)>>6));
+ DEBUG((EFI_D_INFO," OEM_APPLICATION_ID = 0x%X\n",(CIDReg->OID>>8)&0xFF));
+ DEBUG((EFI_D_INFO," PRODUCT_NAME = "));
+ for (i=0; i < 6; i++) {
+ DEBUG((EFI_D_INFO, "%c",CIDReg->PNM[i]));
+ }
+ DEBUG((EFI_D_INFO, "\n"));
+
+ DEBUG((EFI_D_INFO," PRODUCT_REVISION = 0x%X\n",CIDReg->PRV));
+ DEBUG((EFI_D_INFO," PRODUCT_SERIAL_NUM = 0x%X\n",CIDReg->PSN));
+ DEBUG((EFI_D_INFO," MANUFACTURE_DATE = 0x%X\n",CIDReg->MDT));
+ DEBUG((EFI_D_INFO, "==================================================\n"));
+ return 0;
+}
+
+EFI_STATUS
+MmcDecodeCSD (
+ IN CSD *CSDReg
+ )
+{
+ DEBUG((EFI_D_INFO, "\n==========DECODE MMC CSD REGISTER==================\n"));
+ DEBUG((EFI_D_INFO, "csd_struct : [0x%0x] \n",CSDReg->CSD_STRUCTURE));
+ DEBUG((EFI_D_INFO, "specs_ver : [0x%0x] \n",CSDReg->SPEC_VERS));
+ DEBUG((EFI_D_INFO, "reserve2 : [0x%0x] \n",CSDReg->Reserved2));
+ DEBUG((EFI_D_INFO, "taac : [0x%0x] \n",CSDReg->TAAC));
+ DEBUG((EFI_D_INFO, "nsac : [0x%0x] \n",CSDReg->NSAC));
+ DEBUG((EFI_D_INFO, "tran_speed : [0x%0x] \n",CSDReg->TRAN_SPEED));
+ DEBUG((EFI_D_INFO, "ccc : [0x%0x] \n",CSDReg->CCC));
+ DEBUG((EFI_D_INFO, "read_bl_len : [0x%0x] \n",CSDReg->READ_BL_LEN));
+ DEBUG((EFI_D_INFO, "read_partial : [0x%0x] \n",CSDReg->READ_BL_PARTIAL));
+ DEBUG((EFI_D_INFO, "write_misalign : [0x%0x] \n",CSDReg->WRITE_BLK_MISALIGN));
+ DEBUG((EFI_D_INFO, "read_misalign : [0x%0x] \n",CSDReg->READ_BLK_MISALIGN));
+ DEBUG((EFI_D_INFO, "dsr_imp : [0x%0x] \n",CSDReg->DSR_IMP));
+ DEBUG((EFI_D_INFO, "reserve1 : [0x%0x] \n",CSDReg->Reserved1));
+ DEBUG((EFI_D_INFO, "c_size : [0x%0x] \n",CSDReg->C_SIZELow2 | CSDReg->C_SIZEHigh10<<2));
+ DEBUG((EFI_D_INFO, "vdd_r_curr_min : [0x%0x] \n",CSDReg->VDD_R_CURR_MIN));
+ DEBUG((EFI_D_INFO, "vdd_r_curr_max : [0x%0x] \n",CSDReg->VDD_R_CURR_MAX));
+ DEBUG((EFI_D_INFO, "vdd_w_curr_min : [0x%0x] \n",CSDReg->VDD_W_CURR_MIN));
+ DEBUG((EFI_D_INFO, "vdd_w_curr_max : [0x%0x] \n",CSDReg->VDD_W_CURR_MAX));
+ DEBUG((EFI_D_INFO, "c_size_mult : [0x%0x] \n",CSDReg->C_SIZE_MULT));
+ DEBUG((EFI_D_INFO, "erase_grp_size : [0x%0x] \n",CSDReg->ERASE_GRP_SIZE));
+ DEBUG((EFI_D_INFO, "erase_grp_mult : [0x%0x] \n",CSDReg->ERASE_GRP_MULT));
+ DEBUG((EFI_D_INFO, "wp_grp_size : [0x%0x] \n",CSDReg->WP_GRP_SIZE));
+ DEBUG((EFI_D_INFO, "wp_grp_enable : [0x%0x] \n",CSDReg->WP_GRP_ENABLE));
+ DEBUG((EFI_D_INFO, "default_ecc : [0x%0x] \n",CSDReg->DEFAULT_ECC));
+ DEBUG((EFI_D_INFO, "r2w_factor : [0x%0x] \n",CSDReg->R2W_FACTOR));
+ DEBUG((EFI_D_INFO, "write_bl_len : [0x%0x] \n",CSDReg->WRITE_BL_LEN));
+ DEBUG((EFI_D_INFO, "write_partial : [0x%0x] \n",CSDReg->WRITE_BL_PARTIAL));
+ DEBUG((EFI_D_INFO, "reserve0 : [0x%0x] \n",CSDReg->Reserved0));
+ DEBUG((EFI_D_INFO, "content_prot_app : [0x%0x] \n",CSDReg->CONTENT_PROT_APP));
+ DEBUG((EFI_D_INFO, "file_format_grp : [0x%0x] \n",CSDReg->FILE_FORMAT_GRP));
+ DEBUG((EFI_D_INFO, "copy : [0x%0x] \n",CSDReg->COPY));
+ DEBUG((EFI_D_INFO, "perm_write_protect: [0x%0x] \n",CSDReg->PERM_WRITE_PROTECT));
+ DEBUG((EFI_D_INFO, "tmp_write_prot : [0x%0x] \n",CSDReg->TMP_WRITE_PROTECT));
+ DEBUG((EFI_D_INFO, "file_format : [0x%0x] \n",CSDReg->FILE_FORMAT));
+ DEBUG((EFI_D_INFO, "ecc : [0x%0x] \n",CSDReg->ECC));
+ DEBUG((EFI_D_INFO, "==================================================\n"));
+ return 0;
+}
+
+EFI_STATUS
+MmcDecodeExtCSD (
+ IN EXT_CSD *ExtCSDReg
+ )
+{
+ DEBUG((EFI_D_INFO, "\n==========DECODE MMC EXT CSD REGISTER==================\n"));
+ DEBUG((EFI_D_INFO," SUPPORTED_CMD_SETS = 0x%X\n",ExtCSDReg->CMD_SET));
+ DEBUG((EFI_D_INFO," HPI_FEATURES = 0x%X\n",ExtCSDReg->HPI_FEATURES));
+ DEBUG((EFI_D_INFO," BKOPS_SUPPORT = 0x%X\n",ExtCSDReg->BKOPS_SUPPORT));
+ DEBUG((EFI_D_INFO," BKOPS_STATUS = 0x%X\n",ExtCSDReg->BKOPS_STATUS));
+ DEBUG((EFI_D_INFO," CORRECTLY_PRG_SECTORS_NUM = 0x%X%X%X%X\n",ExtCSDReg->CORRECTLY_PRG_SECTORS_NUM[3], \
+ ExtCSDReg->CORRECTLY_PRG_SECTORS_NUM[2], ExtCSDReg->CORRECTLY_PRG_SECTORS_NUM[1], ExtCSDReg->CORRECTLY_PRG_SECTORS_NUM[0]));
+ DEBUG((EFI_D_INFO," INI_TIMEOUT_AP = 0x%X\n",ExtCSDReg->INI_TIMEOUT_AP));
+ DEBUG((EFI_D_INFO," PWR_CL_DDR_52_195 = 0x%X\n",ExtCSDReg->PWR_CL_DDR_52_195));
+ DEBUG((EFI_D_INFO," PWR_CL_DDR_52_360 = 0x%X\n",ExtCSDReg->PWR_CL_DDR_52_360));
+ DEBUG((EFI_D_INFO," MIN_PRF_DDR_W_8_52 = 0x%X\n",ExtCSDReg->MIN_PERF_DDR_W_8_52));
+ DEBUG((EFI_D_INFO," MIN_PRF_DDR_R_8_52 = 0x%X\n",ExtCSDReg->MIN_PERF_DDR_R_8_52));
+ DEBUG((EFI_D_INFO," TRIM_MULT = 0x%X\n",ExtCSDReg->TRIM_MULT));
+ DEBUG((EFI_D_INFO," SEC_FEATURE_SUPP = 0x%X\n",ExtCSDReg->SEC_FEATURE_SUPPORT));
+ DEBUG((EFI_D_INFO," SEC_ERASE_MULT = 0x%X\n",ExtCSDReg->SEC_ERASE_MULT));
+ DEBUG((EFI_D_INFO," SEC_TRIM_MULT = 0x%X\n",ExtCSDReg->SEC_TRIM_MULT));
+ DEBUG((EFI_D_INFO," BOOT_INFO = 0x%X\n",ExtCSDReg->BOOT_INFO));
+ DEBUG((EFI_D_INFO," BOOT_PART_SIZE = 0x%X\n",ExtCSDReg->BOOT_SIZE_MULTI));
+ DEBUG((EFI_D_INFO," ACCESS_SIZE = 0x%X\n",ExtCSDReg->ACC_SIZE));
+ DEBUG((EFI_D_INFO," HI_CAP_ER_GRP_SIZE = 0x%X\n",ExtCSDReg->HC_ERASE_GRP_SIZE));
+ DEBUG((EFI_D_INFO," HI_CAP_ER_TIMEOUT = 0x%X\n",ExtCSDReg->ERASE_TIMEOUT_MULT));
+ DEBUG((EFI_D_INFO," REL_WR_SECTOR_CNT = 0x%X\n",ExtCSDReg->REL_WR_SEC_C));
+ DEBUG((EFI_D_INFO," HI_CAP_WP_GRP_SIZE = 0x%X\n",ExtCSDReg->HC_WP_GRP_SIZE));
+ DEBUG((EFI_D_INFO," SLEEP_CURRENT_VCC = 0x%X\n",ExtCSDReg->S_C_VCC));
+ DEBUG((EFI_D_INFO," SLEEP_CURRENT_VCCQ = 0x%X\n",ExtCSDReg->S_C_VCCQ));
+ DEBUG((EFI_D_INFO," SLP_AWK_TIMEOUT = 0x%X\n",ExtCSDReg->S_A_TIMEOUT));
+ DEBUG((EFI_D_INFO," SECTOR_COUNT = 0x%X\n",*(UINT32*)((UINT8 *)&ExtCSDReg->SEC_COUNT)));
+ DEBUG((EFI_D_INFO," MIN_PERF_W_8_52 = 0x%X\n",ExtCSDReg->MIN_PERF_W_8_52));
+ DEBUG((EFI_D_INFO," MIN_PERF_R_8_52 = 0x%X\n",ExtCSDReg->MIN_PERF_R_8_52));
+ DEBUG((EFI_D_INFO," MIN_PERF_W_8_26_4_52 = 0x%X\n",ExtCSDReg->MIN_PERF_W_8_26_4_52));
+ DEBUG((EFI_D_INFO," MIN_PERF_W_8_26_4_52 = 0x%X\n",ExtCSDReg->MIN_PERF_W_8_26_4_52));
+ DEBUG((EFI_D_INFO," MIN_PERF_W_4_26 = 0x%X\n",ExtCSDReg->MIN_PERF_W_4_26));
+ DEBUG((EFI_D_INFO," MIN_PERF_R_4_26 = 0x%X\n",ExtCSDReg->MIN_PERF_R_4_26));
+ DEBUG((EFI_D_INFO," PWR_CLASS_26_360 = 0x%X\n",ExtCSDReg->PWR_CL_26_360));
+ DEBUG((EFI_D_INFO," PWR_CLASS_52_360 = 0x%X\n",ExtCSDReg->PWR_CL_52_360));
+ DEBUG((EFI_D_INFO," PWR_CLASS_26_195 = 0x%X\n",ExtCSDReg->PWR_CL_26_195));
+ DEBUG((EFI_D_INFO," PWR_CLASS_52_195 = 0x%X\n",ExtCSDReg->PWR_CL_52_195));
+ DEBUG((EFI_D_INFO," PARTITION_SWITCH_TIME = 0x%X\n",ExtCSDReg->PARTITION_SWITCH_TIME));
+ DEBUG((EFI_D_INFO," OUT_OF_INTERRUPT_TIME = 0x%X\n",ExtCSDReg->OUT_OF_INTERRUPT_TIME));
+ DEBUG((EFI_D_INFO," CARD_TYPE = 0x%X\n",ExtCSDReg->CARD_TYPE));
+ DEBUG((EFI_D_INFO," CSD_STRUCTURE = 0x%X\n",ExtCSDReg->CSD_STRUCTURE));
+ DEBUG((EFI_D_INFO," EXT_CSD_REV = 0x%X\n",ExtCSDReg->EXT_CSD_REV));
+ DEBUG((EFI_D_INFO," CMD_SET = 0x%X\n",ExtCSDReg->CMD_SET));
+ DEBUG((EFI_D_INFO," CMD_SET_REV = 0x%X\n",ExtCSDReg->CMD_SET_REV));
+ DEBUG((EFI_D_INFO," PWR_CLASS = 0x%X\n",ExtCSDReg->POWER_CLASS));
+ DEBUG((EFI_D_INFO," HI_SPEED_TIMING = 0x%X\n",ExtCSDReg->HS_TIMING));
+ DEBUG((EFI_D_INFO," BUS_WIDTH_MODE = 0x%X\n",ExtCSDReg->BUS_WIDTH));
+ DEBUG((EFI_D_INFO," ERASED_MEM_CONTENT = 0x%X\n",ExtCSDReg->ERASED_MEM_CONT));
+ DEBUG((EFI_D_INFO," PARTITION_CONFIG = 0x%X\n",ExtCSDReg->PARTITION_CONFIG));
+ DEBUG((EFI_D_INFO," BOOT_CONFIG_PROT = 0x%X\n",ExtCSDReg->BOOT_CONFIG_PROT));
+ DEBUG((EFI_D_INFO," BOOT_BUS_WIDTH = 0x%X\n",ExtCSDReg->BOOT_BUS_WIDTH));
+ DEBUG((EFI_D_INFO," HI_DEN_ER_GRP_DEF = 0x%X\n",ExtCSDReg->ERASE_GROUP_DEF));
+ DEBUG((EFI_D_INFO," BOOT_WP = 0x%X\n",ExtCSDReg->BOOT_WP));
+ DEBUG((EFI_D_INFO," USER_WP = 0x%X\n",ExtCSDReg->USER_WP));
+ DEBUG((EFI_D_INFO," FW_CONFIG = 0x%X\n",ExtCSDReg->FW_CONFIG));
+ DEBUG((EFI_D_INFO," RPMB_SIZE_MULT = 0x%X\n",ExtCSDReg->RPMB_SIZE_MULT));
+ DEBUG((EFI_D_INFO," RST_N_FUNCTION = 0x%X\n",ExtCSDReg->RST_n_FUNCTION));
+ DEBUG((EFI_D_INFO," PARTITIONING_SUPP = 0x%X\n",ExtCSDReg->PARTITIONING_SUPPORT));
+ DEBUG((EFI_D_INFO," MAX_ENH_SIZE_MULT = 0x%02X%02X%02X\n",ExtCSDReg->MAX_ENH_SIZE_MULT[2],ExtCSDReg->MAX_ENH_SIZE_MULT[1],ExtCSDReg->MAX_ENH_SIZE_MULT[0]));
+ DEBUG((EFI_D_INFO," PART_ATTRIBUTE = 0x%X\n",ExtCSDReg->PARTITIONS_ATTRIBUTES));
+ DEBUG((EFI_D_INFO," PART_SETTING_COMP = 0x%X\n",ExtCSDReg->PARTITION_SETTING_COMPLETED));
+ DEBUG((EFI_D_INFO," GP_SIZE_MULT = 0x%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",ExtCSDReg->GP_SIZE_MULT_4[2],ExtCSDReg->GP_SIZE_MULT_4[1],ExtCSDReg->GP_SIZE_MULT_4[0],
+ ExtCSDReg->GP_SIZE_MULT_3[2],ExtCSDReg->GP_SIZE_MULT_3[1],ExtCSDReg->GP_SIZE_MULT_3[0],
+ ExtCSDReg->GP_SIZE_MULT_2[2],ExtCSDReg->GP_SIZE_MULT_2[1],ExtCSDReg->GP_SIZE_MULT_2[0],
+ ExtCSDReg->GP_SIZE_MULT_1[2],ExtCSDReg->GP_SIZE_MULT_1[1],ExtCSDReg->GP_SIZE_MULT_1[0]));
+ DEBUG((EFI_D_INFO," ENH_SIZE_MULT = 0x%02X%02X%02X\n",ExtCSDReg->ENH_SIZE_MULT[2],ExtCSDReg->ENH_SIZE_MULT[1],ExtCSDReg->ENH_SIZE_MULT[0]));
+ DEBUG((EFI_D_INFO," ENH_START_ADDR = 0x%02X%02X%02X%02X\n",ExtCSDReg->ENH_START_ADDR[3],ExtCSDReg->ENH_START_ADDR[2],ExtCSDReg->ENH_START_ADDR[1],ExtCSDReg->ENH_START_ADDR[0]));
+ DEBUG((EFI_D_INFO," SEC_BAD_BLK_MGMNT = 0x%X\n",ExtCSDReg->SEC_BAD_BLOCK_MGMNT));
+ DEBUG((EFI_D_INFO, "==================================================\n"));
+ return 0;
+}
+
+/**
+ Send the card FAST_IO command.
+
+ @param[in] CardData Pointer to CARD_DATA
+ @param[in] RegisterAddress Register Address
+ @param[in, out] RegisterData Pointer to register Data
+ @param[in] Write TRUE for write, FALSE for read
+
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_UNSUPPORTED
+ @retval EFI_DEVICE_ERROR
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+FastIO (
+ IN CARD_DATA *CardData,
+ IN UINT8 RegisterAddress,
+ IN OUT UINT8 *RegisterData,
+ IN BOOLEAN Write
+ )
+{
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo;
+ EFI_STATUS Status;
+ UINT32 Argument;
+ UINT32 Data;
+
+ Status = EFI_SUCCESS;
+ SdHostIo = CardData->SdHostIo;
+
+ if (RegisterData == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Argument = (CardData->Address << 16) | (RegisterAddress << 8);
+ if (Write) {
+ Argument |= BIT15 | (*RegisterData);
+ }
+
+ Status = SendCommand (
+ SdHostIo,
+ FAST_IO,
+ Argument,
+ NoData,
+ NULL,
+ 0,
+ ResponseR4,
+ TIMEOUT_COMMAND,
+ &Data
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ if ((Data & BIT15) == 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ if (!Write) {
+ *RegisterData = (UINT8)Data;
+ }
+
+Exit:
+ return Status;
+}
+
+/**
+ Send the card GO_INACTIVE_STATE command
+
+ @param[in] CardData Pointer to CARD_DATA
+
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_UNSUPPORTED
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+PutCardInactive (
+ IN CARD_DATA *CardData
+ )
+{
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo;
+ EFI_STATUS Status;
+
+ SdHostIo = CardData->SdHostIo;
+
+ Status = SendCommand (
+ SdHostIo,
+ GO_INACTIVE_STATE,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseNo,
+ TIMEOUT_COMMAND,
+ NULL
+ );
+
+ STALL(1000);
+ return Status;
+}
+
+/**
+ Get card interested information for CSD rergister.
+
+ @param[in] CardData Pointer to CARD_DATA
+
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_UNSUPPORTED
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+CalculateCardParameter (
+ IN CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Frequency;
+ UINT32 Multiple;
+ UINT32 CSize;
+ CSD_SDV2 *CsdSDV2;
+
+ Status = EFI_SUCCESS;
+
+ switch (CardData->CSDRegister.TRAN_SPEED & 0x7) {
+ case 0:
+ Frequency = 100 * 1000;
+ break;
+
+ case 1:
+ Frequency = 1 * 1000 * 1000;
+ break;
+
+ case 2:
+ Frequency = 10 * 1000 * 1000;
+ break;
+
+ case 3:
+ Frequency = 100 * 1000 * 1000;
+ break;
+
+ default:
+ DEBUG((EFI_D_ERROR, "Invalid CSD TRAN_SPEED Frequency: 0x%x\n", CardData->CSDRegister.TRAN_SPEED & 0x7));
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ switch ((CardData->CSDRegister.TRAN_SPEED >> 3) & 0xF) {
+ case 1:
+ Multiple = 10;
+ break;
+
+ case 2:
+ Multiple = 12;
+ break;
+
+ case 3:
+ Multiple = 13;
+ break;
+
+ case 4:
+ Multiple = 15;
+ break;
+
+ case 5:
+ Multiple = 20;
+ break;
+
+ case 6:
+ if (CardData->CardType == MMCCard) {
+ Multiple = 26;
+ } else {
+ Multiple = 25;
+ }
+ break;
+
+ case 7:
+ Multiple = 30;
+ break;
+
+ case 8:
+ Multiple = 35;
+ break;
+
+ case 9:
+ Multiple = 40;
+ break;
+
+ case 10:
+ Multiple = 45;
+ break;
+
+ case 11:
+ if (CardData->CardType == MMCCard) {
+ Multiple = 52;
+ } else {
+ Multiple = 50;
+ }
+ break;
+
+ case 12:
+ Multiple = 55;
+ break;
+
+ case 13:
+ Multiple = 60;
+ break;
+
+ case 14:
+ Multiple = 70;
+ break;
+
+ case 15:
+ Multiple = 80;
+ break;
+
+ default:
+ DEBUG((EFI_D_ERROR, "CalculateCardParameter: Invalid CSD TRAN_SPEED Multiple: 0x%x\n", CardData->CSDRegister.TRAN_SPEED >> 3));
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Frequency = Frequency * Multiple / 10;
+ CardData->MaxFrequency = Frequency;
+
+ if ((CardData->ExtCSDRegister.CARD_TYPE & BIT2) ||
+ (CardData->ExtCSDRegister.CARD_TYPE & BIT3)) {
+ CardData->BlockLen = 512;
+ } else {
+ CardData->BlockLen = 1 << CardData->CSDRegister.READ_BL_LEN;
+ }
+
+ if (CardData->CardType == SDMemoryCard2High) {
+ ASSERT(CardData->CSDRegister.CSD_STRUCTURE == 1);
+ CsdSDV2 = (CSD_SDV2*)&CardData->CSDRegister;
+ //
+ // The SD Spec 2.0 says (CSize + 1) * 512K is the total size, so block numbber is (CSize + 1) * 1K
+ // the K here means 1024 not 1000
+ //
+ CardData->BlockNumber = DivU64x32 (MultU64x32 (CsdSDV2->C_SIZE + 1, 512 * 1024) , CardData->BlockLen);
+ } else {
+ //
+ // For MMC card > 2G, the block number will be recaculate later
+ //
+ CSize = CardData->CSDRegister.C_SIZELow2 | (CardData->CSDRegister.C_SIZEHigh10 << 2);
+ CardData->BlockNumber = MultU64x32 (LShiftU64 (1, CardData->CSDRegister.C_SIZE_MULT + 2), CSize + 1);
+ }
+
+ //
+ //For >= 2G card, BlockLen may be 1024, but the transfer size is still 512 bytes
+ //
+ if (CardData->BlockLen > 512) {
+ CardData->BlockNumber = DivU64x32 (MultU64x32 (CardData->BlockNumber, CardData->BlockLen), 512);
+ CardData->BlockLen = 512;
+ }
+
+ DEBUG((
+ EFI_D_ERROR,
+ "CalculateCardParameter: Card Size: 0x%lx\n", MultU64x32 (CardData->BlockNumber, CardData->BlockLen)
+ ));
+
+Exit:
+ return Status;
+}
+
+/**
+ Test the bus width setting for MMC card
+ It is used only for verification purpose.
+
+ @param[in] CardData Pointer to CARD_DATA
+ @param[in] Width 1, 4, 8 bits
+
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_UNSUPPORTED
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+MMCCardBusWidthTest (
+ IN CARD_DATA *CardData,
+ IN UINT32 Width
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo;
+ UINT64 Data;
+ UINT64 Value;
+
+ ASSERT(CardData != NULL);
+
+ SdHostIo = CardData->SdHostIo;
+
+ Value = 0;
+
+ switch (Width) {
+ case 1:
+ Data = 0x80;
+ break;
+
+ case 4:
+ Data = 0x5A;
+ break;
+
+ case 8:
+ Data = 0xAA55;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ CopyMem (CardData->AlignedBuffer, &Data, Width);
+ Status = SendCommand (
+ SdHostIo,
+ BUSTEST_W,
+ 0,
+ OutData,
+ CardData->AlignedBuffer,
+ Width,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Data = 0;
+ STALL(10000);
+
+ Status = SendCommand (
+ SdHostIo,
+ BUSTEST_R,
+ 0,
+ InData,
+ CardData->AlignedBuffer,
+ Width,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ CopyMem (&Data, CardData->AlignedBuffer, Width);
+
+ switch (Width) {
+ case 1:
+ Value = (~(Data ^ 0x80)) & 0xC0;
+ break;
+ case 4:
+ Value = (~(Data ^ 0x5A)) & 0xFF;
+ break;
+ case 8:
+ Value = (~(Data ^ 0xAA55)) & 0xFFFF;
+ break;
+ }
+
+ if (Value == 0) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+
+Exit:
+ return Status;
+}
+
+/**
+ This function can detect these card types
+ 1. MMC card
+ 2. SD 1.1 card
+ 3. SD 2.0 standard card
+ 3. SD 2.0 high capacity card
+
+ @param[in] CardData Pointer to CARD_DATA
+
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_UNSUPPORTED
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+GetCardType (
+ IN CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo;
+#if 1
+ UINT32 Argument;
+ UINT32 ResponseData;
+ UINT32 Count;
+ BOOLEAN SDCommand8Support = FALSE;
+#else
+#endif
+ UINT32 TimeOut=5000;
+
+ SdHostIo = CardData->SdHostIo;
+#if 0
+ CardData->CardType = MMCCard;
+ SdHostIo->SetupDevice (SdHostIo);
+#endif
+
+ //
+ // To bring back the normal MMC card to work
+ // after sending the SD command. Otherwise some
+ // card could not work
+
+ Status = SendCommand (
+ SdHostIo,
+ GO_IDLE_STATE,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseNo,
+ TIMEOUT_COMMAND,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));
+ }
+#if 1
+ //
+ //No spec requirment, can be adjusted
+ //
+ gBS->Stall (10 * 1000);
+
+
+ //
+ // Only 2.7V - 3.6V is supported for SD2.0, only SD 2.0 card can pass
+ // MMC and SD1.1 card will fail this command
+ //
+ Argument = (VOLTAGE_27_36 << 8) | CHECK_PATTERN;
+ ResponseData = 0;
+
+ Status = SendCommand (
+ SdHostIo,
+ SEND_IF_COND,
+ Argument,
+ NoData,
+ NULL,
+ 0,
+ ResponseR7,
+ TIMEOUT_COMMAND,
+ &ResponseData
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->Stall (10 * 1000); // eMMC initalization will fail without this
+ DEBUG((EFI_D_ERROR, "SEND_IF_COND -> %r\n", Status));
+ if (Status != EFI_TIMEOUT) {
+ goto Exit;
+ }
+ } else {
+ if (ResponseData != Argument) {
+ DEBUG((EFI_D_ERROR, "SEND_IF_COND Fail, respond data does not match send data\n"));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ SDCommand8Support = TRUE;
+ }
+
+
+ Argument = 0;
+ if (SdHostIo->HostCapability.V30Support == TRUE) {
+ Argument |= BIT17 | BIT18;
+ } else if (SdHostIo->HostCapability.V33Support == TRUE) {
+ Argument |= BIT20 | BIT21;
+ }
+
+ if (SDCommand8Support) {
+ //
+ //If command SD_SEND_OP_COND sucessed, it should be set.
+ // SD 1.1 card will ignore it
+ // SD 2.0 standard card will repsond with CCS 0, SD high capacity card will respond with CCS 1
+ // CCS is BIT30 of OCR
+ Argument |= BIT30;
+ }
+
+ Count = 100;
+ //
+ //Only SD card will respond to this command, and spec says the card only checks condition at first ACMD41 command
+ //
+ do {
+ DEBUG ((EFI_D_ERROR, "Argument = %8x.\n", Argument));
+ Status = SendAppCommand (
+ CardData,
+ SD_SEND_OP_COND,
+ Argument,
+ NoData,
+ NULL,
+ 0,
+ ResponseR3,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->OCRRegister)
+ );
+ if (EFI_ERROR (Status)) {
+ if ((Status == EFI_TIMEOUT) && (!SDCommand8Support)) {
+ DEBUG((EFI_D_ERROR, "Card Type: MMC\n"));
+ CardData->CardType = MMCCard;
+ Status = EFI_SUCCESS;
+ break;
+ } else {
+ //
+ // Not as expected, MMC card should has no response, which means timeout.
+ // SD card should pass this command
+ //
+ DEBUG((EFI_D_ERROR, "SD_SEND_OP_COND Fail, check whether it is neither a MMC card nor a SD card\n"));
+ }
+ goto Exit;
+ }
+
+ gBS->Stall (50 * 1000);
+ Count--;
+ if (Count == 0) {
+ DEBUG((EFI_D_ERROR, "Card is always in busy state\n"));
+ Status = EFI_TIMEOUT;
+ goto Exit;
+ }
+ } while (CardData->OCRRegister.Busy != 1);
+
+ if (CardData->CardType == MMCCard) {
+ CardData->CardType = MMCCard;
+ SdHostIo->SetupDevice (SdHostIo);
+
+ //
+ // To bring back the normal MMC card to work
+ // after sending the SD command. Otherwise some
+ // card could not work
+
+ Status = SendCommand (
+ SdHostIo,
+ GO_IDLE_STATE,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseNo,
+ TIMEOUT_COMMAND,
+ NULL
+ );
+
+#endif
+#if SVP_PF_ENABLE
+ DEBUG ((EFI_D_ERROR | EFI_D_INFO, "Sending first CMD1 for AlPM .\n"));
+ //
+ //CE-ATA device needs long delay
+ //
+ STALL ( 3000 * 1000);
+
+ //
+ //Get OCR register to check voltage support, first time the OCR is 0
+ //
+ Status = SendCommand (
+ SdHostIo,
+ SEND_OP_COND,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseR3,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->OCRRegister)
+ );
+#elif TABLET_PF_ENABLE
+ DEBUG ((EFI_D_ERROR | EFI_D_INFO, "Sending first CMD1 for BLAK .\n"));
+ //
+ //CE-ATA device needs long delay
+ //
+ STALL ( 1 * 1000);
+
+ //
+ //Get OCR register to check voltage support, first time the OCR is 0
+ //
+
+ DEBUG ((EFI_D_ERROR | EFI_D_INFO, "Sending first CMD1 with 0x40FF8080 .\n"));
+
+ Status = SendCommand (
+ SdHostIo,
+ SEND_OP_COND,
+ 0x40FF8080,
+ NoData,
+ NULL,
+ 0,
+ ResponseR3,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->OCRRegister)
+ );
+
+#endif
+
+ DEBUG((EFI_D_ERROR, "Check OCR register for busy 0x%x\n",*((UINT32*)&CardData->OCRRegister )));
+
+ STALL (1 * 1000);
+
+ while (CardData->OCRRegister.Busy != 1) {
+ CardData->OCRRegister.AccessMode = 2;
+ Status = SendCommand (
+ SdHostIo,
+ SEND_OP_COND,
+ *(UINT32*)&(CardData->OCRRegister),
+ NoData,
+ NULL,
+ 0,
+ ResponseR3,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->OCRRegister)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
+ goto Exit;
+ }
+
+ STALL (1 * 1000);
+ TimeOut--;
+ if (TimeOut == 0) {
+ DEBUG((EFI_D_ERROR, "Card is always in busy state\n"));
+ Status = EFI_TIMEOUT;
+ goto Exit;
+ }
+}
+#if 1
+ }
+ if (CardData->CardType != MMCCard) {
+ //
+ //Check supported voltage
+ //
+ Argument = 0;
+ if (SdHostIo->HostCapability.V30Support == TRUE) {
+ if ((CardData->OCRRegister.V270_V360 & BIT2) == BIT2) {
+ Argument |= BIT17;
+ } else if ((CardData->OCRRegister.V270_V360 & BIT3) == BIT3) {
+ Argument |= BIT18;
+ }
+ } else if (SdHostIo->HostCapability.V33Support == TRUE) {
+ if ((CardData->OCRRegister.V270_V360 & BIT5) == BIT5) {
+ Argument |= BIT20;
+ } else if ((CardData->OCRRegister.V270_V360 & BIT6) == BIT6) {
+ Argument |= BIT21;
+ }
+ }
+
+ if (Argument == 0) {
+ //
+ //No matched support voltage
+ //
+ PutCardInactive (CardData);
+ DEBUG((EFI_D_ERROR, "No matched voltage for this card\n"));
+ Status = EFI_UNSUPPORTED;
+ goto Exit;
+ }
+
+ CardData->CardType = SDMemoryCard;
+ if (SDCommand8Support == TRUE) {
+ CardData->CardType = SDMemoryCard2;
+ }
+
+ if ((CardData->OCRRegister.AccessMode & BIT1) == BIT1) {
+ CardData->CardType = SDMemoryCard2High;
+ }
+ }
+#endif
+
+Exit:
+ return Status;
+}
+
+/**
+ MMC card high/low voltage selection function.
+
+ @param[in] CardData Pointer to CARD_DATA
+
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_SUCCESS
+ @retval EFI_UNSUPPORTED
+ @retval EFI_BAD_BUFFER_SIZE
+
+**/
+EFI_STATUS
+MMCCardVoltageSelection (
+ IN CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo;
+ UINT8 Index;
+ UINT8 Retry;
+ UINT32 TimeOut;
+
+ SdHostIo = CardData->SdHostIo;
+ Status = EFI_SUCCESS;
+
+#if 1
+ if (CardData->CardType != MMCCard) {
+#else
+ if (FALSE) {
+#endif
+ //
+ //First try the high voltage, then if supported choose the low voltage
+ //
+ for (Index = 0; Index < 2; Index++) {
+
+ for (Retry = 0; Retry < 3; Retry++) {
+ //
+ // To bring back the normal MMC card to work
+ // after sending the SD command. Otherwise some
+ // card could not work
+
+ Status = SendCommand (
+ SdHostIo,
+ GO_IDLE_STATE,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseNo,
+ TIMEOUT_COMMAND,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));
+ continue;
+ }
+ //
+ //CE-ATA device needs long delay
+ //
+ STALL ((Retry + 1) * 50 * 1000);
+
+ //
+ //Get OCR register to check voltage support, first time the OCR is 0
+ //
+ Status = SendCommand (
+ SdHostIo,
+ SEND_OP_COND,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseR3,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->OCRRegister)
+ );
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ if (Retry == 3) {
+ DEBUG((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ if (CardData->OCRRegister.V170_V195 == 1) {
+ CardData->DualVoltage = TRUE;
+ }
+ if (CardData->OCRRegister.V270_V360 != 0x1F &&
+ CardData->OCRRegister.V200_V260 != 0) {
+ DEBUG((EFI_D_ERROR, "Incompatiable voltage device\n"));
+ PutCardInactive (CardData);
+ Status = EFI_INCOMPATIBLE_VERSION;
+ goto Exit;
+ }
+
+ if (Index == 0) {
+ //
+ //Choose the high voltage first
+ //
+ CardData->OCRRegister.V170_V195 = 0;
+ } else {
+ //
+ //Choose the low voltage
+ //
+ CardData->OCRRegister.V170_V195 = 1;
+ CardData->OCRRegister.V270_V360 = 0;
+ }
+
+ //
+ // Set sector mode
+ //
+ CardData->OCRRegister.AccessMode |= 2;
+
+ //
+ //TimeOut Value, 5000 * 100 * 1000 = 5 s
+ //
+ TimeOut = 5000;
+
+ do {
+ Status = SendCommand (
+ SdHostIo,
+ SEND_OP_COND,
+ *(UINT32*)&(CardData->OCRRegister),
+ NoData,
+ NULL,
+ 0,
+ ResponseR3,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->OCRRegister)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
+ goto Exit;
+ }
+
+ STALL (1 * 1000);
+ TimeOut--;
+ if (TimeOut == 0) {
+ DEBUG((EFI_D_ERROR, "Card is always in busy state\n"));
+ Status = EFI_TIMEOUT;
+ goto Exit;
+ }
+ } while (CardData->OCRRegister.Busy != 1);
+
+ if (CardData->DualVoltage == TRUE && SdHostIo->HostCapability.V18Support == TRUE) {
+ //
+ //Power Off the card and then power on into low voltage
+ //
+ SdHostIo->SetHostVoltage (SdHostIo, 0);
+ STALL (1 * 1000);
+ SdHostIo->SetHostVoltage (SdHostIo, 18);
+ } else {
+ //
+ //Not support the low voltage, exit
+ //
+ break;
+ }
+ }
+ }
+
+Exit:
+ return Status;
+
+}
+
+/**
+ This function set the bus and device width for MMC card.
+
+ @param[in] CardData Pointer to CARD_DATA
+ @param[in] BusWidth 1, 4, 8 bits
+
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_UNSUPPORTED
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+MMCCardSetBusWidth (
+ IN CARD_DATA *CardData,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo;
+ SWITCH_ARGUMENT SwitchArgument;
+ UINT8 Value;
+
+ SdHostIo = CardData->SdHostIo;
+ Value = 0;
+ switch (BusWidth) {
+ case 28: //20 in 28 indicates DDR in 8 bit bus
+ Value = 6;
+ break;
+
+ case 24: //20 in 24 indicates DDR in 4 bit bus
+ Value = 5;
+ break;
+
+ case 8:
+ Value = 2;
+ break;
+
+ case 4:
+ Value = 1;
+ break;
+
+ case 1:
+ Value = 0;
+ break;
+
+ default:
+ ASSERT(0);
+ }
+
+ ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+ SwitchArgument.CmdSet = 0;
+ SwitchArgument.Value = Value;
+ SwitchArgument.Index = (UINT32)((UINTN)
+ (&(CardData->ExtCSDRegister.BUS_WIDTH)) - (UINTN)(&(CardData->ExtCSDRegister)));
+ SwitchArgument.Access = WriteByte_Mode;
+ Status = SendCommand (
+ SdHostIo,
+ SWITCH,
+ *(UINT32*)&SwitchArgument,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1b,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = SendCommand (
+ SdHostIo,
+ SEND_STATUS,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SWITCH %d bits Fail\n", BusWidth));
+ goto Exit;
+ } else {
+ if ((BusWidth == 24) || (BusWidth == 28)) {
+ Status = SdHostIo->SetBusWidth (SdHostIo, BusWidth - 20);
+ } else {
+ Status = SdHostIo->SetBusWidth (SdHostIo, BusWidth);
+ }
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ STALL (5 * 1000);
+ }
+ }
+ if ((BusWidth == 24) || (BusWidth == 28)) {
+ goto Exit;
+ } else {
+ Status = MMCCardBusWidthTest (CardData, BusWidth);
+ }
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest %d bit Fail\n", BusWidth));
+ goto Exit;
+ }
+
+ CardData->CurrentBusWidth = BusWidth;
+
+Exit:
+ return Status;
+}
+
+/**
+ MMC/SD card init function.
+
+ @param[in] CardData Pointer to CARD_DATA
+
+ @retval EFI_INVALID_PARAMETER
+ @retval EFI_SUCCESS
+ @retval EFI_UNSUPPORTED
+ @retval EFI_BAD_BUFFER_SIZE
+
+**/
+EFI_STATUS
+MMCSDCardInit (
+ IN CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo;
+ SWITCH_ARGUMENT SwitchArgument;
+ UINT32 Data;
+ UINT32 Argument;
+ UINT8 PowerValue;
+ UINT8 DoubleSpeed;
+
+ ASSERT(CardData != NULL);
+ SdHostIo = CardData->SdHostIo;
+ CardData->CurrentBusWidth = 1;
+
+ Status = GetCardType (CardData);
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "GetCardType -> %r\n", Status));
+ goto Exit;
+ }
+
+ ASSERT (CardData->CardType != UnknownCard);
+ //
+ //MMC, SD card need host auto stop command support
+ //
+ SdHostIo->EnableAutoStopCmd (SdHostIo, TRUE);
+
+#if 1
+ if (CardData->CardType == MMCCard) {
+ Status = MMCCardVoltageSelection (CardData);
+ if (EFI_ERROR(Status)) {
+ DEBUG((EFI_D_ERROR, "MMCCardVoltageSelection -> %r\n", Status));
+ goto Exit;
+ }
+ }
+#endif
+
+ //
+ // Get CID Register, but the info is not used currently
+ //
+ Status = SendCommand (
+ SdHostIo,
+ ALL_SEND_CID,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseR2,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CIDRegister)
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "ALL_SEND_CID -> %r\n", Status));
+ goto Exit;
+ }
+
+ //
+ //SET_RELATIVE_ADDR
+ //
+ if (CardData->CardType == MMCCard) {
+ CardData->Address = 1;
+
+ //
+ // Set RCA Register
+ //
+ Status = SendCommand (
+ SdHostIo,
+ SET_RELATIVE_ADDR,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR -> %r\n", Status));
+ goto Exit;
+ }
+#if 1
+ } else {
+ Data = 0;
+ Status = SendCommand (
+ SdHostIo,
+ SET_RELATIVE_ADDR,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseR6,
+ TIMEOUT_COMMAND,
+ &Data
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR -> %r\n", Status));
+ goto Exit;
+ }
+
+ CardData->Address = (UINT16)(Data >> 16);
+ *(UINT32*)&CardData->CardStatus = Data & 0x1FFF;
+ CardData->CardStatus.ERROR = (Data >> 13) & 0x1;
+ CardData->CardStatus.ILLEGAL_COMMAND = (Data >> 14) & 0x1;
+ CardData->CardStatus.COM_CRC_ERROR = (Data >> 15) & 0x1;
+ Status = CheckCardStatus (*(UINT32*)&CardData->CardStatus);
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR -> %r\n", Status));
+ goto Exit;
+ }
+#endif
+ }
+
+ //
+ // Get CSD Register
+ //
+ Status = SendCommand (
+ SdHostIo,
+ SEND_CSD,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR2,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CSDRegister)
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SEND_CSD -> %r\n", Status));
+ goto Exit;
+ }
+
+ MmcDecodeCSD (&CardData->CSDRegister);
+
+ Status = CalculateCardParameter (CardData);
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "CalculateCardParameter -> %r\n", Status));
+ goto Exit;
+ }
+
+#if 1
+ //
+ // It is platform and hardware specific, need hadrware engineer input
+ //
+ if (CardData->CSDRegister.DSR_IMP == 1) {
+ //
+ // Default is 0x404
+ //
+ Status = SendCommand (
+ SdHostIo,
+ SET_DSR,
+ (DEFAULT_DSR_VALUE << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseNo,
+ TIMEOUT_COMMAND,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SET_DSR -> %r\n", Status));
+ //
+ // Assume can operate even fail
+ //
+ }
+ }
+
+ //
+ //Change clock frequency from 400KHz to max supported
+ //
+ Status = SdHostIo->SetClockFrequency (SdHostIo, CardData->MaxFrequency);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SetClockFrequency -> %r\n", Status));
+ goto Exit;
+ }
+#endif
+
+ //
+ //Put the card into tran state
+ //
+ Status = SendCommand (
+ SdHostIo,
+ SELECT_DESELECT_CARD,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SELECT_DESELECT_CARD -> %r\n", Status));
+ goto Exit;
+ }
+
+ Status = SendCommand (
+ SdHostIo,
+ SEND_STATUS,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SELECT_DESELECT_CARD SEND_STATUS Fail Status = 0x%x\n", Status));
+ goto Exit;
+ }
+
+ if (CardData->CardType == MMCCard) {
+ //
+ //Only V4.0 and above supports more than 1 bits and high speed
+ //
+ if (CardData->CSDRegister.SPEC_VERS >= 4) {
+ //
+ //Get ExtCSDRegister
+ //
+ Status = SendCommand (
+ SdHostIo,
+ SEND_EXT_CSD,
+ 0, // stuff bits are 0
+ InData,
+ CardData->AlignedBuffer,
+ sizeof (EXT_CSD),
+ ResponseR1,
+ TIMEOUT_DATA,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SEND_EXT_CSD -> %r\n", Status));
+ goto Exit;
+ }
+
+ CopyMem (&(CardData->ExtCSDRegister), CardData->AlignedBuffer, sizeof (EXT_CSD));
+ MmcDecodeExtCSD(&CardData->ExtCSDRegister);
+
+ //
+ // Recaculate the block number for >2G MMC card
+ //
+ Data = (CardData->ExtCSDRegister.SEC_COUNT[0]) |
+ (CardData->ExtCSDRegister.SEC_COUNT[1] << 8) |
+ (CardData->ExtCSDRegister.SEC_COUNT[2] << 16) |
+ (CardData->ExtCSDRegister.SEC_COUNT[3] << 24);
+
+ if (Data != 0) {
+ CardData->BlockNumber = Data;
+ }
+ DEBUG((DEBUG_INFO, "CardData->BlockNumber %d\n", Data));
+
+ //
+ // Check the DDR setting
+ //
+ DoubleSpeed = 0 ;
+ DEBUG((EFI_D_ERROR, "CardData->ExtCSDRegister.CARD_TYPE -> %d\n", (UINTN)CardData->ExtCSDRegister.CARD_TYPE));
+ if ((CardData->ExtCSDRegister.CARD_TYPE & BIT2)||
+ (CardData->ExtCSDRegister.CARD_TYPE & BIT3)) {
+ DEBUG((DEBUG_INFO, "Card support DDR\n"));
+ DoubleSpeed = 20; //Add 20 for double speed, decoded in MMCCardSetBusWidth()
+ }
+
+ if (SdHostIo->HostCapability.HighSpeedSupport) {
+
+ //
+ //Change to high frequency mode
+ //
+ ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+ SwitchArgument.CmdSet = 0;
+ SwitchArgument.Value = 1;
+ SwitchArgument.Index = (UINT32)((UINTN)
+ (&(CardData->ExtCSDRegister.HS_TIMING)) - (UINTN)(&(CardData->ExtCSDRegister)));
+ SwitchArgument.Access = WriteByte_Mode;
+ Status = SendCommand (
+ CardData->SdHostIo,
+ SWITCH,
+ *(UINT32*)&SwitchArgument,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1b,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SWITCH frequency -> %r\n", Status));
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Status = SendCommand (
+ SdHostIo,
+ SEND_STATUS,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Enable the high speed mode
+ //
+
+ if (DoubleSpeed != 0) {
+ DEBUG((EFI_D_ERROR, "Set to DDR50 mode \n", Status));
+ Status = SdHostIo->SetHostDdrMode(SdHostIo, TRUE);
+ } else {
+ DEBUG((EFI_D_ERROR, "Set to HS mode \n", Status));
+ SdHostIo->SetHostSpeedMode (SdHostIo, 1);
+ }
+ //
+ //Change host clock
+ //
+ if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+ Status = SdHostIo->SetClockFrequency (SdHostIo, FREQUENCY_MMC_PP_HIGH);
+ } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+ Status = SdHostIo->SetClockFrequency (SdHostIo, FREQUENCY_MMC_PP);
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // It seems no need to stall after changing bus freqeuncy.
+ // It is said that the freqeuncy can be changed at any time. Just appends 8 clocks after command.
+ // But SetClock alreay has delay.
+ //
+ }
+ }
+ }
+
+ //
+ // Prefer wide bus width for performance
+ //
+ //
+ // Set to BusWidth bits mode, only version 4.0 or above support more than 1 bits
+ //
+ if (SdHostIo->HostCapability.BusWidth8 == 1) {
+ Status = MMCCardSetBusWidth (CardData, DoubleSpeed + 8);
+ if (EFI_ERROR (Status)) {
+ //
+ // CE-ATA may support 8 bits and 4 bits, but has no software method for detection
+ //
+ Status = MMCCardSetBusWidth (CardData, DoubleSpeed + 4);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ }
+ } else if (SdHostIo->HostCapability.BusWidth4 == 1) {
+ Status = MMCCardSetBusWidth (CardData, DoubleSpeed + 4);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ }
+
+ PowerValue = 0;
+
+ if (CardData->CurrentBusWidth == 8) {
+ if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+ PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;
+ PowerValue = PowerValue >> 4;
+ } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+ PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;
+ PowerValue = PowerValue >> 4;
+ }
+ } else if (CardData->CurrentBusWidth == 4) {
+ if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+ PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;
+ PowerValue = PowerValue & 0xF;
+ } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+ PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;
+ PowerValue = PowerValue & 0xF;
+ }
+ }
+
+ if (PowerValue != 0) {
+ //
+ //Update Power Class
+ //
+ ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+ SwitchArgument.CmdSet = 0;
+ SwitchArgument.Value = PowerValue;
+ SwitchArgument.Index = (UINT32)((UINTN)
+ (&(CardData->ExtCSDRegister.POWER_CLASS)) - (UINTN)(&(CardData->ExtCSDRegister)));
+ SwitchArgument.Access = WriteByte_Mode;
+ Status = SendCommand (
+ SdHostIo,
+ SWITCH,
+ *(UINT32*)&SwitchArgument,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1b,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = SendCommand (
+ SdHostIo,
+ SEND_STATUS,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SWITCH Power Class -> %r\n", Status));
+ }
+ //STALL (10 * 1000);
+ }
+ }
+ } else {
+ DEBUG((EFI_D_ERROR, "MMC Card version %d only supportes 1 bits at lower transfer speed\n",CardData->CSDRegister.SPEC_VERS));
+ }
+
+ } else {
+ //
+ // Pin 1, at power up this line has a 50KOhm pull up enabled in the card.
+ // This pull-up should be disconnected by the user, during regular data transfer,
+ // with SET_CLR_CARD_DETECT (ACMD42) command
+ //
+ Status = SendAppCommand (
+ CardData,
+ SET_CLR_CARD_DETECT,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SET_CLR_CARD_DETECT Fail -> %r\n", Status));
+ goto Exit;
+ }
+
+ //
+ // Set Bus Width to 4
+ //
+ Status = SendAppCommand (
+ CardData,
+ SET_BUS_WIDTH,
+ SD_BUS_WIDTH_4,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SET_BUS_WIDTH 4 bits -> %r\n", Status));
+ goto Exit;
+ }
+
+ Status = SdHostIo->SetBusWidth (SdHostIo, 4);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ CardData->CurrentBusWidth = 4;
+
+ if ((SdHostIo->HostCapability.HighSpeedSupport == FALSE) ||
+ ((CardData->CSDRegister.CCC & BIT10) != BIT10)) {
+ //
+ // Host must support high speed
+ // Card must support Switch function
+ //
+ goto Exit;
+ }
+
+ //
+ //Mode = 0, group 1, function 1, check operation
+ //
+ Argument = 0xFFFF01;
+ ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));
+
+ Status = SendCommand (
+ SdHostIo,
+ SWITCH_FUNC,
+ Argument,
+ InData,
+ CardData->AlignedBuffer,
+ sizeof (SWITCH_STATUS),
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));
+
+ if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||
+ ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {
+ //
+ // 1. SD 1.1 card does not suppport busy bit
+ // 2. Ready state
+ //
+ //
+
+ //
+ //Mode = 1, group 1, function 1, BIT31 set means set mode
+ //
+ Argument = 0xFFFF01 | BIT31;
+ ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));
+
+ Status = SendCommand (
+ SdHostIo,
+ SWITCH_FUNC,
+ Argument,
+ InData,
+ CardData->AlignedBuffer,
+ sizeof (SWITCH_STATUS),
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));
+
+ if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||
+ ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {
+ //
+ // 1. SD 1.1 card does not suppport busy bit
+ // 2. Ready state
+ //
+
+ //
+ // 8 clocks, (1/ 25M) * 8 ==> 320 us, so 1ms > 0.32 ms
+ //
+ STALL (1000);
+
+ }
+ }
+ }
+ if (!((CardData->ExtCSDRegister.CARD_TYPE & BIT2) ||
+ (CardData->ExtCSDRegister.CARD_TYPE & BIT3))) {
+ //
+ // Set Block Length, to improve compatibility in case of some cards
+ //
+ Status = SendCommand (
+ SdHostIo,
+ SET_BLOCKLEN,
+ 512,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SET_BLOCKLEN -> %r\n", Status));
+ goto Exit;
+ }
+ }
+ SdHostIo->SetBlockLength (SdHostIo, 512);
+
+Exit:
+ if (Status) {
+ }
+ return Status;
+}
+
+EFI_STATUS
+MmcSelect (
+ IN CARD_DATA *CardData,
+ IN BOOLEAN Select
+ )
+{
+ return SendCommand (
+ CardData->SdHostIo,
+ SELECT_DESELECT_CARD,
+ Select ? (CardData->Address << 16) : ~(CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+}
+
+EFI_STATUS
+MmcSendSwitch (
+ IN CARD_DATA *CardData,
+ IN SWITCH_ARGUMENT *SwitchArgument
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo;
+
+ SdHostIo = CardData->SdHostIo;
+
+ Status = SendCommand (
+ SdHostIo,
+ SWITCH,
+ *(UINT32*)SwitchArgument,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1b,
+ TIMEOUT_DATA,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = SendCommand (
+ SdHostIo,
+ SEND_STATUS,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "SWITCH FAILURE\n"));
+ }
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+MmcUpdateCardStatus (
+ IN CARD_DATA *CardData
+ )
+{
+ return SendCommand (
+ CardData->SdHostIo,
+ SEND_STATUS,
+ (CardData->Address << 16),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+}
+
+EFI_STATUS
+MmcMoveToTranState (
+ IN CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ if (CardData->CardStatus.CURRENT_STATE != Tran_STATE) {
+ //
+ // Put the card into tran state
+ //
+ Status = MmcSelect (CardData, TRUE);
+ DEBUG((EFI_D_INFO, "MmcMoveToTranState: CMD7 -> %r\n", Status));
+ MmcUpdateCardStatus (CardData);
+ }
+
+ if (CardData->CardStatus.CURRENT_STATE != Tran_STATE) {
+ DEBUG((EFI_D_ERROR, "MmcMoveToTranState: Unable to put card into tran state\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+MmcReadExtCsd (
+ IN CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MmcMoveToTranState (CardData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SendCommand (
+ CardData->SdHostIo,
+ SEND_EXT_CSD,
+ (CardData->Address << 16),
+ InData,
+ CardData->AlignedBuffer,
+ sizeof (EXT_CSD),
+ ResponseR1,
+ TIMEOUT_DATA,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ DEBUG ((EFI_D_INFO, "MmcReadExtCsd: SEND_EXT_CSD -> %r\n", Status));
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ CopyMem (&(CardData->ExtCSDRegister), CardData->AlignedBuffer, sizeof (EXT_CSD));
+
+ return Status;
+}
+
+EFI_STATUS
+MmcSetExtCsd8 (
+ IN CARD_DATA *CardData,
+ IN UINT8 Index,
+ IN UINT8 Value
+ )
+{
+ EFI_STATUS Status;
+ SWITCH_ARGUMENT SwitchArgument;
+
+ Status = MmcMoveToTranState (CardData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+ SwitchArgument.CmdSet = 0;
+ SwitchArgument.Value = (UINT8) Value;
+ SwitchArgument.Index = (UINT8) Index;
+ SwitchArgument.Access = WriteByte_Mode; // SetBits_Mode;
+ return MmcSendSwitch (CardData, &SwitchArgument);
+}
+
+EFI_STATUS
+MmcSetExtCsd24 (
+ IN CARD_DATA *CardData,
+ IN UINT8 Index,
+ IN UINT32 Value
+ )
+{
+ EFI_STATUS Status = EFI_NOT_FOUND;
+ UINTN Loop;
+
+ ASSERT ((Value & 0xff000000ULL) == 0);
+
+ for (Loop = 0; Loop < 3; Loop++) {
+ Status = MmcSetExtCsd8 (CardData, Index + (UINT8)Loop, Value & 0xff);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Value = Value >> 8;
+ }
+
+ return Status;
+}
+
+UINT32
+MmcGetExtCsd8 (
+ IN CARD_DATA *CardData,
+ IN UINTN Offset
+ )
+{
+ ASSERT (Offset < sizeof (CardData->ExtCSDRegister));
+ return ((UINT8*)&CardData->ExtCSDRegister)[Offset];
+}
+
+UINT32
+MmcGetExtCsd32 (
+ IN CARD_DATA *CardData,
+ IN UINTN Offset
+ )
+{
+ return *(UINT32*) (((UINT8*)&CardData->ExtCSDRegister) + Offset);
+}
+
+UINT32
+MmcGetExtCsd24 (
+ IN CARD_DATA *CardData,
+ IN UINTN Offset
+ )
+{
+ return MmcGetExtCsd32 (CardData, Offset) & 0xffffff;
+}
+
+UINTN
+MmcGetCurrentPartitionNum (
+ IN CARD_DATA *CardData
+ )
+{
+ return MmcGetExtCsd8 (
+ CardData,
+ OFFSET_OF (EXT_CSD, PARTITION_CONFIG)
+ ) & 0x7;
+}
+
+VOID
+SetEmmcWpOnEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN Offset;
+ CARD_DATA *CardData;
+ UINT8 TempData;
+ UINTN WriteProtectAddress;
+ UINTN WriteProtectGroupSize;
+ static BOOLEAN WriteProtectDone = FALSE;
+
+ DEBUG ((EFI_D_INFO, "eMMC Write Protection Config Checkpoint\n"));
+
+ if (0) {
+
+ CardData = (CARD_DATA*)Context;
+
+ if (!WriteProtectDone) {
+ //
+ // Protect GPP and BP
+ // Update Power on write protection bit in USER_WP and BP_WP EXT_CSD registers
+ //
+ Offset = OFFSET_OF (EXT_CSD, ERASE_GROUP_DEF);
+ Status = MmcSetExtCsd8 (CardData, (UINT8)Offset, 0x01);
+ if (Status) {
+ DEBUG ((EFI_D_INFO, "Setting ERASE_GROUP_DEF failed\n"));
+ }
+ Status = MmcReadExtCsd (CardData);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Read EXT_CSD failed\n"));
+ }
+ Offset = OFFSET_OF (EXT_CSD, BOOT_WP);
+ TempData = (CardData->ExtCSDRegister.BOOT_WP) | B_PWR_WP_EN | B_PERM_WP_DIS;
+ Status = MmcSetExtCsd8 (CardData, (UINT8)Offset, TempData);
+ if (Status) {
+ DEBUG ((EFI_D_INFO, "BP Write protect failed\n"));
+ }
+
+ MmcSelectPartitionNum(CardData, 4); //Switch to GPP before issuing CMD28
+ Offset = OFFSET_OF (EXT_CSD, USER_WP);
+ TempData = (CardData->ExtCSDRegister.USER_WP) | US_PWR_WP_EN | US_PERM_WP_DIS;
+ Status = MmcSetExtCsd8 (CardData, (UINT8)Offset, TempData);
+ if (Status) {
+ DEBUG ((EFI_D_INFO, "GPP Write protect failed\n"));
+ }
+ if (CardData->ExtCSDRegister.ERASE_GROUP_DEF) {
+ WriteProtectGroupSize = ((UINTN)(CardData->ExtCSDRegister.HC_WP_GRP_SIZE))
+ * 512 * 1024 * ((UINTN)(CardData->ExtCSDRegister.HC_ERASE_GRP_SIZE));
+ } else {
+ WriteProtectGroupSize = (CardData->CSDRegister.WP_GRP_SIZE + 1)
+ * ((UINTN)CardData->CSDRegister.ERASE_GRP_SIZE + 1)
+ * ((UINTN)CardData->CSDRegister.ERASE_GRP_MULT + 1)
+ * ((UINTN)(CardData->Partitions[4].BlockIoMedia.BlockSize));
+ }
+
+ Status = MmcReadExtCsd (CardData);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Read EXT_CSD failed\n"));
+ }
+ DEBUG ((EFI_D_INFO, "\nWP_GRP_SIZE 0x%02x", (UINT8)CardData->CSDRegister.WP_GRP_SIZE));
+ DEBUG ((EFI_D_INFO, "\nGPP Number of Blocks 0x%x", (UINTN)(((UINTN)CardData->Partitions[4].BlockIoMedia.LastBlock) + 1)));
+ DEBUG ((EFI_D_INFO, "\nGPP BlockSize 0x%x", (UINTN)(CardData->Partitions[4].BlockIoMedia.BlockSize)));
+ DEBUG ((EFI_D_INFO, "\nERASE_GRP_SIZE 0x%02x", (UINT8)(CardData->CSDRegister.ERASE_GRP_SIZE)));
+ DEBUG ((EFI_D_INFO, "\nERASE_GRP_MULT 0x%02x", (UINT8)(CardData->CSDRegister.ERASE_GRP_MULT)));
+ DEBUG ((EFI_D_INFO, "\nHC_WP_GRP_SIZE 0x%02x", (UINT8)(CardData->ExtCSDRegister.HC_WP_GRP_SIZE)));
+ DEBUG ((EFI_D_INFO, "\nHC_ERASE_GRP_SIZE 0x%02x", (UINT8)(CardData->ExtCSDRegister.HC_ERASE_GRP_SIZE)));
+ DEBUG ((EFI_D_INFO, "\nBOOT_WP 0x%02x", (UINT8)(CardData->ExtCSDRegister.BOOT_WP)));
+ DEBUG ((EFI_D_INFO, "\nUSER_WP 0x%02x", (UINT8)(CardData->ExtCSDRegister.USER_WP)));
+ DEBUG((EFI_D_INFO, "\nWriteProtectGroupSize = 0x%x \n", WriteProtectGroupSize));
+
+ for (WriteProtectAddress = 0; WriteProtectAddress < 0x300000; WriteProtectAddress+=WriteProtectGroupSize) {
+ //
+ // Send Write protect command
+ //
+ DEBUG ((EFI_D_INFO, "Send Write protect command Address = 0x%x\n", WriteProtectAddress));
+ Status = SendCommand (
+ CardData->SdHostIo,
+ SET_WRITE_PROT,
+ (UINT32)(WriteProtectAddress / 0x200),
+ NoData,
+ NULL,
+ 0,
+ ResponseR1b,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (Status) {
+ DEBUG ((EFI_D_INFO, "GPP1 Write protect failed\n"));
+ break;
+ }
+ }
+ WriteProtectDone = TRUE;
+ }
+ }
+}
+
+VOID
+SecureErase (
+ CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+ UINT64 SecureEraseTimeout; // Secure erase-Timeout issue
+ static BOOLEAN SecureEraseDone = FALSE;
+
+ DEBUG ((EFI_D_INFO, "eMMC Secure Erase Checkpoint\n"));
+
+ if (!SecureEraseDone) {
+ if (CardData->ExtCSDRegister.SEC_FEATURE_SUPPORT & BIT0) { // BIT0 --> 1 --> Secure Purge operations are supported
+
+ MmcSelectPartitionNum(CardData, 0); // 0 --> User partition
+
+ Status = SendCommand (
+ CardData->SdHostIo,
+ ERASE_GROUP_START,
+ 0,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (Status) {
+ DEBUG ((EFI_D_INFO, "Set ERASE_GROUP_START failed\n"));
+ return;
+ }
+
+ Status = SendCommand (
+ CardData->SdHostIo,
+ ERASE_GROUP_END,
+ (UINT32)CardData->Partitions[0].BlockIoMedia.LastBlock,
+ NoData,
+ NULL,
+ 0,
+ ResponseR1,
+ TIMEOUT_COMMAND,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ if (Status) {
+ DEBUG ((EFI_D_INFO, "Set ERASE_GROUP_END failed\n"));
+ return;
+ }
+
+ if (CardData->ExtCSDRegister.ERASE_GROUP_DEF) {
+ SecureEraseTimeout = CardData->ExtCSDRegister.SEC_ERASE_MULT
+ * CardData->ExtCSDRegister.ERASE_TIMEOUT_MULT
+ * ((UINTN)CardData->Partitions[0].BlockIoMedia.LastBlock + 1)
+ / (1024 * (CardData->ExtCSDRegister.HC_WP_GRP_SIZE) * CardData->ExtCSDRegister.HC_ERASE_GRP_SIZE);
+ } else {
+ SecureEraseTimeout = CardData->ExtCSDRegister.SEC_ERASE_MULT
+ * CardData->ExtCSDRegister.ERASE_TIMEOUT_MULT
+ * ((UINTN)CardData->Partitions[0].BlockIoMedia.LastBlock + 1)
+ / ((CardData->CSDRegister.ERASE_GRP_SIZE + 1) * (CardData->ExtCSDRegister.HC_WP_GRP_SIZE) * (CardData->CSDRegister.ERASE_GRP_MULT));
+ }
+ DEBUG ((EFI_D_INFO, "CardData->ExtCSDRegister.SEC_ERASE_MULT : %x\n", CardData->ExtCSDRegister.SEC_ERASE_MULT));
+ DEBUG ((EFI_D_INFO, "CardData->ExtCSDRegister.ERASE_TIMEOUT_MULT : %x\n", CardData->ExtCSDRegister.ERASE_TIMEOUT_MULT));
+ DEBUG ((EFI_D_INFO, "CardData->ExtCSDRegister.HC_ERASE_GRP_SIZE : %x\n", CardData->ExtCSDRegister.HC_ERASE_GRP_SIZE));
+ DEBUG ((EFI_D_INFO, "CardData->ExtCSDRegister.SEC_ERASE_MULT : %x\n", CardData->ExtCSDRegister.SEC_ERASE_MULT));
+ DEBUG ((EFI_D_INFO, "CardData->ExtCSDRegister.ERASE_TIMEOUT_MULT : %x\n", CardData->ExtCSDRegister.ERASE_TIMEOUT_MULT));
+ DEBUG ((EFI_D_INFO, "SecureEraseTimeout : %lx\n", SecureEraseTimeout));
+ DEBUG ((EFI_D_INFO, "lastblock : %lx\n", ((UINTN)CardData->Partitions[0].BlockIoMedia.LastBlock)));
+
+ Status = SendCommand (
+ CardData->SdHostIo,
+ ERASE,
+ 0x80000000, // Secure Erase bit 31
+ NoData,
+ NULL,
+ 0,
+ ResponseR1b,
+ (UINT32)SecureEraseTimeout,
+ (UINT32*)&(CardData->CardStatus)
+ );
+ do {
+ DEBUG ((EFI_D_INFO, "Secure Erase Wait\n"));
+ gBS->Stall(100); //Timeout needed to avoid further errors during the flow
+ } while (SecureEraseTimeout--);
+
+ MmcUpdateCardStatus (CardData);
+ if (CardData->CardStatus.WP_ERASE_SKIP) {
+ DEBUG ((EFI_D_INFO, "Secure Erase failed due to Write protect\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "Secure Erase SecureEraseDone = TRUE\n"));
+ SecureEraseDone = TRUE;
+ }
+
+ } else {
+ DEBUG ((EFI_D_INFO, "Secure Erase Not supported\n"));
+ }
+ }
+}
+
+EFI_STATUS
+MmcSelectPartitionNum (
+ IN CARD_DATA *CardData,
+ IN UINT8 Partition
+ )
+{
+ EFI_STATUS Status;
+ UINTN Offset;
+ UINT8 *ExtByte;
+ UINTN CurrentPartition;
+
+ if (Partition > 7) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CurrentPartition = MmcGetCurrentPartitionNum (CardData);
+ if (Partition == CurrentPartition) {
+ return EFI_SUCCESS;
+ }
+
+ Status = MmcReadExtCsd (CardData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((EFI_D_INFO,
+ "MmcSelectPartitionNum: Switch partition: %d => %d\n",
+ CurrentPartition,
+ Partition
+ ));
+
+ Offset = OFFSET_OF (EXT_CSD, PARTITION_CONFIG);
+ Status = MmcSetExtCsd8 (CardData, (UINT8)Offset, Partition);
+
+#if 1
+ Status = MmcReadExtCsd (CardData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CurrentPartition = MmcGetCurrentPartitionNum (CardData);
+ if (Partition != CurrentPartition) {
+ DEBUG ((EFI_D_INFO, "MmcSelectPartitionNum: Switch partition failed!\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ ExtByte = NULL;
+#else
+ if (!EFI_ERROR (Status)) {
+ ExtByte = ((UINT8*)&CardData->ExtCSDRegister) + Offset;
+ *ExtByte = (UINT8) ((*ExtByte & 0xF7) | Partition);
+ }
+#endif
+
+ return Status;
+}
+
+EFI_STATUS
+MmcSelectPartition (
+ IN MMC_PARTITION_DATA *Partition
+ )
+{
+ return MmcSelectPartitionNum (
+ Partition->CardData,
+ (UINT8)CARD_DATA_PARTITION_NUM (Partition)
+ );
+}
+
+#if 1
+EFI_STATUS
+CommunicateBusMaster (
+ CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+ UINT32 ReadData;
+
+ //
+ // Spec define
+ //
+ Status = CardData->PciIo->Mem.Read (
+ CardData->PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ (UINT64) MMIO_PSTATE,
+ 1,
+ &ReadData
+ );
+ //
+ // No card
+ //
+ if ((ReadData & (BIT16 | BIT17 | BIT18)) != (BIT16 | BIT17 | BIT18)) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+#endif
diff --git a/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MediaDeviceDriver.c b/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MediaDeviceDriver.c
new file mode 100644
index 0000000000..d2d7e24c10
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MediaDeviceDriver.c
@@ -0,0 +1,608 @@
+/** @file
+ UEFI Driver Entry and Binding support.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ 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 "MediaDeviceDriver.h"
+#include <Protocol/EmmcCardInfoProtocol.h>
+
+//
+// MMCSDIOController Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gMediaDeviceDriverBinding = {
+ MediaDeviceDriverBindingSupported,
+ MediaDeviceDriverBindingStart,
+ MediaDeviceDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+EFI_EMMC_CARD_INFO_PROTOCOL *gEfiEmmcCardInfo = NULL;
+
+/**
+ Entry point for Media Device EFI drivers.
+
+ @param[in] ImageHandle EFI_HANDLE
+ @param[in] SystemTable EFI_SYSTEM_TABLE
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_DEVICE_ERROR The function failed to complete
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallAllDriverProtocols (
+ ImageHandle,
+ SystemTable,
+ &gMediaDeviceDriverBinding,
+ ImageHandle,
+ &gMediaDeviceComponentName,
+ NULL,
+ NULL
+ );
+}
+
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ that has installed will be supported.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] Controller Handle of device to test.
+ @param[in] RemainingDevicePath Not used.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo;
+
+ //
+ // Test whether there is SDHostIO Protocol attached on the controller handle.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSdHostIoProtocolGuid,
+ (VOID **) &SdHostIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSdHostIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+Exit:
+ return Status;
+}
+
+/**
+ Starting the Media Device Driver
+
+ @param[in] This Protocol instance pointer.
+ @param[in] Controller Handle of device to test
+ @param[in] RemainingDevicePath Not used
+
+ @retval EFI_SUCCESS Supports this device.
+ @retval EFI_UNSUPPORTED Do not support this device.
+ @retval EFI_DEVICE_ERROR Cannot be started due to device Error.
+ @retval EFI_OUT_OF_RESOURCES Cannot allocate resources.
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo = NULL;
+ CARD_DATA *CardData;
+ UINTN Loop;
+#if 1
+ UINTN SdCtlrDev, SdCtlrFunc, SdCtlrBus, Seg;
+ EFI_STATUS LocatePciStatus;
+#endif
+ UINTN Pages = 0;
+ EFI_EMMC_CARD_INFO_PROTOCOL *EfiEmmcCardInfoRegister;
+
+ EfiEmmcCardInfoRegister = NULL;
+ CardData = NULL;
+ //
+ //Alloc memory for EfiEmmcCardInfoRegister variable
+ //
+ EfiEmmcCardInfoRegister = (EFI_EMMC_CARD_INFO_PROTOCOL *)AllocateZeroPool(sizeof(EFI_EMMC_CARD_INFO_PROTOCOL));
+ if(EfiEmmcCardInfoRegister == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ //
+ // Open PCI I/O Protocol and save pointer to open protocol
+ // in private data area.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSdHostIoProtocolGuid,
+ (VOID **) &SdHostIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStart: Fail to open gEfiSdHostIoProtocolGuid \n"));
+ goto Exit;
+ }
+
+ Status = SdHostIo->DetectCardAndInitHost (SdHostIo);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStart: Fail to DetectCardAndInitHost %r\n", Status));
+ goto Exit;
+ }
+
+ CardData = (CARD_DATA*)AllocateZeroPool (sizeof (CARD_DATA));
+ if (CardData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStart: Fail to AllocateZeroPool(CARD_DATA) \n"));
+ goto Exit;
+ }
+
+ ASSERT (SdHostIo->HostCapability.BoundarySize >= 4 * 1024);
+ CardData->RawBufferPointer = (UINT8*)(UINTN)0xffffffff;
+ Pages = (2 * SdHostIo->HostCapability.BoundarySize);
+
+ DEBUG ((EFI_D_ERROR, "CardData->RawBufferPointer = 0x%x \n",CardData->RawBufferPointer));
+ DEBUG ((EFI_D_ERROR, "requesting 0x%x pages \n",EFI_SIZE_TO_PAGES(Pages)));
+ //
+ // Allocated the buffer under 4G
+ //
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES(Pages),
+ (EFI_PHYSICAL_ADDRESS *)(&(CardData->RawBufferPointer))
+ );
+ DEBUG ((EFI_D_ERROR, "CardData->RawBufferPointer = 0x%x \n",CardData->RawBufferPointer));
+ if (!EFI_ERROR (Status)) {
+ CardData->RawBufferPointer = ZeroMem (CardData->RawBufferPointer, EFI_SIZE_TO_PAGES(Pages));
+ } else {
+ DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStart: Fail to AllocateZeroPool(2*x) \n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ CardData->AlignedBuffer = CardData->RawBufferPointer - ((UINTN)(CardData->RawBufferPointer) & (SdHostIo->HostCapability.BoundarySize - 1)) + SdHostIo->HostCapability.BoundarySize;
+
+ CardData->Signature = CARD_DATA_SIGNATURE;
+ CardData->SdHostIo = SdHostIo;
+ CardData->Handle = Controller;
+ for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Loop++) {
+ CardData->Partitions[Loop].Signature = CARD_PARTITION_SIGNATURE;
+ }
+#if 1
+ LocatePciStatus = gBS->HandleProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID**) &(CardData->PciIo)
+ );
+ if (EFI_ERROR (LocatePciStatus)) {
+ DEBUG ((EFI_D_ERROR, "Get PCI IO Failed\n"));
+ }
+
+ LocatePciStatus = CardData->PciIo->GetLocation (
+ CardData->PciIo,
+ &Seg,
+ &SdCtlrBus,
+ &SdCtlrDev,
+ &SdCtlrFunc
+ );
+ if (EFI_ERROR (LocatePciStatus)) {
+ DEBUG ((EFI_D_ERROR, "Get PCI Bus Dev Func Fail\n"));
+ } else {
+ DEBUG ((EFI_D_ERROR, "Bus: %02x Dev: %02x Func: %02x\n", SdCtlrBus, SdCtlrDev, SdCtlrFunc));
+ }
+#endif
+
+ Status = MMCSDCardInit (CardData);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStart: Fail to MMCSDCardInit \n"));
+ goto Exit;
+ }
+
+ DEBUG ((EFI_D_INFO, "MediaDeviceDriverBindingStart: MMC SD card\n"));
+ Status = MMCSDBlockIoInit (CardData);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStart: Card BlockIo init failed\n"));
+ goto Exit;
+ }
+
+ Status = MediaDeviceDriverInstallBlockIo (This, CardData);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStart: Fail to install gEfiBlockIoProtocolGuid \n"));
+ goto Exit;
+ }
+
+ //
+ // Component name protocol
+ //
+ Status = AddUnicodeString (
+ "eng",
+ gMediaDeviceComponentName.SupportedLanguages,
+ &CardData->ControllerNameTable,
+ L"MMC/SD Media Device"
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Loop++) {
+ if (!CardData->Partitions[Loop].Present) {
+ continue;
+ }
+ gBS->UninstallMultipleProtocolInterfaces (
+ CardData->Partitions[Loop].Handle,
+ &gEfiBlockIoProtocolGuid,
+ &CardData->Partitions[Loop].BlockIo,
+ &gEfiDevicePathProtocolGuid,
+ CardData->Partitions[Loop].DevPath,
+ NULL
+ );
+ }
+ goto Exit;
+ }
+
+ if (EfiEmmcCardInfoRegister != NULL) {
+
+ //
+ // assign to protocol
+ //
+ EfiEmmcCardInfoRegister->CardData = CardData;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiEmmcCardInfoProtocolGuid,
+ EfiEmmcCardInfoRegister,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStart: Install eMMC Card info protocol failed\n"));
+ for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Loop++) {
+ if (!CardData->Partitions[Loop].Present) {
+ continue;
+ }
+ gBS->UninstallMultipleProtocolInterfaces (
+ CardData->Partitions[Loop].Handle,
+ &gEfiBlockIoProtocolGuid,
+ &CardData->Partitions[Loop].BlockIo,
+ &gEfiDevicePathProtocolGuid,
+ CardData->Partitions[Loop].DevPath,
+ NULL
+ );
+ }
+
+ goto Exit;
+ }
+
+ gEfiEmmcCardInfo = EfiEmmcCardInfoRegister;
+ }
+
+ DEBUG ((EFI_D_INFO, "MediaDeviceDriverBindingStart: Started\n"));
+
+Exit:
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStart: End with failure\n"));
+ if (CardData != NULL && SdHostIo != NULL) {
+ if (CardData->RawBufferPointer != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN) CardData->RawBufferPointer, EFI_SIZE_TO_PAGES(Pages));
+ }
+ FreePool (CardData);
+ }
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSdHostIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle. Support stoping any child handles
+ created by this driver.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] Controller Handle of device to stop driver on
+ @param[in] NumberOfChildren Number of Children in the ChildHandleBuffer
+ @param[in] ChildHandleBuffer List of handles for the children we need to stop.
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_DEVICE_ERROR Fail
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+
+{
+ EFI_STATUS Status;
+ CARD_DATA *CardData;
+ BOOLEAN AllChildrenStopped;
+ UINTN Index;
+ UINTN Pages = 0;
+
+ Status = EFI_SUCCESS;
+ CardData = gEfiEmmcCardInfo->CardData;
+
+ if (NumberOfChildren == 0) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiEmmcCardInfoProtocolGuid,
+ gEfiEmmcCardInfo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStop: UNINSTALL gEfiEmmcCardInfoProtocolGuid FAILURE\n"));
+ return Status;
+ }
+
+ FreeUnicodeStringTable (CardData->ControllerNameTable);
+
+ Pages = (2 * (CardData->SdHostIo->HostCapability.BoundarySize));
+ if (CardData->RawBufferPointer != NULL) {
+ FreePages (CardData->RawBufferPointer, EFI_SIZE_TO_PAGES(Pages));
+ }
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiSdHostIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ if (MediaDeviceDriverAllPartitionNotPresent(CardData)) {
+ FreePool (CardData);
+ FreePool (gEfiEmmcCardInfo);
+ gEfiEmmcCardInfo = NULL;
+ }
+
+ return Status;
+ }
+
+ AllChildrenStopped = TRUE;
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ Status = MediaDeviceDriverUninstallBlockIo(This, CardData, ChildHandleBuffer[Index]);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStop: UNINSTALL block io FAILURE\n"));
+ AllChildrenStopped = FALSE;
+ break;
+ }
+ }
+
+ return Status;
+}
+
+BOOLEAN
+MediaDeviceDriverAllPartitionNotPresent (
+ IN CARD_DATA *CardData
+ )
+{
+ BOOLEAN AllPartitionNotPresent;
+ UINTN Loop;
+ MMC_PARTITION_DATA *Partition;
+
+ Partition = CardData->Partitions;
+
+ AllPartitionNotPresent = TRUE;
+
+ for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Partition++, Loop++) {
+ if (Partition->Present) {
+ AllPartitionNotPresent = FALSE;
+ break;
+ }
+ }
+
+ return AllPartitionNotPresent;
+}
+
+STATIC
+struct {
+ DEVICE_LOGICAL_UNIT_DEVICE_PATH LogicalUnit;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} SdCardDevPathTemplate = {
+ {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_DEVICE_LOGICAL_UNIT_DP,
+ {
+ sizeof (DEVICE_LOGICAL_UNIT_DEVICE_PATH),
+ 0
+ },
+ },
+ 0
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+};
+
+EFI_STATUS
+MediaDeviceDriverInstallBlockIo (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN CARD_DATA *CardData
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Loop;
+ MMC_PARTITION_DATA *Partition;
+ EFI_DEVICE_PATH_PROTOCOL *MainPath;
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo = NULL;
+
+ Partition = CardData->Partitions;
+
+ Status = gBS->HandleProtocol (
+ CardData->Handle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &MainPath
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Partition++, Loop++) {
+ if (!Partition->Present) {
+ continue;
+ }
+
+ DEBUG ((EFI_D_INFO, "MediaDeviceDriverInstallBlockIo: Installing Block I/O for partition %d\n", Loop));
+
+ Partition->Handle = NULL;
+ Partition->CardData = CardData;
+
+ SdCardDevPathTemplate.LogicalUnit.Lun = Loop;
+ Partition->DevPath =
+ AppendDevicePath (
+ MainPath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &SdCardDevPathTemplate
+ );
+ if (Partition->DevPath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+
+ Status = gBS->InstallProtocolInterface (
+ &(Partition->Handle),
+ &gEfiDevicePathProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ Partition->DevPath
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ Status = gBS->InstallProtocolInterface (
+ &(Partition->Handle),
+ &gEfiBlockIoProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Partition->BlockIo
+ );
+
+ //
+ // Open parent controller by child
+ //
+ Status = gBS->OpenProtocol (
+ CardData->Handle,
+ &gEfiSdHostIoProtocolGuid,
+ (VOID **) &SdHostIo,
+ This->DriverBindingHandle,
+ Partition->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+MediaDeviceDriverUninstallBlockIo (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN CARD_DATA *CardData,
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ UINTN Loop;
+ MMC_PARTITION_DATA *Partition;
+
+ Partition = CardData->Partitions;
+
+ Status = EFI_SUCCESS;
+
+ for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Partition++, Loop++) {
+ if (!Partition->Present || Partition->Handle != Handle) {
+ continue;
+ }
+#if 1
+ //
+ // Close SdHostIoProtocol by child
+ //
+ Status = gBS->CloseProtocol (
+ CardData->Handle,
+ &gEfiSdHostIoProtocolGuid,
+ This->DriverBindingHandle,
+ Partition->Handle
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "CloseProtocol gEfiSdHostIoProtocolGuid FAILURE \n"));
+ return Status;
+ }
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Partition->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &Partition->BlockIo,
+ &gEfiDevicePathProtocolGuid,
+ Partition->DevPath,
+ NULL
+ );
+ Partition->Present = FALSE;
+ DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStop gEfiBlockIoProtocolGuid removed. %x\n", Status));
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR, "MediaDeviceDriverUninstallBlockIo UNISTALL FAILURE \n"));
+ }
+
+#else
+ Status = gBS->UninstallProtocolInterface (
+ Partition->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &Partition->BlockIo
+ );
+#endif
+ return Status;
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
diff --git a/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MediaDeviceDriver.h b/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MediaDeviceDriver.h
new file mode 100644
index 0000000000..d6cd600766
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MediaDeviceDriver.h
@@ -0,0 +1,392 @@
+/** @file
+ Media Device Driver header.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ 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 _MEDIA_DEVICE_DRIVER_H
+#define _MEDIA_DEVICE_DRIVER_H
+
+#include <Uefi.h>
+#include <Guid/EventGroup.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <IndustryStandard/Mmc.h>
+#include <IndustryStandard/CeAta.h>
+#include <IndustryStandard/SdCard.h>
+
+//
+// Driver Consumed Protocol Prototypes
+//
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/SdHostIo.h>
+#if 1
+#include <Protocol/PciIo.h>
+#endif
+
+//
+// Driver Produced Protocol Prototypes
+//
+#include <Protocol/DriverBinding.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/BlockIo.h>
+
+
+extern EFI_COMPONENT_NAME_PROTOCOL gMediaDeviceComponentName;
+extern EFI_DRIVER_BINDING_PROTOCOL gMediaDeviceDriverBinding;
+extern EFI_COMPONENT_NAME2_PROTOCOL gSdMediaDeviceName2;
+
+
+extern UINT32 gMediaDeviceDebugLevel;
+
+#define CARD_DATA_SIGNATURE SIGNATURE_32 ('c', 'a', 'r', 'd')
+#define CARD_PARTITION_SIGNATURE SIGNATURE_32 ('c', 'p', 'a', 'r')
+
+#define CARD_PARTITION_DATA_FROM_THIS(a) \
+ CR(a, MMC_PARTITION_DATA, BlockIo, CARD_PARTITION_SIGNATURE)
+
+#define CARD_DATA_FROM_THIS(a) \
+ ((CARD_PARTITION_DATA_FROM_THIS(a))->CardData)
+
+#define CARD_DATA_PARTITION_NUM(p) \
+ ((((UINTN) p) - ((UINTN) &(p->CardData->Partitions))) / sizeof (*p))
+
+//
+// Command timeout will be max 100 ms
+//
+#define TIMEOUT_COMMAND 100
+#define TIMEOUT_DATA 5000
+#if 1
+#define ONE_SECOND 10000000
+#define EFI_EVENT_TIMER 0x80000000
+#define EFI_EVENT_NOTIFY_SIGNAL 0x00000200
+#endif
+
+typedef enum {
+ UnknownCard = 0,
+ MMCCard, // MMC card
+ CEATACard, // CE-ATA device
+ SDMemoryCard, // SD 1.1 card
+ SDMemoryCard2, // SD 2.0 or above standard card
+ SDMemoryCard2High // SD 2.0 or above high capacity card
+} CARD_TYPE;
+
+typedef struct _CARD_DATA CARD_DATA;
+
+typedef struct {
+ //
+ //BlockIO
+ //
+ UINT32 Signature;
+
+ EFI_HANDLE Handle;
+
+ BOOLEAN Present;
+
+ EFI_DEVICE_PATH_PROTOCOL *DevPath;
+
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+
+ EFI_BLOCK_IO_MEDIA BlockIoMedia;
+
+ CARD_DATA *CardData;
+
+} MMC_PARTITION_DATA;
+
+#define MAX_NUMBER_OF_PARTITIONS 8
+
+struct _CARD_DATA {
+ //
+ //BlockIO
+ //
+ UINT32 Signature;
+
+ EFI_HANDLE Handle;
+
+ MMC_PARTITION_DATA Partitions[MAX_NUMBER_OF_PARTITIONS];
+
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+ CARD_TYPE CardType;
+
+ UINT8 CurrentBusWidth;
+ BOOLEAN DualVoltage;
+ BOOLEAN NeedFlush;
+ UINT8 Reserved[3];
+
+ UINT16 Address;
+ UINT32 BlockLen;
+ UINT32 MaxFrequency;
+ UINT64 BlockNumber;
+ //
+ //Common used
+ //
+ CARD_STATUS CardStatus;
+ OCR OCRRegister;
+ CID CIDRegister;
+ CSD CSDRegister;
+ EXT_CSD ExtCSDRegister;
+ UINT8 *RawBufferPointer;
+ UINT8 *AlignedBuffer;
+ //
+ //CE-ATA specific
+ //
+ TASK_FILE TaskFile;
+ IDENTIFY_DEVICE_DATA IndentifyDeviceData;
+ //
+ //SD specific
+ //
+ SCR SCRRegister;
+ SD_STATUS_REG SDSattus;
+ SWITCH_STATUS SwitchStatus;
+#if 1
+ EFI_PCI_IO_PROTOCOL *PciIo;
+#endif
+};
+
+//
+//
+//
+
+EFI_STATUS
+EFIAPI
+MediaDeviceDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+EFI_STATUS
+MediaDeviceDriverInstallBlockIo (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN CARD_DATA *CardData
+ );
+
+EFI_STATUS
+MediaDeviceDriverUninstallBlockIo (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN CARD_DATA *CardData,
+ IN EFI_HANDLE Handle
+ );
+
+BOOLEAN
+MediaDeviceDriverAllPartitionNotPresent (
+ IN CARD_DATA *CardData
+ );
+
+EFI_STATUS
+EFIAPI
+MediaDeviceComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+EFI_STATUS
+EFIAPI
+MediaDeviceComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle, OPTIONAL
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+EFI_STATUS
+EFIAPI
+MediaDeviceDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+MediaDeviceDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+MediaDeviceDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+EFI_STATUS
+MMCSDCardInit (
+ IN CARD_DATA *CardData
+ );
+
+EFI_STATUS
+MMCSDBlockIoInit (
+ IN CARD_DATA *CardData
+ );
+
+EFI_STATUS
+SendCommand (
+ IN EFI_SD_HOST_IO_PROTOCOL *This,
+ IN UINT16 CommandIndex,
+ IN UINT32 Argument,
+ IN TRANSFER_TYPE DataType,
+ IN UINT8 *Buffer, OPTIONAL
+ IN UINT32 BufferSize,
+ IN RESPONSE_TYPE ResponseType,
+ IN UINT32 TimeOut,
+ OUT UINT32 *ResponseData
+ );
+
+EFI_STATUS
+FastIO (
+ IN CARD_DATA *CardData,
+ IN UINT8 RegisterAddress,
+ IN OUT UINT8 *RegisterData,
+ IN BOOLEAN Write
+ );
+
+BOOLEAN
+IsCEATADevice (
+ IN CARD_DATA *CardData
+ );
+
+EFI_STATUS
+CEATABlockIoInit (
+ IN CARD_DATA *CardData
+ );
+
+EFI_STATUS
+IndentifyDevice (
+ IN CARD_DATA *CardData
+ );
+
+EFI_STATUS
+FlushCache (
+ IN CARD_DATA *CardData
+ );
+
+EFI_STATUS
+StandByImmediate (
+ IN CARD_DATA *CardData
+ );
+
+EFI_STATUS
+ReadDMAExt (
+ IN CARD_DATA *CardData,
+ IN EFI_LBA LBA,
+ IN UINT8 *Buffer,
+ IN UINT16 SectorCount
+ );
+
+EFI_STATUS
+WriteDMAExt (
+ IN CARD_DATA *CardData,
+ IN EFI_LBA LBA,
+ IN UINT8 *Buffer,
+ IN UINT16 SectorCount
+ );
+
+EFI_STATUS
+SoftwareReset (
+ IN CARD_DATA *CardData
+ );
+
+EFI_STATUS
+SendAppCommand (
+ IN CARD_DATA *CardData,
+ IN UINT16 CommandIndex,
+ IN UINT32 Argument,
+ IN TRANSFER_TYPE DataType,
+ IN UINT8 *Buffer, OPTIONAL
+ IN UINT32 BufferSize,
+ IN RESPONSE_TYPE ResponseType,
+ IN UINT32 TimeOut,
+ OUT UINT32 *ResponseData
+ );
+
+UINT32
+MmcGetExtCsd8 (
+ IN CARD_DATA *CardData,
+ IN UINTN Offset
+ );
+
+UINT32
+MmcGetExtCsd24 (
+ IN CARD_DATA *CardData,
+ IN UINTN Offset
+ );
+
+UINT32
+MmcGetExtCsd32 (
+ IN CARD_DATA *CardData,
+ IN UINTN Offset
+ );
+
+UINTN
+MmcGetCurrentPartitionNum (
+ IN CARD_DATA *CardData
+ );
+
+VOID
+SetEmmcWpOnEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+VOID
+SecureEraseEvent(
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+EFI_STATUS
+MmcSelectPartitionNum (
+ IN CARD_DATA *CardData,
+ IN UINT8 Partition
+ );
+
+EFI_STATUS
+MmcSelectPartition (
+ IN MMC_PARTITION_DATA *Partition
+ );
+
+VOID
+SecureErase (
+ CARD_DATA *CardData
+ );
+
+#if 1
+VOID
+CheckCardExistEvent (
+ IN EFI_EVENT EVENT,
+ IN VOID *Context
+ );
+
+EFI_STATUS
+CommunicateBusMaster (
+ IN CARD_DATA *CardData
+ );
+#endif
+
+#endif
diff --git a/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MmcMediaDeviceDxe.inf b/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MmcMediaDeviceDxe.inf
new file mode 100644
index 0000000000..93041346f4
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/SDMediaDeviceDxe/MmcMediaDeviceDxe.inf
@@ -0,0 +1,62 @@
+## @file
+# PCH SD/MMC Media Dxe Module
+#
+# Provides support for SD and MMC media. This allows file system access to the
+# SD and MMC media on the system.
+#
+# Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# 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 = MmcMediaDevice
+ FILE_GUID = F93025BF-7A31-4BD0-86C7-39AECC6013CA
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = MediaDeviceDriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ ComponentName.c
+ MediaDeviceDriver.c
+ MMCSDBlockIo.c
+ MMCSDTransfer.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ChvRefCodePkg/ChvRefCodePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ DebugLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiLib
+ DevicePathLib
+ IoLib
+ PcdLib
+
+[Protocols]
+ gEfiDevicePathProtocolGuid ## BY_START
+ gEfiSdHostIoProtocolGuid ## TO_START
+ gEfiBlockIoProtocolGuid ## BY_START
+ gEfiEmmcCardInfoProtocolGuid ## BY_START
+ gEfiPciIoProtocolGuid ## TO_START
+