* [PATCH V4 1/1] EmbeddedPkg: DwMmcHcDxe: Add support for Designware SDMMC driver
@ 2021-03-19 8:22 Loh, Tien Hock
2021-03-19 8:22 ` Loh, Tien Hock
0 siblings, 1 reply; 4+ messages in thread
From: Loh, Tien Hock @ 2021-03-19 8:22 UTC (permalink / raw)
To: devel; +Cc: tien.hock.loh, thloh85
From: Loh Tien Hock <tien.hock.loh@intel.com>
This adds support for Designware SDMMC driver. The SDMMC driver depends on
MdeModulePkg/Bus/Sd/, and produces EFI_SD_MMC_PASS_THRU_PROTOCOL. The
driver uses MMIO to read/write, and uses
gEdkiiNonDiscoverableDeviceProtocolGuid. Platform needs to register device
with gEdkiiNonDiscoverableDeviceProtocolGuid.
https://github.com/thloh85-intel/edk2/tree/dwmmc_driver_v4
--
v4:
* Rewrite the MMIO section so that it reuses
gEdkiiNonDiscoverableDeviceProtocolGuid, thus no extra NonDiscoverable
driver is needed
Tien Hock, Loh (1):
EmbeddedPkg: DwMmcHcDxe: Add support for Designware SDMMC driver
EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec | 40 +
EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf | 70 +
EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h | 817 ++++++++++
EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h | 985 ++++++++++++
EmbeddedPkg/Include/Protocol/PlatformDwMmc.h | 79 +
EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c | 214 +++
EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c | 1296 ++++++++++++++++
EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c | 1602 ++++++++++++++++++++
EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c | 1042 +++++++++++++
EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c | 1105 ++++++++++++++
10 files changed, 7250 insertions(+)
create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
create mode 100644 EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
--
2.12.3
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH V4 1/1] EmbeddedPkg: DwMmcHcDxe: Add support for Designware SDMMC driver
2021-03-19 8:22 [PATCH V4 1/1] EmbeddedPkg: DwMmcHcDxe: Add support for Designware SDMMC driver Loh, Tien Hock
@ 2021-03-19 8:22 ` Loh, Tien Hock
2021-03-19 15:33 ` [edk2-devel] " Michael D Kinney
0 siblings, 1 reply; 4+ messages in thread
From: Loh, Tien Hock @ 2021-03-19 8:22 UTC (permalink / raw)
To: devel; +Cc: tien.hock.loh, thloh85, Leif Lindholm, Ard Biesheuvel
From: "Tien Hock, Loh" <tien.hock.loh@intel.com>
This adds support for Designware SDMMC driver. The SDMMC driver depends on
MdeModulePkg/Bus/Sd/, and produces EFI_SD_MMC_PASS_THRU_PROTOCOL. The
driver uses MMIO to read/write, and uses
gEdkiiNonDiscoverableDeviceProtocolGuid. Platform needs to register device
with gEdkiiNonDiscoverableDeviceProtocolGuid.
Signed-off-by: Loh Tien Hock <tien.hock.loh@intel.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
---
EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec | 40 +
EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf | 70 +
EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h | 817 ++++++++++
EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h | 985 ++++++++++++
EmbeddedPkg/Include/Protocol/PlatformDwMmc.h | 79 +
EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c | 214 +++
EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c | 1296 ++++++++++++++++
EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c | 1602 ++++++++++++++++++++
EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c | 1042 +++++++++++++
EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c | 1105 ++++++++++++++
10 files changed, 7250 insertions(+)
diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
new file mode 100644
index 000000000000..cf85ccb1a030
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
@@ -0,0 +1,40 @@
+#/** @file
+# Framework Module Development Environment Industry Standards
+#
+# This Package provides headers and libraries that conform to EFI/PI Industry standards.
+# Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2012-2014, ARM Ltd. All rights reserved.<BR>
+# Copyright (c) 2018, Linaro. 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]
+ DEC_SPECIFICATION = 0x00010019
+ PACKAGE_NAME = DwMmcHcDxePkg
+ PACKAGE_GUID = e73097ce-1fe2-41a6-a930-3136bc6d23ef
+ PACKAGE_VERSION = 0.1
+
+
+################################################################################
+#
+# Include Section - list of Include Paths that are provided by this package.
+# Comments are used for Keywords and Module Types.
+#
+# Supported Module Types:
+# BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION
+#
+################################################################################
+
+[Guids.common]
+ gDwMmcHcDxeTokenSpaceGuid = { 0x576c132e, 0x7d51, 0x4abb, { 0xbc, 0x60, 0x13, 0x08, 0x04, 0x0e, 0x90, 0x92 }}
+
+[Protocols.common]
+ gPlatformDwMmcProtocolGuid = { 0x1d6dfde5, 0x76a7, 0x4404, { 0x85, 0x74, 0x7a, 0xdf, 0x1a, 0x8a, 0xa2, 0x0d }}
diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
new file mode 100644
index 000000000000..4cd0960ef9c3
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
@@ -0,0 +1,70 @@
+## @file
+# DwSdMmcHcDxe driver is used to manage those host controllers which comply with
+# Designware SD Host Controller.
+#
+# It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC/eMMC cmds
+# to specified devices from upper layer.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+# Copyright (C) 2016, Marvell International Ltd. All rights reserved.<BR>
+# Copyright (c) 2018, Linaro Ltd. 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 = 0x00010019
+ BASE_NAME = DwMmcHcDxe
+ MODULE_UNI_FILE = DwMmcHcDxe.uni
+ FILE_GUID = 9be4d260-208c-4efe-a524-0b5d3bf77f9d
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeDwMmcHcDxe
+
+[Sources]
+ ComponentName.c
+ DwMmcHcDxe.c
+ DwMmcHcDxe.h
+ DwMmcHci.c
+ DwMmcHci.h
+ EmmcDevice.c
+ SdDevice.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ ArmLib
+ BaseLib
+ BaseMemoryLib
+ CacheMaintenanceLib
+ DebugLib
+ DevicePathLib
+ DmaLib
+ MemoryAllocationLib
+ TimerLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ UefiRuntimeServicesTableLib
+
+[Protocols]
+ gEdkiiNonDiscoverableDeviceProtocolGuid
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiSdMmcPassThruProtocolGuid ## BY_START
+ gPlatformDwMmcProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DwMmcHcDxeExtra.uni
diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
new file mode 100644
index 000000000000..b783d9830325
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
@@ -0,0 +1,817 @@
+/** @file
+
+ Provides some data structure definitions used by the Designware SD/MMC
+ host controller driver.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ Copyright (C) 2018, Linaro Ltd. All rigths 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 _DW_MMC_HC_DXE_H_
+#define _DW_MMC_HC_DXE_H_
+
+#include <Uefi.h>
+
+#include <Library/UefiLib.h>
+
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/DeviceIo.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/SdMmcPassThru.h>
+
+#include "DwMmcHci.h"
+
+extern EFI_COMPONENT_NAME_PROTOCOL gDwMmcHcComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gDwMmcHcComponentName2;
+extern EFI_DRIVER_BINDING_PROTOCOL gDwMmcHcDriverBinding;
+
+#define DW_MMC_HC_PRIVATE_SIGNATURE SIGNATURE_32 ('d', 'w', 's', 'd')
+
+#define DW_MMC_HC_PRIVATE_FROM_THIS(a) \
+ CR(a, DW_MMC_HC_PRIVATE_DATA, PassThru, DW_MMC_HC_PRIVATE_SIGNATURE)
+
+//
+// Generic time out value, 1 microsecond as unit.
+//
+#define DW_MMC_HC_GENERIC_TIMEOUT (1 * 1000 * 1000)
+
+//
+// SD/MMC async transfer timer interval, set by experience.
+// The unit is 100us, takes 1ms as interval.
+//
+#define DW_MMC_HC_ASYNC_TIMER EFI_TIMER_PERIOD_MILLISECONDS(1)
+//
+// SD/MMC removable device enumeration timer interval, set by experience.
+// The unit is 100us, takes 100ms as interval.
+//
+#define DW_MMC_HC_ENUM_TIMER EFI_TIMER_PERIOD_MILLISECONDS(100)
+
+typedef struct {
+ BOOLEAN Enable;
+ EFI_SD_MMC_SLOT_TYPE SlotType;
+ BOOLEAN MediaPresent;
+ BOOLEAN Initialized;
+ SD_MMC_CARD_TYPE CardType;
+} DW_MMC_HC_SLOT;
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE ControllerHandle;
+
+ // Mmio base address
+ UINTN DevBase;
+
+ EFI_SD_MMC_PASS_THRU_PROTOCOL PassThru;
+
+ PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc;
+ //
+ // The field is used to record the previous slot in GetNextSlot().
+ //
+ UINT8 PreviousSlot;
+ //
+ // For Non-blocking operation.
+ //
+ EFI_EVENT TimerEvent;
+ //
+ // For Sd removable device enumeration.
+ //
+ EFI_EVENT ConnectEvent;
+ LIST_ENTRY Queue;
+
+ DW_MMC_HC_SLOT Slot[DW_MMC_HC_MAX_SLOT];
+ DW_MMC_HC_SLOT_CAP Capability[DW_MMC_HC_MAX_SLOT];
+ UINT64 MaxCurrent[DW_MMC_HC_MAX_SLOT];
+
+ UINT32 ControllerVersion;
+} DW_MMC_HC_PRIVATE_DATA;
+
+#define DW_MMC_HC_TRB_SIG SIGNATURE_32 ('D', 'T', 'R', 'B')
+
+//
+// TRB (Transfer Request Block) contains information for the cmd request.
+//
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY TrbList;
+
+ UINT8 Slot;
+ UINT16 BlockSize;
+
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ VOID *Data;
+ UINT32 DataLen;
+ BOOLEAN Read;
+ EFI_PHYSICAL_ADDRESS DataPhy;
+ VOID *DataMap;
+ DW_MMC_HC_TRANSFER_MODE Mode;
+
+ EFI_EVENT Event;
+ BOOLEAN Started;
+ UINT64 Timeout;
+
+ DW_MMC_HC_DMA_DESC_LINE *DmaDesc;
+ EFI_PHYSICAL_ADDRESS DmaDescPhy;
+ UINT32 DmaDescPages;
+ VOID *DmaMap;
+
+ BOOLEAN UseFifo;
+ BOOLEAN UseBE; // Big-endian
+
+ DW_MMC_HC_PRIVATE_DATA *Private;
+} DW_MMC_HC_TRB;
+
+#define DW_MMC_HC_TRB_FROM_THIS(a) \
+ CR(a, DW_MMC_HC_TRB, TrbList, DW_MMC_HC_TRB_SIG)
+
+//
+// Task for Non-blocking mode.
+//
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ UINT8 Slot;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ BOOLEAN IsStart;
+ EFI_EVENT Event;
+ UINT64 RetryTimes;
+ BOOLEAN InfiniteWait;
+ VOID *Map;
+ VOID *MapAddress;
+} DW_MMC_HC_QUEUE;
+
+//
+// Prototypes
+//
+/**
+ Execute card identification procedure.
+
+ @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+
+ @retval EFI_SUCCESS The card is identified correctly.
+ @retval Others The card can't be identified.
+
+**/
+typedef
+EFI_STATUS
+(*DWMMC_CARD_TYPE_DETECT_ROUTINE) (
+ IN DW_MMC_HC_PRIVATE_DATA *Private
+ );
+
+/**
+ Sends SD command to an SD card that is attached to the SD controller.
+
+ The PassThru() function sends the SD command specified by Packet to the SD
+ card specified by Slot.
+
+ If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.
+
+ If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is
+ returned.
+
+ If Slot is not in a valid range for the SD controller, then
+ EFI_INVALID_PARAMETER is returned.
+
+ If Packet defines a data command but both InDataBuffer and OutDataBuffer are
+ NULL, EFI_INVALID_PARAMETER is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Slot The slot number of the SD card to send the
+ command to.
+ @param[in,out] Packet A pointer to the SD command data structure.
+ @param[in] Event If Event is NULL, blocking I/O is performed. If
+ Event is not NULL, then nonblocking I/O is
+ performed, and Event will be signaled when the
+ Packet completes.
+
+ @retval EFI_SUCCESS The SD Command Packet was sent by the host.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
+ the SD command Packet.
+ @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is
+ invalid.
+ @retval EFI_INVALID_PARAMETER Packet defines a data command but both
+ InDataBuffer and OutDataBuffer are NULL.
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.
+ @retval EFI_UNSUPPORTED The command described by the SD Command Packet
+ is not supported by the host controller.
+ @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength
+ exceeds the limit supported by SD card ( i.e. if
+ the number of bytes exceed the Last LBA).
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruPassThru (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot,
+ IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ );
+
+/**
+ Used to retrieve next slot numbers supported by the SD controller. The
+ function returns information about all available slots (populated or
+ not-populated).
+
+ The GetNextSlot() function retrieves the next slot number on an SD controller.
+ If on input Slot is 0xFF, then the slot number of the first slot on the SD
+ controller is returned.
+
+ If Slot is a slot number that was returned on a previous call to
+ GetNextSlot(), then the slot number of the next slot on the SD controller is
+ returned.
+
+ If Slot is not 0xFF and Slot was not returned on a previous call to
+ GetNextSlot(), EFI_INVALID_PARAMETER is returned.
+
+ If Slot is the slot number of the last slot on the SD controller, then
+ EFI_NOT_FOUND is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in,out] Slot On input, a pointer to a slot number on the SD
+ controller.
+ On output, a pointer to the next slot number on
+ the SD controller.
+ An input value of 0xFF retrieves the first slot
+ number on the SD controller.
+
+ @retval EFI_SUCCESS The next slot number on the SD controller was
+ returned in Slot.
+ @retval EFI_NOT_FOUND There are no more slots on this SD controller.
+ @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a
+ previous call to GetNextSlot().
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruGetNextSlot (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 *Slot
+ );
+
+/**
+ Used to allocate and build a device path node for an SD card on the SD
+ controller.
+
+ The BuildDevicePath() function allocates and builds a single device node
+ for the SD
+ card specified by Slot.
+
+ If the SD card specified by Slot is not present on the SD controller, then
+ EFI_NOT_FOUND is returned.
+
+ If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.
+
+ If there are not enough resources to allocate the device path node, then
+ EFI_OUT_OF_RESOURCES is returned.
+
+ Otherwise, DevicePath is allocated with the boot service AllocatePool(), the
+ contents of DevicePath are initialized to describe the SD card specified by
+ Slot, and EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Slot Specifies the slot number of the SD card for
+ which a device path node is to be allocated and
+ built.
+ @param[in,out] DevicePath A pointer to a single device path node that
+ describes the SD card specified by Slot. This
+ function is responsible for allocating the
+ buffer DevicePath with the boot service
+ AllocatePool(). It is the caller's responsibi-
+ lity to free DevicePath when the caller is
+ finished with DevicePath.
+
+ @retval EFI_SUCCESS The device path node that describes the SD card
+ specified by Slot was allocated and returned in
+ DevicePath.
+ @retval EFI_NOT_FOUND The SD card specified by Slot does not exist on
+ the SD controller.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate
+ DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruBuildDevicePath (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ This function retrieves an SD card slot number based on the input device path.
+
+ The GetSlotNumber() function retrieves slot number for the SD card specified
+ by the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is
+ returned.
+
+ If DevicePath is not a device path node type that the SD Pass Thru driver
+ supports, EFI_UNSUPPORTED is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] DevicePath A pointer to the device path node that describes
+ a SD card on the SD controller.
+ @param[out] Slot On return, points to the slot number of an SD
+ card on the SD controller.
+
+ @retval EFI_SUCCESS SD card slot number is returned in Slot.
+ @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.
+ @retval EFI_UNSUPPORTED DevicePath is not a device path node type that
+ the SD Pass Thru driver supports.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruGetSlotNumber (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT8 *Slot
+ );
+
+/**
+ Resets an SD card that is connected to the SD controller.
+
+ The ResetDevice() function resets the SD card specified by Slot.
+
+ If this SD controller does not support a device reset operation,
+ EFI_UNSUPPORTED is returned.
+
+ If Slot is not in a valid slot number for this SD controller,
+ EFI_INVALID_PARAMETER is returned.
+
+ If the device reset operation is completed, EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Slot Specifies the slot number of the SD card to be
+ reset.
+
+ @retval EFI_SUCCESS The SD card specified by Slot was reset.
+ @retval EFI_UNSUPPORTED The SD controller does not support a device
+ reset operation.
+ @retval EFI_INVALID_PARAMETER Slot number is invalid.
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.
+ @retval EFI_DEVICE_ERROR The reset command failed due to a device error
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruResetDevice (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot
+ );
+
+//
+// Driver model protocol interfaces
+//
+/**
+ Tests to see if this driver supports a given controller. If a child device is
+ provided, it further tests to see if this driver supports creating a handle
+ for the specified child device.
+
+ This function checks to see if the driver specified by This supports the
+ device specified by ControllerHandle. Drivers will typically use the device
+ path attached to ControllerHandle and/or the services from the bus I/O
+ abstraction attached to ControllerHandle to determine if the driver supports
+ ControllerHandle. This function may be called many times during platform
+ initialization. In order to reduce boot times, the tests performed by this
+ function must be very small, and take as little time as possible to execute.
+ This function must not change the state of any hardware devices, and this
+ function must be aware that the device specified by ControllerHandle may
+ already be managed by the same driver or a different driver. This function
+ must match its calls to AllocatePages() with FreePages(), AllocatePool() with
+ FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if
+ a protocol is already in the opened state, then it must not be closed with
+ CloseProtocol(). This is required to guarantee the state of ControllerHandle
+ is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param[in] ControllerHandle The handle of the controller to test. This
+ handle must support a protocol interface that
+ supplies an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a
+ device path. This parameter is ignored by
+ device drivers, and is optional for bus
+ drivers. For bus drivers, if this parameter
+ is not NULL, then the bus driver must deter-
+ mine if the bus controller specified by
+ ControllerHandle and the child controller
+ specified by RemainingDevicePath are both
+ supported by this bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the
+ driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed
+ by the driver specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed
+ by a different driver or an application that
+ requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the
+ driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ The Start() function is designed to be invoked from the EFI boot service
+ ConnectController().
+ As a result, much of the error checking on the parameters to Start() has been
+ moved into this common boot service. It is legal to call Start() from other
+ locations,
+ but the following calling restrictions must be followed or the system behavior
+ will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a natural-
+ ly aligned EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver specified
+ by This must have been called with the same calling parameters, and
+ Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param[in] ControllerHandle The handle of the controller to start. This
+ handle must support a protocol interface that
+ supplies an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a
+ device path. This parameter is ignored by
+ device drivers, and is optional for bus dri-
+ vers. For a bus driver, if this parameter is
+ NULL, then handles for all the children of
+ Controller are created by this driver.
+ If this parameter is not NULL and the first
+ Device Path Node is not the End of Device
+ Path Node, then only the handle for the
+ child device specified by the first Device
+ Path Node of RemainingDevicePath is created
+ by this driver.
+ If the first Device Path Node of
+ RemainingDevicePath is the End of Device Path
+ Node, no child handle is created by this
+ driver.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a
+ device error. Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+ @retval Others The driver failded to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ The Stop() function is designed to be invoked from the EFI boot service
+ DisconnectController().
+ As a result, much of the error checking on the parameters to Stop() has been
+ moved into this common boot service. It is legal to call Stop() from other
+ locations, but the following calling restrictions must be followed or the
+ system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous
+ call to this same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+ EFI_HANDLE. In addition, all of these handles must have been created in
+ this driver's Start() function, and the Start() function must have called
+ OpenProtocol() on ControllerHandle with an Attribute of
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle
+ must support a bus specific I/O protocol for the
+ driver to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in
+ ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be
+ NULL if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device
+ error.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name 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. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] 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
+DwMmcHcComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] 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 ChildHandle[in] 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 Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name 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. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] 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
+DwMmcHcComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle, OPTIONAL
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Create a new TRB for the SD/MMC cmd request.
+
+ @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command
+ to.
+ @param[in] Packet A pointer to the SD command data structure.
+ @param[in] Event If Event is NULL, blocking I/O is performed.
+ If Event is not NULL, then nonblocking I/O is
+ performed, and Event will be signaled when the
+ Packet completes.
+
+ @return Created Trb or NULL.
+
+**/
+DW_MMC_HC_TRB *
+DwMmcCreateTrb (
+ IN DW_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event
+ );
+
+/**
+ Free the resource used by the TRB.
+
+ @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
+
+**/
+VOID
+DwMmcFreeTrb (
+ IN DW_MMC_HC_TRB *Trb
+ );
+
+/**
+ Check if the env is ready for execute specified TRB.
+
+ @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The env is ready for TRB execution.
+ @retval EFI_NOT_READY The env is not ready for TRB execution.
+ @retval Others Some erros happen.
+
+**/
+EFI_STATUS
+DwMmcCheckTrbEnv (
+ IN DW_MMC_HC_PRIVATE_DATA *Private,
+ IN DW_MMC_HC_TRB *Trb
+ );
+
+/**
+ Wait for the env to be ready for execute specified TRB.
+
+ @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The env is ready for TRB execution.
+ @retval EFI_TIMEOUT The env is not ready for TRB execution in time.
+ @retval Others Some erros happen.
+
+**/
+EFI_STATUS
+DwMmcWaitTrbEnv (
+ IN DW_MMC_HC_PRIVATE_DATA *Private,
+ IN DW_MMC_HC_TRB *Trb
+ );
+
+/**
+ Execute the specified TRB.
+
+ @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is sent to host controller successfully.
+ @retval Others Some erros happen when sending this request to the
+ host controller.
+
+**/
+EFI_STATUS
+DwMmcExecTrb (
+ IN DW_MMC_HC_PRIVATE_DATA *Private,
+ IN DW_MMC_HC_TRB *Trb
+ );
+
+/**
+ Check the TRB execution result.
+
+ @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval EFI_NOT_READY The TRB is not completed for execution.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+DwMmcCheckTrbResult (
+ IN DW_MMC_HC_PRIVATE_DATA *Private,
+ IN DW_MMC_HC_TRB *Trb
+ );
+
+/**
+ Wait for the TRB execution result.
+
+ @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+DwMmcWaitTrbResult (
+ IN DW_MMC_HC_PRIVATE_DATA *Private,
+ IN DW_MMC_HC_TRB *Trb
+ );
+
+/**
+ Execute EMMC device identification procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+
+ @retval EFI_SUCCESS There is a EMMC card.
+ @retval Others There is not a EMMC card.
+
+**/
+EFI_STATUS
+EmmcIdentification (
+ IN DW_MMC_HC_PRIVATE_DATA *Private
+ );
+
+/**
+ Execute EMMC device identification procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+
+ @retval EFI_SUCCESS There is a EMMC card.
+ @retval Others There is not a EMMC card.
+
+**/
+EFI_STATUS
+SdCardIdentification (
+ IN DW_MMC_HC_PRIVATE_DATA *Private
+ );
+
+#endif /* _DW_MMC_HC_DXE_H_ */
diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
new file mode 100644
index 000000000000..12ef58a37368
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
@@ -0,0 +1,985 @@
+/** @file
+
+ Provides some data structure definitions used by the SD/MMC host controller
+ driver.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2018, Linaro Ltd. 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 _DW_MMC_HCI_H_
+#define _DW_MMC_HCI_H_
+
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/TimerLib.h>
+
+#include <Protocol/PlatformDwMmc.h>
+
+//
+// SD Host Controller SlotInfo Register Offset
+//
+#define DW_MMC_HC_SLOT_OFFSET 0x40
+
+#define DW_MMC_HC_MAX_SLOT 1
+
+//
+// SD Host Controller MMIO Register Offset
+//
+#define DW_MMC_CTRL 0x000
+#define DW_MMC_PWREN 0x004
+#define DW_MMC_CLKDIV 0x008
+#define DW_MMC_CLKSRC 0x00c
+#define DW_MMC_CLKENA 0x010
+#define DW_MMC_TMOUT 0x014
+#define DW_MMC_CTYPE 0x018
+#define DW_MMC_BLKSIZ 0x01c
+#define DW_MMC_BYTCNT 0x020
+#define DW_MMC_INTMASK 0x024
+#define DW_MMC_CMDARG 0x028
+#define DW_MMC_CMD 0x02c
+#define DW_MMC_RESP0 0x030
+#define DW_MMC_RESP1 0x034
+#define DW_MMC_RESP2 0x038
+#define DW_MMC_RESP3 0x03c
+#define DW_MMC_RINTSTS 0x044
+#define DW_MMC_STATUS 0x048
+#define DW_MMC_FIFOTH 0x04c
+#define DW_MMC_GPIO 0x058
+#define DW_MMC_DEBNCE 0x064
+#define DW_MMC_USRID 0x068
+#define DW_MMC_VERID 0x06c
+#define DW_MMC_HCON 0x070
+#define DW_MMC_UHSREG 0x074
+#define DW_MMC_BMOD 0x080
+#define DW_MMC_DBADDR 0x088
+#define DW_MMC_IDSTS 0x08c
+#define DW_MMC_IDINTEN 0x090
+#define DW_MMC_DSCADDR 0x094
+#define DW_MMC_BUFADDR 0x098
+#define DW_MMC_CARDTHRCTL 0x100
+#define DW_MMC_UHSREG_EXT 0x108
+#define DW_MMC_ENABLE_SHIFT 0x110
+#define DW_MMC_FIFO_START 0x200
+
+#define GET_IDSTS_DMAC_FSM(x) (((x) >> 13) & 0xf)
+#define IDSTS_FSM_DMA_IDLE 0
+#define IDSTS_FSM_DMA_SUSPEND 1
+#define IDSTS_FSM_DESC_RD 2
+#define IDSTS_FSM_DESC_CHK 3
+#define IDSTS_FSM_DMA_RD_REQ_WAIT 4
+#define IDSTS_FSM_DMA_WR_REQ_WAIT 5
+#define IDSTS_FSM_DMA_RD 6
+#define IDSTS_FSM_DMA_WR 7
+#define IDSTS_FSM_DESC_CLOSE 8
+#define IDSTS_FSM_MASK 0xf
+
+#define CMD_UPDATE_CLK 0x80202000
+#define CMD_START_BIT (1 << 31)
+
+#define MMC_8BIT_MODE (1 << 16)
+#define MMC_4BIT_MODE (1 << 0)
+#define MMC_1BIT_MODE 0
+
+#define DW_MMC_BLOCK_SIZE 512
+
+#define CMD_INDEX_MASK 0x3F
+#define BIT_CMD_RESPONSE_EXPECT (1 << 6)
+#define BIT_CMD_LONG_RESPONSE (1 << 7)
+#define BIT_CMD_CHECK_RESPONSE_CRC (1 << 8)
+#define BIT_CMD_DATA_EXPECTED (1 << 9)
+#define BIT_CMD_READ (0 << 10)
+#define BIT_CMD_WRITE (1 << 10)
+#define BIT_CMD_BLOCK_TRANSFER (0 << 11)
+#define BIT_CMD_STREAM_TRANSFER (1 << 11)
+#define BIT_CMD_SEND_AUTO_STOP (1 << 12)
+#define BIT_CMD_WAIT_PRVDATA_COMPLETE (1 << 13)
+#define BIT_CMD_STOP_ABORT_CMD (1 << 14)
+#define BIT_CMD_SEND_INIT (1 << 15)
+#define BIT_CMD_UPDATE_CLOCK_ONLY (1 << 21)
+#define BIT_CMD_READ_CEATA_DEVICE (1 << 22)
+#define BIT_CMD_CCS_EXPECTED (1 << 23)
+#define BIT_CMD_ENABLE_BOOT (1 << 24)
+#define BIT_CMD_EXPECT_BOOT_ACK (1 << 25)
+#define BIT_CMD_DISABLE_BOOT (1 << 26)
+#define BIT_CMD_MANDATORY_BOOT (0 << 27)
+#define BIT_CMD_ALTERNATE_BOOT (1 << 27)
+#define BIT_CMD_VOLT_SWITCH (1 << 28)
+#define BIT_CMD_USE_HOLD_REG (1 << 29)
+#define BIT_CMD_START (1 << 31)
+
+#define CMD_INDEX(x) ((x) & CMD_INDEX_MASK)
+
+#define DW_MMC_INT_EBE (1 << 15) /* End-bit Err */
+#define DW_MMC_INT_SBE (1 << 13) /* Start-bit Err */
+#define DW_MMC_INT_HLE (1 << 12) /* Hardware-lock Err */
+#define DW_MMC_INT_FRUN (1 << 11) /* FIFO UN/OV RUN */
+#define DW_MMC_INT_DRT (1 << 9) /* Data timeout */
+#define DW_MMC_INT_RTO (1 << 8) /* Response timeout */
+#define DW_MMC_INT_DCRC (1 << 7) /* Data CRC err */
+#define DW_MMC_INT_RCRC (1 << 6) /* Response CRC err */
+#define DW_MMC_INT_RXDR (1 << 5) /* Receive FIFO data request */
+#define DW_MMC_INT_TXDR (1 << 4) /* Transmit FIFO data request */
+#define DW_MMC_INT_DTO (1 << 3) /* Data trans over */
+#define DW_MMC_INT_CMD_DONE (1 << 2) /* Command done */
+#define DW_MMC_INT_RE (1 << 1) /* Response error */
+
+#define DW_MMC_IDMAC_DES0_DIC (1 << 1)
+#define DW_MMC_IDMAC_DES0_LD (1 << 2)
+#define DW_MMC_IDMAC_DES0_FS (1 << 3)
+#define DW_MMC_IDMAC_DES0_CH (1 << 4)
+#define DW_MMC_IDMAC_DES0_ER (1 << 5)
+#define DW_MMC_IDMAC_DES0_CES (1 << 30)
+#define DW_MMC_IDMAC_DES0_OWN (1 << 31)
+#define DW_MMC_IDMAC_DES1_BS1(x) ((x) & 0x1fff)
+#define DW_MMC_IDMAC_DES2_BS2(x) (((x) & 0x1fff) << 13)
+#define DW_MMC_IDMAC_SWRESET (1 << 0)
+#define DW_MMC_IDMAC_FB (1 << 1)
+#define DW_MMC_IDMAC_ENABLE (1 << 7)
+
+#define DW_MMC_CTRL_RESET (1 << 0)
+#define DW_MMC_CTRL_FIFO_RESET (1 << 1)
+#define DW_MMC_CTRL_DMA_RESET (1 << 2)
+#define DW_MMC_CTRL_INT_EN (1 << 4)
+#define DW_MMC_CTRL_DMA_EN (1 << 5)
+#define DW_MMC_CTRL_IDMAC_EN (1 << 25)
+#define DW_MMC_CTRL_RESET_ALL (DW_MMC_CTRL_RESET | DW_MMC_CTRL_FIFO_RESET | DW_MMC_CTRL_DMA_RESET)
+
+#define DW_MMC_STS_DATA_BUSY (1 << 9)
+#define DW_MMC_STS_FIFO_COUNT(x) (((x) & 0x1fff) << 17) /* Number of filled locations in FIFO */
+#define GET_STS_FIFO_COUNT(x) (((x) >> 17) & 0x1fff)
+#define DW_MMC_STS_FIFO_FULL(x) (((x) >> 3) & 1)
+
+#define DW_MMC_BMOD_SWR (1 << 0) /* Software Reset */
+#define DW_MMC_BMOD_FB (1 << 1) /* Fix Burst */
+#define DW_MMC_BMOD_DE (1 << 7) /* IDMAC Enable */
+
+#define DW_MMC_IDSTS_TI (1 << 0) /* Transmit Interrupt */
+#define DW_MMC_IDSTS_RI (1 << 1) /* Receive Interrupt */
+
+#define DW_MMC_FIFO_TWMARK(x) ((x) & 0xfff)
+#define DW_MMC_FIFO_RWMARK(x) (((x) & 0x1ff) << 16)
+#define DW_MMC_DMA_BURST_SIZE(x) (((x) & 0x7) << 28)
+
+#define DW_MMC_CARD_RD_THR(x) (((x) & 0xfff) << 16)
+#define DW_MMC_CARD_RD_THR_EN (1 << 0)
+
+#define UHS_DDR_MODE (1 << 16)
+
+#define GENCLK_DIV 7
+
+#define DW_MMC_GPIO_CLK_DIV(x) (((x) & 0xf) << 8)
+#define DW_MMC_GPIO_USE_SAMPLE_DLY(x) (((x) & 1) << 13)
+#define DW_MMC_GPIO_CLK_ENABLE BIT16
+
+#define UHSEXT_SAMPLE_PHASE(x) (((x) & 0x1f) << 16)
+#define UHSEXT_SAMPLE_DRVPHASE(x) (((x) & 0x1f) << 21)
+#define UHSEXT_SAMPLE_DLY(x) (((x) & 0x1f) << 26)
+
+#define DWMMC_DMA_BUF_SIZE (512 * 8)
+#define DWMMC_FIFO_THRESHOLD 16
+
+#define DWMMC_INIT_CLOCK_FREQ 400 /* KHz */
+
+//
+// The transfer modes supported by SD Host Controller
+// Simplified Spec 3.0 Table 1-2
+//
+typedef enum {
+ SdMmcNoData,
+ SdMmcPioMode,
+ SdMmcSdmaMode,
+ SdMmcAdmaMode
+} DW_MMC_HC_TRANSFER_MODE;
+
+//
+// The maximum data length of each descriptor line
+//
+#define ADMA_MAX_DATA_PER_LINE 0x10000
+
+typedef struct {
+ UINT32 Des0;
+ UINT32 Des1;
+ UINT32 Des2;
+ UINT32 Des3;
+} DW_MMC_HC_DMA_DESC_LINE;
+
+#define SD_MMC_SDMA_BOUNDARY 512 * 1024
+#define SD_MMC_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1))
+
+typedef struct {
+ UINT8 FirstBar:3; // bit 0:2
+ UINT8 Reserved:1; // bit 3
+ UINT8 SlotNum:3; // bit 4:6
+ UINT8 Reserved1:1; // bit 7
+} DW_MMC_HC_SLOT_INFO;
+
+/**
+ Dump the content of SD/MMC host controller's Capability Register.
+
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Capability The buffer to store the capability data.
+
+**/
+VOID
+DumpCapabilityReg (
+ IN UINT8 Slot,
+ IN DW_MMC_HC_SLOT_CAP *Capability
+ );
+
+#if 0
+/**
+ Read SlotInfo register from SD/MMC host controller pci config space.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[out] FirstBar The buffer to store the first BAR value.
+ @param[out] SlotNum The buffer to store the supported slot number.
+
+ @retval EFI_SUCCESS The operation succeeds.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcGetSlotInfo (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ OUT UINT8 *FirstBar,
+ OUT UINT8 *SlotNum
+ );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+ Read/Write specified SD/MMC host controller mmio register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Read A boolean to indicate it's read or write operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in, out] Data For read operations, the destination buffer to store
+ the results. For write operations, the source buffer
+ to write data from. The caller is responsible for
+ having ownership of the data buffer and ensuring its
+ size not less than Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The read/write operation succeeds.
+ @retval Others The read/write operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcRwMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN BOOLEAN Read,
+ IN UINT8 Count,
+ IN OUT VOID *Data
+ );
+#else
+/**
+ Read/Write specified SD/MMC host controller mmio register.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Read A boolean to indicate it's read or write operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in, out] Data For read operations, the destination buffer to store
+ the results. For write operations, the source buffer
+ to write data from. The caller is responsible for
+ having ownership of the data buffer and ensuring its
+ size not less than Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The read/write operation succeeds.
+ @retval Others The read/write operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcRwMmio (
+ IN UINTN DevBase,
+ IN UINT32 Offset,
+ IN BOOLEAN Read,
+ IN UINT8 Count,
+ IN OUT VOID *Data
+ );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+ Do OR operation with the value of the specified SD/MMC host controller mmio register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in] OrData The pointer to the data used to do OR operation.
+ The caller is responsible for having ownership of
+ the data buffer and ensuring its size not less than
+ Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The OR operation succeeds.
+ @retval Others The OR operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcOrMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN VOID *OrData
+ );
+#else
+/**
+ Do OR operation with the value of the specified SD/MMC host controller mmio register.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in] OrData The pointer to the data used to do OR operation.
+ The caller is responsible for having ownership of
+ the data buffer and ensuring its size not less than
+ Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The OR operation succeeds.
+ @retval Others The OR operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcOrMmio (
+ IN UINTN DevBase,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN VOID *OrData
+ );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+ Do AND operation with the value of the specified SD/MMC host controller mmio register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in] AndData The pointer to the data used to do AND operation.
+ The caller is responsible for having ownership of
+ the data buffer and ensuring its size not less than
+ Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The AND operation succeeds.
+ @retval Others The AND operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcAndMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN VOID *AndData
+ );
+#else
+/**
+ Do AND operation with the value of the specified SD/MMC host controller mmio register.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2 , 4 or 8 bytes.
+ @param[in] AndData The pointer to the data used to do AND operation.
+ The caller is responsible for having ownership of
+ the data buffer and ensuring its size not less than
+ Count bytes.
+
+ @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid.
+ @retval EFI_SUCCESS The AND operation succeeds.
+ @retval Others The AND operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcAndMmio (
+ IN UINTN DevBase,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN VOID *AndData
+ );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+ Wait for the value of the specified MMIO register set to the test value.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] BarIndex The BAR index of the standard PCI Configuration
+ header to use as the base address for the memory
+ operation to perform.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2, 4 or 8 bytes.
+ @param[in] MaskValue The mask value of memory.
+ @param[in] TestValue The test value of memory.
+ @param[in] Timeout The time out value for wait memory set, uses 1
+ microsecond as a unit.
+
+ @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout
+ range.
+ @retval EFI_SUCCESS The MMIO register has expected value.
+ @retval Others The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcWaitMmioSet (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN UINT64 MaskValue,
+ IN UINT64 TestValue,
+ IN UINT64 Timeout
+ );
+#else
+/**
+ Wait for the value of the specified MMIO register set to the test value.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] Offset The offset within the selected BAR to start the
+ memory operation.
+ @param[in] Count The width of the mmio register in bytes.
+ Must be 1, 2, 4 or 8 bytes.
+ @param[in] MaskValue The mask value of memory.
+ @param[in] TestValue The test value of memory.
+ @param[in] Timeout The time out value for wait memory set, uses 1
+ microsecond as a unit.
+
+ @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout
+ range.
+ @retval EFI_SUCCESS The MMIO register has expected value.
+ @retval Others The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcWaitMmioSet (
+ IN UINTN DevBase,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN UINT64 MaskValue,
+ IN UINT64 TestValue,
+ IN UINT64 Timeout
+ );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+ Software reset the specified SD/MMC host controller.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The software reset executes successfully.
+ @retval Others The software reset fails.
+
+**/
+EFI_STATUS
+DwMmcHcReset (
+fark
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN DW_MMC_HC_SLOT_CAP Capability
+ );
+#else
+/**
+ Software reset the specified SD/MMC host controller.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+
+ @retval EFI_SUCCESS The software reset executes successfully.
+ @retval Others The software reset fails.
+
+**/
+EFI_STATUS
+DwMmcHcReset (
+ IN UINTN DevBase,
+ IN DW_MMC_HC_SLOT_CAP Capability
+ );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+ Set all interrupt status bits in Normal and Error Interrupt Status Enable
+ register.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+DwMmcHcEnableInterrupt (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ );
+#else
+/**
+ Set all interrupt status bits in Normal and Error Interrupt Status Enable
+ register.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+DwMmcHcEnableInterrupt (
+ IN UINTN DevBase
+ );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+ Get the capability data from the specified slot.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] Capability The buffer to store the capability data.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+DwMmcHcGetCapability (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_HANDLE Controller,
+ IN UINT8 Slot,
+ OUT DW_MMC_HC_SLOT_CAP *Capability
+ );
+#else
+/**
+ Get the capability data from the specified slot.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] Capability The buffer to store the capability data.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+DwMmcHcGetCapability (
+ IN UINTN DevBase,
+ IN EFI_HANDLE Controller,
+ IN UINT8 Slot,
+ OUT DW_MMC_HC_SLOT_CAP *Capability
+ );
+#endif
+
+#if 0
+/**
+ Get the maximum current capability data from the specified slot.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] MaxCurrent The buffer to store the maximum current capability data.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+DwMmcHcGetMaxCurrent (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT UINT64 *MaxCurrent
+ );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+ Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller
+ slot.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] MediaPresent The pointer to the media present boolean value.
+
+ @retval EFI_SUCCESS There is no media change happened.
+ @retval EFI_MEDIA_CHANGED There is media change happened.
+ @retval Others The detection fails.
+
+**/
+EFI_STATUS
+DwMmcHcCardDetect (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_HANDLE Controller,
+ IN UINT8 Slot,
+ OUT BOOLEAN *MediaPresent
+ );
+#else
+/**
+ Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller
+ slot.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] MediaPresent The pointer to the media present boolean value.
+
+ @retval EFI_SUCCESS There is no media change happened.
+ @retval EFI_MEDIA_CHANGED There is media change happened.
+ @retval Others The detection fails.
+
+**/
+EFI_STATUS
+DwMmcHcCardDetect (
+ IN UINTN DevBase,
+ IN EFI_HANDLE Controller,
+ IN UINT8 Slot,
+ OUT BOOLEAN *MediaPresent
+ );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+ Stop SD/MMC card clock.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS Succeed to stop SD/MMC clock.
+ @retval Others Fail to stop SD/MMC clock.
+
+**/
+EFI_STATUS
+DwMmcHcStopClock (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ );
+
+/**
+ SD/MMC card clock supply.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcClockSupply (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN UINT64 ClockFreq,
+ IN DW_MMC_HC_SLOT_CAP Capability
+ );
+#else
+/**
+ Stop SD/MMC card clock.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+
+ @retval EFI_SUCCESS Succeed to stop SD/MMC clock.
+ @retval Others Fail to stop SD/MMC clock.
+
+**/
+EFI_STATUS
+DwMmcHcStopClock (
+ IN UINTN DevBase
+ );
+
+/**
+ SD/MMC card clock supply.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcClockSupply (
+ IN UINTN DevBase,
+ IN UINT64 ClockFreq,
+ IN DW_MMC_HC_SLOT_CAP Capability
+ );
+#endif
+
+#if 0
+/**
+ SD/MMC bus power control.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] PowerCtrl The value setting to the power control register.
+
+ @retval TRUE There is a SD/MMC card attached.
+ @retval FALSE There is no a SD/MMC card attached.
+
+**/
+EFI_STATUS
+DwMmcHcPowerControl (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN UINT8 PowerCtrl
+ );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+ Set the SD/MMC bus width.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] BusWidth The bus width used by the SD/MMC device, it must be 1, 4 or 8.
+
+ @retval EFI_SUCCESS The bus width is set successfully.
+ @retval Others The bus width isn't set successfully.
+
+**/
+EFI_STATUS
+DwMmcHcSetBusWidth (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN BOOLEAN IsDdr,
+ IN UINT16 BusWidth
+ );
+#else
+/**
+ Set the SD/MMC bus width.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] BusWidth The bus width used by the SD/MMC device, it must be 1, 4 or 8.
+
+ @retval EFI_SUCCESS The bus width is set successfully.
+ @retval Others The bus width isn't set successfully.
+
+**/
+EFI_STATUS
+DwMmcHcSetBusWidth (
+ IN UINTN DevBase,
+ IN BOOLEAN IsDdr,
+ IN UINT16 BusWidth
+ );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+ Supply SD/MMC card with lowest clock frequency at initialization.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitClockFreq (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN DW_MMC_HC_SLOT_CAP Capability
+ );
+#else
+/**
+ Supply SD/MMC card with lowest clock frequency at initialization.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitClockFreq (
+ IN UINTN DevBase,
+ IN DW_MMC_HC_SLOT_CAP Capability
+ );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+ Supply SD/MMC card with maximum voltage at initialization.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The voltage is supplied successfully.
+ @retval Others The voltage isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitPowerVoltage (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN DW_MMC_HC_SLOT_CAP Capability
+ );
+#else
+/**
+ Supply SD/MMC card with maximum voltage at initialization.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The voltage is supplied successfully.
+ @retval Others The voltage isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitPowerVoltage (
+ IN UINTN DevBase,
+ IN DW_MMC_HC_SLOT_CAP Capability
+ );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+ Initialize the Timeout Control register with most conservative value at initialization.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The timeout control register is configured successfully.
+ @retval Others The timeout control register isn't configured successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitTimeoutCtrl (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ );
+#else
+/**
+ Initialize the Timeout Control register with most conservative value at initialization.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The timeout control register is configured successfully.
+ @retval Others The timeout control register isn't configured successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitTimeoutCtrl (
+ IN UINTN DevBase
+ );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+ Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value
+ at initialization.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The host controller is initialized successfully.
+ @retval Others The host controller isn't initialized successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitHost (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN DW_MMC_HC_SLOT_CAP Capability
+ );
+#else
+/**
+ Initial SD/MMC host controller with lowest clock frequency, max power and
+ max timeout value at initialization.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The host controller is initialized successfully.
+ @retval Others The host controller isn't initialized successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitHost (
+ IN UINTN DevBase,
+ IN DW_MMC_HC_SLOT_CAP Capability
+ );
+#endif
+
+#endif /* _DW_MMC_HCI_H_ */
diff --git a/EmbeddedPkg/Include/Protocol/PlatformDwMmc.h b/EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
new file mode 100644
index 000000000000..acbc3e153dac
--- /dev/null
+++ b/EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
@@ -0,0 +1,79 @@
+/** @file
+
+ Copyright (c) 2018, Linaro. All rights reserved.
+
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PLATFORM_DW_MMC_H__
+#define __PLATFORM_DW_MMC_H__
+
+typedef enum {
+ RemovableSlot,
+ EmbeddedSlot,
+ SharedBusSlot,
+ UnknownSlot
+} EFI_SD_MMC_SLOT_TYPE;
+
+typedef enum {
+ UnknownCardType,
+ SdCardType,
+ SdioCardType,
+ MmcCardType,
+ EmmcCardType
+} SD_MMC_CARD_TYPE;
+
+typedef struct {
+ UINT32 DefaultSpeed:1; // bit 0
+ UINT32 HighSpeed:1; // bit 1
+ UINT32 Sdr12:1; // bit 2
+ UINT32 Sdr25:1; // bit 3
+ UINT32 Sdr50:1; // bit 4
+ UINT32 Sdr104:1; // bit 5
+ UINT32 Ddr50:1; // bit 6
+ UINT32 SysBus64:1; // bit 7
+ UINT32 BusWidth:4; // bit 11:8
+ UINT32 SlotType:2; // bit 13:12
+ UINT32 CardType:3; // bit 16:14
+ UINT32 Voltage18:1; // bit 17
+ UINT32 Voltage30:1; // bit 18
+ UINT32 Voltage33:1; // bit 19
+ UINT32 BaseClkFreq;
+ EFI_HANDLE Controller;
+} DW_MMC_HC_SLOT_CAP;
+
+//
+// Protocol interface structure
+//
+typedef struct _PLATFORM_DW_MMC_PROTOCOL PLATFORM_DW_MMC_PROTOCOL;
+
+typedef
+EFI_STATUS
+(EFIAPI *PLATFORM_DW_MMC_GET_CAPABILITY) (
+ IN EFI_HANDLE Controller,
+ IN UINT8 Slot,
+ OUT DW_MMC_HC_SLOT_CAP *Capability
+ );
+
+typedef
+BOOLEAN
+(EFIAPI *PLATFORM_DW_MMC_CARD_DETECT) (
+ IN EFI_HANDLE Controller,
+ IN UINT8 Slot
+ );
+
+struct _PLATFORM_DW_MMC_PROTOCOL {
+ PLATFORM_DW_MMC_GET_CAPABILITY GetCapability;
+ PLATFORM_DW_MMC_CARD_DETECT CardDetect;
+};
+
+extern EFI_GUID gPlatformDwMmcProtocolGuid;
+
+#endif /* __PLATFORM_DW_MMC_H__ */
diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c b/EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
new file mode 100644
index 000000000000..1edade69d091
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
@@ -0,0 +1,214 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for Designware SD/MMC host
+ controller driver.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2018, Linaro Ltd. 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 "DwMmcHcDxe.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gDwMmcHcComponentName = {
+ DwMmcHcComponentNameGetDriverName,
+ DwMmcHcComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gDwMmcHcComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) DwMmcHcComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) DwMmcHcComponentNameGetControllerName,
+ "en"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mDwMmcHcDriverNameTable[] = {
+ { "eng;en", L"Designware Sd/Mmc Host Controller Driver" },
+ { NULL , NULL }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mDwMmcHcControllerNameTable[] = {
+ { "eng;en", L"Designware Sd/Mmc Host Controller" },
+ { NULL , NULL }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name 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. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] 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
+DwMmcHcComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mDwMmcHcDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gDwMmcHcComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] 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 ChildHandle[in] 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 Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name 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. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] 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
+DwMmcHcComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle, OPTIONAL
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ if (Language == NULL || ControllerName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gDwMmcHcDriverBinding.DriverBindingHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mDwMmcHcControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gDwMmcHcComponentName)
+ );
+}
diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
new file mode 100644
index 000000000000..aea12170d2cc
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
@@ -0,0 +1,1296 @@
+/** @file
+ This driver is used to manage Designware SD/MMC host controller.
+
+ It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.
+
+ Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
+ Copyright (C) 2016 Marvell International Ltd. All rigths reserved.<BR>
+ Copyright (C) 2018, Linaro Ltd. All rigths 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 <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Protocol/NonDiscoverableDevice.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/PlatformDwMmc.h>
+
+#include "DwMmcHcDxe.h"
+
+//
+// Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gDwMmcHcDriverBinding = {
+ DwMmcHcDriverBindingSupported,
+ DwMmcHcDriverBindingStart,
+ DwMmcHcDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+//
+// Template for Designware SD/MMC host controller private data.
+//
+DW_MMC_HC_PRIVATE_DATA gDwMmcHcTemplate = {
+ DW_MMC_HC_PRIVATE_SIGNATURE, // Signature
+ NULL, // ControllerHandle
+ 0x0, // Mmio base address
+ { // PassThru
+ sizeof (UINT32),
+ DwMmcPassThruPassThru,
+ DwMmcPassThruGetNextSlot,
+ DwMmcPassThruBuildDevicePath,
+ DwMmcPassThruGetSlotNumber,
+ DwMmcPassThruResetDevice
+ },
+ NULL, // PlatformDwMmc
+ 0, // PreviousSlot
+ NULL, // TimerEvent
+ NULL, // ConnectEvent
+ // Queue
+ INITIALIZE_LIST_HEAD_VARIABLE (gDwMmcHcTemplate.Queue),
+ { // Slot
+ {0, UnknownSlot, 0, 0, 0}
+ },
+ { // Capability
+ {0}
+ },
+ { // MaxCurrent
+ 0
+ },
+ 0 // ControllerVersion
+};
+
+SD_DEVICE_PATH mSdDpTemplate = {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_SD_DP,
+ {
+ (UINT8) (sizeof (SD_DEVICE_PATH)),
+ (UINT8) ((sizeof (SD_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0
+};
+
+EMMC_DEVICE_PATH mEmmcDpTemplate = {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_EMMC_DP,
+ {
+ (UINT8) (sizeof (EMMC_DEVICE_PATH)),
+ (UINT8) ((sizeof (EMMC_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0
+};
+
+//
+// Prioritized function list to detect card type.
+// User could add other card detection logic here.
+//
+DWMMC_CARD_TYPE_DETECT_ROUTINE mCardTypeDetectRoutineTable[] = {
+ EmmcIdentification,
+ SdCardIdentification,
+ NULL
+};
+
+/**
+ The entry point for SD host controller driver, used to install this driver on the ImageHandle.
+
+ @param[in] ImageHandle The firmware allocated handle for this driver image.
+ @param[in] SystemTable Pointer to the EFI system table.
+
+ @retval EFI_SUCCESS Driver loaded.
+ @retval other Driver not loaded.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeDwMmcHcDxe (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gDwMmcHcDriverBinding,
+ ImageHandle,
+ &gDwMmcHcComponentName,
+ &gDwMmcHcComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Call back function when the timer event is signaled.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the
+ Event.
+
+**/
+VOID
+EFIAPI
+ProcessAsyncTaskList (
+ IN EFI_EVENT Event,
+ IN VOID* Context
+ )
+{
+ DW_MMC_HC_PRIVATE_DATA *Private;
+ LIST_ENTRY *Link;
+ DW_MMC_HC_TRB *Trb;
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ BOOLEAN InfiniteWait;
+ EFI_EVENT TrbEvent;
+
+ Private = (DW_MMC_HC_PRIVATE_DATA *)Context;
+
+ //
+ // Check if the first entry in the async I/O queue is done or not.
+ //
+ Status = EFI_SUCCESS;
+ Trb = NULL;
+ Link = GetFirstNode (&Private->Queue);
+ if (!IsNull (&Private->Queue, Link)) {
+ Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
+ if (!Private->Slot[Trb->Slot].MediaPresent) {
+ Status = EFI_NO_MEDIA;
+ goto Done;
+ }
+ if (!Trb->Started) {
+ //
+ // Check whether the cmd/data line is ready for transfer.
+ //
+ Status = DwMmcCheckTrbEnv (Private, Trb);
+ if (!EFI_ERROR (Status)) {
+ Trb->Started = TRUE;
+ Status = DwMmcExecTrb (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ } else {
+ goto Done;
+ }
+ }
+ Status = DwMmcCheckTrbResult (Private, Trb);
+ }
+
+Done:
+ if ((Trb != NULL) && (Status == EFI_NOT_READY)) {
+ Packet = Trb->Packet;
+ if (Packet->Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+ if ((!InfiniteWait) && (Trb->Timeout-- == 0)) {
+ RemoveEntryList (Link);
+ Trb->Packet->TransactionStatus = EFI_TIMEOUT;
+ TrbEvent = Trb->Event;
+ DwMmcFreeTrb (Trb);
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT\n",
+ TrbEvent
+ ));
+ gBS->SignalEvent (TrbEvent);
+ return;
+ }
+ }
+ if ((Trb != NULL) && (Status != EFI_NOT_READY)) {
+ RemoveEntryList (Link);
+ Trb->Packet->TransactionStatus = Status;
+ TrbEvent = Trb->Event;
+ DwMmcFreeTrb (Trb);
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "ProcessAsyncTaskList(): Signal Event %p with %r\n",
+ TrbEvent,
+ Status
+ ));
+ gBS->SignalEvent (TrbEvent);
+ }
+ return;
+}
+
+/**
+ Sd removable device enumeration callback function when the timer event is signaled.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the
+ Event.
+
+**/
+VOID
+EFIAPI
+DwMmcHcEnumerateDevice (
+ IN EFI_EVENT Event,
+ IN VOID* Context
+ )
+{
+ DW_MMC_HC_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+ BOOLEAN MediaPresent;
+ UINT32 RoutineNum;
+ DWMMC_CARD_TYPE_DETECT_ROUTINE *Routine;
+ UINTN Index;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ DW_MMC_HC_TRB *Trb;
+ EFI_TPL OldTpl;
+
+ Private = (DW_MMC_HC_PRIVATE_DATA *)Context;
+
+ if ((Private->Slot[0].Enable) &&
+ (Private->Slot[0].SlotType == RemovableSlot)) {
+ Status = DwMmcHcCardDetect (
+ Private->DevBase,
+ Private->ControllerHandle,
+ 0,
+ &MediaPresent
+ );
+ if ((Status == EFI_MEDIA_CHANGED) && !MediaPresent) {
+ DEBUG ((
+ DEBUG_INFO,
+ "DwMmcHcEnumerateDevice: device disconnected at %p\n",
+ Private->DevBase
+ ));
+ Private->Slot[0].MediaPresent = FALSE;
+ //
+ // Signal all async task events at the slot with EFI_NO_MEDIA status.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ for (Link = GetFirstNode (&Private->Queue);
+ !IsNull (&Private->Queue, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Private->Queue, Link);
+ Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
+ if (Trb->Slot == 0) {
+ RemoveEntryList (Link);
+ Trb->Packet->TransactionStatus = EFI_NO_MEDIA;
+ gBS->SignalEvent (Trb->Event);
+ DwMmcFreeTrb (Trb);
+ }
+ }
+ gBS->RestoreTPL (OldTpl);
+ //
+ // Notify the upper layer the connect state change through
+ // ReinstallProtocolInterface.
+ //
+ gBS->ReinstallProtocolInterface (
+ Private->ControllerHandle,
+ &gEfiSdMmcPassThruProtocolGuid,
+ &Private->PassThru,
+ &Private->PassThru
+ );
+ }
+ if ((Status == EFI_MEDIA_CHANGED) && MediaPresent) {
+ DEBUG ((
+ DEBUG_INFO,
+ "DwMmcHcEnumerateDevice: device connected at %p\n",
+ Private->DevBase
+ ));
+ //
+ // Initialize slot and start identification process for the new
+ // attached device
+ //
+ Status = DwMmcHcInitHost (Private->DevBase, Private->Capability[0]);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ //
+ // Reset the specified slot of the SD/MMC Pci Host Controller
+ //
+ Status = DwMmcHcReset (Private->DevBase, Private->Capability[0]);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ Private->Slot[0].MediaPresent = TRUE;
+ RoutineNum = sizeof (mCardTypeDetectRoutineTable) /
+ sizeof (DWMMC_CARD_TYPE_DETECT_ROUTINE);
+ for (Index = 0; Index < RoutineNum; Index++) {
+ Routine = &mCardTypeDetectRoutineTable[Index];
+ if (*Routine != NULL) {
+ Status = (*Routine) (Private);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ }
+ //
+ // This card doesn't get initialized correctly.
+ //
+ if (Index == RoutineNum) {
+ return;
+ }
+
+ //
+ // Notify the upper layer the connect state change through
+ // ReinstallProtocolInterface.
+ //
+ gBS->ReinstallProtocolInterface (
+ Private->ControllerHandle,
+ &gEfiSdMmcPassThruProtocolGuid,
+ &Private->PassThru,
+ &Private->PassThru
+ );
+ }
+ }
+
+ return;
+}
+
+/**
+ Reset the specified SD/MMC host controller and enable all interrupts.
+
+ @param[in] DevBase The Mmio Device Base Address.
+
+ @retval EFI_SUCCESS The software reset executes successfully.
+ @retval Others The software reset fails.
+
+**/
+EFI_STATUS
+DwMmcHcReset (
+ IN UINTN DevBase,
+ IN DW_MMC_HC_SLOT_CAP Capability
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlkSize;
+
+ //
+ // Enable all interrupt after reset all.
+ //
+ Status = DwMmcHcEnableInterrupt (DevBase);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "DwMmcHcReset: enable interrupts fail: %r\n", Status));
+ return Status;
+ }
+ Status = DwMmcHcInitTimeoutCtrl (DevBase);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BlkSize = DW_MMC_BLOCK_SIZE;
+ MmioWrite32 (DevBase + DW_MMC_BLKSIZ, BlkSize);
+
+ Status = DwMmcHcInitClockFreq (DevBase, Capability);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = DwMmcHcSetBusWidth (DevBase, FALSE, 1);
+
+ return Status;
+}
+
+/**
+ Tests to see if this driver supports a given controller. If a child device
+ is provided, it further tests to see if this driver supports creating a
+ handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the
+ device specified by ControllerHandle. Drivers will typically use the device
+ path attached to ControllerHandle and/or the services from the bus I/O
+ abstraction attached to ControllerHandle to determine if the driver supports
+ ControllerHandle. This function may be called many times during platform
+ initialization. In order to reduce boot times, the tests performed by this
+ function must be very small, and take as little time as possible to execute.
+ This function must not change the state of any hardware devices, and this
+ function must be aware that the device specified by ControllerHandle may
+ already be managed by the same driver or a different driver. This function
+ must match its calls to AllocatePages() with FreePages(), AllocatePool() with
+ FreePool(), and OpenProtocol() with CloseProtocol(). Since ControllerHandle
+ may have been previously started by the same driver, if a protocol is already
+ in the opened state, then it must not be closed with CloseProtocol(). This is
+ required to guarantee the state of ControllerHandle is not modified by this
+ function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param[in] ControllerHandle The handle of the controller to test. This
+ handle must support a protocol interface that
+ supplies an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a
+ device path. This parameter is ignored by
+ device drivers, and is optional for bus
+ drivers. For bus drivers, if this parameter
+ is not NULL, then the bus driver must deter-
+ mine if the bus controller specified by
+ ControllerHandle and the child controller
+ specified by RemainingDevicePath are both
+ supported by this bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the
+ driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed
+ by the driver specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed
+ by a different driver or an application that
+ requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the
+ driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ NON_DISCOVERABLE_DEVICE *Dev;
+ PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc;
+
+ ParentDevicePath = NULL;
+
+ Status = gBS->LocateProtocol (
+ &gPlatformDwMmcProtocolGuid,
+ NULL,
+ (VOID **) &PlatformDwMmc
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID *) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // EFI_ALREADY_STARTED is also an error.
+ //
+ return Status;
+ }
+ //
+ // Close the protocol because we don't use it here.
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Now test the EmbeddedNonDiscoverableIoProtocol.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEdkiiNonDiscoverableDeviceProtocolGuid,
+ (VOID **) &Dev,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ gBS->CloseProtocol (
+ Controller,
+ &gEdkiiNonDiscoverableDeviceProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_SUCCESS;
+}
+
+/**
+ Starts a device controller or a bus controller.
+
+ The Start() function is designed to be invoked from the EFI boot service
+ ConnectController().
+ As a result, much of the error checking on the parameters to Start() has
+ been moved into this
+ common boot service. It is legal to call Start() from other locations,
+ but the following calling restrictions must be followed or the system
+ behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a
+ naturally aligned EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver
+ specified by This must have been called with the same calling parameters,
+ and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param[in] ControllerHandle The handle of the controller to start. This
+ handle must support a protocol interface
+ that supplies an I/O abstraction to the
+ driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a
+ device path. This parameter is ignored by
+ device drivers, and is optional for bus
+ drivers.
+ For a bus driver, if this parameter is NULL,
+ then handles for all the children of
+ Controller are created by this driver.
+ If this parameter is not NULL and the first
+ Device Path Node is not the End of Device
+ Path Node, then only the handle for the
+ child device specified by the first Device
+ Path Node of RemainingDevicePath is created
+ by this driver.
+ If the first Device Path Node of
+ RemainingDevicePath is the End of Device Path
+ Node, no child handle is created by this
+ driver.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a
+ device error. Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+ @retval Others The driver failded to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ DW_MMC_HC_PRIVATE_DATA *Private;
+
+ NON_DISCOVERABLE_DEVICE *Dev;
+
+ BOOLEAN MediaPresent;
+ DWMMC_CARD_TYPE_DETECT_ROUTINE *Routine;
+ UINT8 Index;
+ UINT32 RoutineNum;
+ PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc;
+
+ Status = gBS->LocateProtocol (
+ &gPlatformDwMmcProtocolGuid,
+ NULL,
+ (VOID **) &PlatformDwMmc
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "err %d", __LINE__));
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEdkiiNonDiscoverableDeviceProtocolGuid,
+ (VOID **) &Dev,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "err %d", __LINE__));
+ return Status;
+ }
+
+ Private = AllocateCopyPool (sizeof (DW_MMC_HC_PRIVATE_DATA), &gDwMmcHcTemplate);
+ if (Private == NULL) {
+ DEBUG ((DEBUG_ERROR, "err %d", __LINE__));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Private->ControllerHandle = Controller;
+ Private->DevBase = Dev->Resources[0].AddrRangeMin;
+ Private->PlatformDwMmc = PlatformDwMmc;
+ InitializeListHead (&Private->Queue);
+
+ Status = Private->PlatformDwMmc->GetCapability (Controller, 0, &Private->Capability[0]);
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Private->Capability[0].BaseClkFreq == 0) {
+ goto Done;
+ }
+
+ DumpCapabilityReg (0, &Private->Capability[0]);
+
+ MediaPresent = FALSE;
+
+ Status = Private->PlatformDwMmc->CardDetect (Controller, 0);
+ Status = DwMmcHcCardDetect (Private->DevBase, Controller, 0, &MediaPresent);
+ if (MediaPresent == FALSE) {
+ goto Done;
+ }
+
+ //
+ // Initialize slot and start identification process for the new attached device
+ //
+ Status = DwMmcHcInitHost (Private->DevBase, Private->Capability[0]);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Reset HC
+ //
+ Status = DwMmcHcReset (Private->DevBase, Private->Capability[0]);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Private->Slot[0].CardType = Private->Capability[0].CardType;
+ Private->Slot[0].Enable = TRUE;
+ Private->Slot[0].MediaPresent = TRUE;
+
+ RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (DWMMC_CARD_TYPE_DETECT_ROUTINE);
+ for (Index = 0; Index < RoutineNum; Index++) {
+ Routine = &mCardTypeDetectRoutineTable[Index];
+ if (*Routine != NULL) {
+ Status = (*Routine) (Private);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ }
+
+ //
+ // Start the asynchronous I/O monitor
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ProcessAsyncTaskList,
+ Private,
+ &Private->TimerEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->SetTimer (Private->TimerEvent, TimerPeriodic, DW_MMC_HC_ASYNC_TIMER);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Start the Sd removable device connection enumeration
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ DwMmcHcEnumerateDevice,
+ Private,
+ &Private->ConnectEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->SetTimer (Private->ConnectEvent, TimerPeriodic, DW_MMC_HC_ENUM_TIMER);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ &(Private->PassThru),
+ NULL
+ );
+
+ DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStart: %r End on %x\n", Status, Controller));
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if ((Private != NULL) && (Private->TimerEvent != NULL)) {
+ gBS->CloseEvent (Private->TimerEvent);
+ }
+
+ if ((Private != NULL) && (Private->ConnectEvent != NULL)) {
+ gBS->CloseEvent (Private->ConnectEvent);
+ }
+
+ if (Private != NULL) {
+ FreePool (Private);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Stops a device controller or a bus controller.
+
+ The Stop() function is designed to be invoked from the EFI boot service
+ DisconnectController().
+ As a result, much of the error checking on the parameters to Stop() has been
+ moved into this common boot service. It is legal to call Stop() from other
+ locations, but the following calling restrictions must be followed or the
+ system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous
+ call to this same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+ EFI_HANDLE. In addition, all of these handles must have been created in
+ this driver's Start() function, and the Start() function must have called
+ OpenProtocol() on ControllerHandle with an Attribute of
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle
+ must support a bus specific I/O protocol for the
+ driver to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in
+ ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be
+ NULL if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device
+ error.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ DW_MMC_HC_PRIVATE_DATA *Private;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ DW_MMC_HC_TRB *Trb;
+
+ DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStop: Start\n"));
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID**) &PassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+ //
+ // Close Non-Blocking timer and free Task list.
+ //
+ if (Private->TimerEvent != NULL) {
+ gBS->CloseEvent (Private->TimerEvent);
+ Private->TimerEvent = NULL;
+ }
+ if (Private->ConnectEvent != NULL) {
+ gBS->CloseEvent (Private->ConnectEvent);
+ Private->ConnectEvent = NULL;
+ }
+ //
+ // As the timer is closed, there is no needs to use TPL lock to
+ // protect the critical region "queue".
+ //
+ for (Link = GetFirstNode (&Private->Queue);
+ !IsNull (&Private->Queue, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Private->Queue, Link);
+ RemoveEntryList (Link);
+ Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
+ Trb->Packet->TransactionStatus = EFI_ABORTED;
+ gBS->SignalEvent (Trb->Event);
+ DwMmcFreeTrb (Trb);
+ }
+
+ //
+ // Uninstall Block I/O protocol from the device handle
+ //
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ &(Private->PassThru)
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ FreePool (Private);
+
+ DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStop: End with %r\n", Status));
+
+ return Status;
+}
+
+/**
+ Sends SD command to an SD card that is attached to the SD controller.
+
+ The PassThru() function sends the SD command specified by Packet to the SD
+ card specified by Slot.
+
+ If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.
+
+ If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is
+ returned.
+
+ If Slot is not in a valid range for the SD controller, then
+ EFI_INVALID_PARAMETER is returned.
+
+ If Packet defines a data command but both InDataBuffer and OutDataBuffer are
+ NULL, EFI_INVALID_PARAMETER is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Slot The slot number of the SD card to send the
+ command to.
+ @param[in,out] Packet A pointer to the SD command data structure.
+ @param[in] Event If Event is NULL, blocking I/O is performed. If
+ Event is not NULL, then nonblocking I/O is
+ performed, and Event will be signaled when the
+ Packet completes.
+
+ @retval EFI_SUCCESS The SD Command Packet was sent by the host.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
+ the SD command Packet.
+ @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is
+ invalid.
+ @retval EFI_INVALID_PARAMETER Packet defines a data command but both
+ InDataBuffer and OutDataBuffer are NULL.
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.
+ @retval EFI_UNSUPPORTED The command described by the SD Command Packet
+ is not supported by the host controller.
+ @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength
+ exceeds the limit supported by SD card
+ ( i.e. if the number of bytes exceed the Last
+ LBA).
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruPassThru (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot,
+ IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ DW_MMC_HC_PRIVATE_DATA *Private;
+ DW_MMC_HC_TRB *Trb;
+ EFI_TPL OldTpl;
+
+ if ((This == NULL) || (Packet == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->SdMmcCmdBlk == NULL) || (Packet->SdMmcStatusBlk == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ if (!Private->Slot[Slot].Enable) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!Private->Slot[Slot].MediaPresent) {
+ return EFI_NO_MEDIA;
+ }
+
+ Trb = DwMmcCreateTrb (Private, Slot, Packet, Event);
+ if (Trb == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Immediately return for async I/O.
+ //
+ if (Event != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Wait async I/O list is empty before execute sync I/O operation.
+ //
+ while (TRUE) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ if (IsListEmpty (&Private->Queue)) {
+ gBS->RestoreTPL (OldTpl);
+ break;
+ }
+ gBS->RestoreTPL (OldTpl);
+ }
+
+ Status = DwMmcWaitTrbEnv (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = DwMmcExecTrb (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = DwMmcWaitTrbResult (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+Done:
+ if (Trb != NULL) {
+ DwMmcFreeTrb (Trb);
+ }
+
+ return Status;
+}
+
+/**
+ Used to retrieve next slot numbers supported by the SD controller. The
+ function returns information about all available slots (populated or
+ not-populated).
+
+ The GetNextSlot() function retrieves the next slot number on an SD controller.
+ If on input Slot is 0xFF, then the slot number of the first slot on the SD
+ controller is returned.
+
+ If Slot is a slot number that was returned on a previous call to
+ GetNextSlot(), then the slot number of the next slot on the SD controller is
+ returned.
+
+ If Slot is not 0xFF and Slot was not returned on a previous call to
+ GetNextSlot(), EFI_INVALID_PARAMETER is returned.
+
+ If Slot is the slot number of the last slot on the SD controller, then
+ EFI_NOT_FOUND is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in,out] Slot On input, a pointer to a slot number on the SD
+ controller.
+ On output, a pointer to the next slot number on
+ the SD controller.
+ An input value of 0xFF retrieves the first slot
+ number on the SD controller.
+
+ @retval EFI_SUCCESS The next slot number on the SD controller was
+ returned in Slot.
+ @retval EFI_NOT_FOUND There are no more slots on this SD controller.
+ @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a
+ previous call to GetNextSlot().
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruGetNextSlot (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 *Slot
+ )
+{
+ DW_MMC_HC_PRIVATE_DATA *Private;
+
+ if ((This == NULL) || (Slot == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ if (*Slot == 0xFF) {
+ if (Private->Slot[0].Enable) {
+ *Slot = 0;
+ Private->PreviousSlot = 0;
+ return EFI_SUCCESS;
+ }
+ return EFI_NOT_FOUND;
+ } else if (*Slot == Private->PreviousSlot) {
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+}
+
+/**
+ Used to allocate and build a device path node for an SD card on the SD
+ controller.
+
+ The BuildDevicePath() function allocates and builds a single device node
+ for the SD card specified by Slot.
+
+ If the SD card specified by Slot is not present on the SD controller, then
+ EFI_NOT_FOUND is returned.
+
+ If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.
+
+ If there are not enough resources to allocate the device path node, then
+ EFI_OUT_OF_RESOURCES is returned.
+
+ Otherwise, DevicePath is allocated with the boot service AllocatePool(),
+ the contents of DevicePath are initialized to describe the SD card specified
+ by Slot, and EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Slot Specifies the slot number of the SD card for
+ which a device path node is to be allocated and
+ built.
+ @param[in,out] DevicePath A pointer to a single device path node that
+ describes the SD card specified by Slot. This
+ function is responsible for allocating the
+ buffer DevicePath with the boot service
+ AllocatePool(). It is the caller's responsi-
+ bility to free DevicePath when the caller is
+ finished with DevicePath.
+
+ @retval EFI_SUCCESS The device path node that describes the SD card
+ specified by Slot was allocated and returned in
+ DevicePath.
+ @retval EFI_NOT_FOUND The SD card specified by Slot does not exist on
+ the SD controller.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate
+ DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruBuildDevicePath (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ DW_MMC_HC_PRIVATE_DATA *Private;
+ SD_DEVICE_PATH *SdNode;
+ EMMC_DEVICE_PATH *EmmcNode;
+
+ if ((This == NULL) || (DevicePath == NULL) || (Slot >= DW_MMC_HC_MAX_SLOT)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ if ((!Private->Slot[Slot].Enable) || (!Private->Slot[Slot].MediaPresent)) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Private->Slot[Slot].CardType == SdCardType) {
+ SdNode = AllocateCopyPool (sizeof (SD_DEVICE_PATH), &mSdDpTemplate);
+ if (SdNode == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ SdNode->SlotNumber = Slot;
+
+ *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) SdNode;
+ } else if (Private->Slot[Slot].CardType == EmmcCardType) {
+ EmmcNode = AllocateCopyPool (sizeof (EMMC_DEVICE_PATH), &mEmmcDpTemplate);
+ if (EmmcNode == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ EmmcNode->SlotNumber = Slot;
+
+ *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) EmmcNode;
+ } else {
+ //
+ // Currently we only support SD and EMMC two device nodes.
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function retrieves an SD card slot number based on the input device path.
+
+ The GetSlotNumber() function retrieves slot number for the SD card specified
+ by the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is
+ returned.
+
+ If DevicePath is not a device path node type that the SD Pass Thru driver
+ supports, EFI_UNSUPPORTED is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] DevicePath A pointer to the device path node that describes
+ a SD card on the SD controller.
+ @param[out] Slot On return, points to the slot number of an SD
+ card on the SD controller.
+
+ @retval EFI_SUCCESS SD card slot number is returned in Slot.
+ @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.
+ @retval EFI_UNSUPPORTED DevicePath is not a device path node type that
+ the SD Pass Thru driver supports.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruGetSlotNumber (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT8 *Slot
+ )
+{
+ DW_MMC_HC_PRIVATE_DATA *Private;
+ SD_DEVICE_PATH *SdNode;
+ EMMC_DEVICE_PATH *EmmcNode;
+ UINT8 SlotNumber;
+
+ if ((This == NULL) || (DevicePath == NULL) || (Slot == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ //
+ // Check whether the DevicePath belongs to SD_DEVICE_PATH or EMMC_DEVICE_PATH
+ //
+ if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
+ ((DevicePath->SubType != MSG_SD_DP) &&
+ (DevicePath->SubType != MSG_EMMC_DP)) ||
+ (DevicePathNodeLength(DevicePath) != sizeof(SD_DEVICE_PATH)) ||
+ (DevicePathNodeLength(DevicePath) != sizeof(EMMC_DEVICE_PATH))) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (DevicePath->SubType == MSG_SD_DP) {
+ SdNode = (SD_DEVICE_PATH *) DevicePath;
+ SlotNumber = SdNode->SlotNumber;
+ } else {
+ EmmcNode = (EMMC_DEVICE_PATH *) DevicePath;
+ SlotNumber = EmmcNode->SlotNumber;
+ }
+
+ if (SlotNumber >= DW_MMC_HC_MAX_SLOT) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Private->Slot[SlotNumber].Enable) {
+ *Slot = SlotNumber;
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+ Resets an SD card that is connected to the SD controller.
+
+ The ResetDevice() function resets the SD card specified by Slot.
+
+ If this SD controller does not support a device reset operation,
+ EFI_UNSUPPORTED is returned.
+
+ If Slot is not in a valid slot number for this SD controller,
+ EFI_INVALID_PARAMETER is returned.
+
+ If the device reset operation is completed, EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Slot Specifies the slot number of the SD card to be
+ reset.
+
+ @retval EFI_SUCCESS The SD card specified by Slot was reset.
+ @retval EFI_UNSUPPORTED The SD controller does not support a device
+ reset operation.
+ @retval EFI_INVALID_PARAMETER Slot number is invalid.
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.
+ @retval EFI_DEVICE_ERROR The reset command failed due to a device error
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruResetDevice (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot
+ )
+{
+ DW_MMC_HC_PRIVATE_DATA *Private;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ DW_MMC_HC_TRB *Trb;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ if (!Private->Slot[Slot].Enable) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!Private->Slot[Slot].MediaPresent) {
+ return EFI_NO_MEDIA;
+ }
+
+ //
+ // Free all async I/O requests in the queue
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ for (Link = GetFirstNode (&Private->Queue);
+ !IsNull (&Private->Queue, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Private->Queue, Link);
+ RemoveEntryList (Link);
+ Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
+ Trb->Packet->TransactionStatus = EFI_ABORTED;
+ gBS->SignalEvent (Trb->Event);
+ DwMmcFreeTrb (Trb);
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
new file mode 100644
index 000000000000..b091f9803b2e
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
@@ -0,0 +1,1602 @@
+/** @file
+ This driver is used to manage Designware SD/MMC PCI host controllers.
+
+ It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.
+
+ Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2018, Linaro Ltd. 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 <IndustryStandard/Emmc.h>
+#include <IndustryStandard/Sd.h>
+
+#include <Library/ArmLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DmaLib.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "DwMmcHcDxe.h"
+
+/**
+ Dump the content of SD/MMC host controller's Capability Register.
+
+ @param[in] Slot The slot number of the SD card to send the
+ command to.
+ @param[in] Capability The buffer to store the capability data.
+
+**/
+VOID
+DumpCapabilityReg (
+ IN UINT8 Slot,
+ IN DW_MMC_HC_SLOT_CAP *Capability
+ )
+{
+ //
+ // Dump Capability Data
+ //
+ DEBUG ((
+ DEBUG_INFO,
+ " == Slot [%d] Capability is 0x%x ==\n",
+ Slot,
+ Capability
+ ));
+ DEBUG ((
+ DEBUG_INFO,
+ " Base Clk Freq %dKHz\n",
+ Capability->BaseClkFreq
+ ));
+ DEBUG ((
+ DEBUG_INFO,
+ " BusWidth %d\n",
+ Capability->BusWidth
+ ));
+ DEBUG ((
+ DEBUG_INFO,
+ " HighSpeed Support %a\n",
+ Capability->HighSpeed ? "TRUE" : "FALSE"
+ ));
+ DEBUG ((
+ DEBUG_INFO,
+ " Voltage 1.8 %a\n",
+ Capability->Voltage18 ? "TRUE" : "FALSE"
+ ));
+ DEBUG ((
+ DEBUG_INFO,
+ " 64-bit Sys Bus %a\n",
+ Capability->SysBus64 ? "TRUE" : "FALSE"
+ ));
+ DEBUG ((DEBUG_INFO, " SlotType "));
+ if (Capability->SlotType == 0x00) {
+ DEBUG ((DEBUG_INFO, "%a\n", "Removable Slot"));
+ } else if (Capability->SlotType == 0x01) {
+ DEBUG ((DEBUG_INFO, "%a\n", "Embedded Slot"));
+ } else if (Capability->SlotType == 0x02) {
+ DEBUG ((DEBUG_INFO, "%a\n", "Shared Bus Slot"));
+ } else {
+ DEBUG ((DEBUG_INFO, "%a\n", "Reserved"));
+ }
+ DEBUG ((
+ DEBUG_INFO,
+ " SDR50 Support %a\n",
+ Capability->Sdr50 ? "TRUE" : "FALSE"
+ ));
+ DEBUG ((
+ DEBUG_INFO,
+ " SDR104 Support %a\n",
+ Capability->Sdr104 ? "TRUE" : "FALSE"
+ ));
+ DEBUG ((
+ DEBUG_INFO,
+ " DDR50 Support %a\n",
+ Capability->Ddr50 ? "TRUE" : "FALSE"
+ ));
+ return;
+}
+
+/**
+ Set all interrupt status bits in Normal and Error Interrupt Status Enable
+ register.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+DwMmcHcEnableInterrupt (
+ UINTN DevBase
+ )
+{
+ UINT32 IntStatus;
+ UINT32 IdIntEn;
+ UINT32 IdSts;
+
+ //
+ // Enable all bits in Interrupt Mask Register
+ //
+ IntStatus = 0;
+ MmioWrite32 (DevBase + DW_MMC_INTMASK, IntStatus);
+
+ //
+ // Clear status in Interrupt Status Register
+ //
+ IntStatus = ~0;
+ MmioWrite32 (DevBase + DW_MMC_RINTSTS, IntStatus);
+
+ IdIntEn = ~0;
+ MmioWrite32 (DevBase + DW_MMC_IDINTEN, IdIntEn);
+
+ IdSts = ~0;
+ MmioWrite32 (DevBase + DW_MMC_IDSTS, IdSts);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+DwMmcHcGetCapability (
+ IN UINTN DevBase,
+ IN EFI_HANDLE Controller,
+ IN UINT8 Slot,
+ OUT DW_MMC_HC_SLOT_CAP *Capacity
+ )
+{
+ PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc;
+ EFI_STATUS Status;
+
+ if (Capacity == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = gBS->LocateProtocol (
+ &gPlatformDwMmcProtocolGuid,
+ NULL,
+ (VOID **) &PlatformDwMmc
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = PlatformDwMmc->GetCapability (Controller, Slot, Capacity);
+ return Status;
+}
+
+/**
+ Detect whether there is a SD/MMC card attached at the specified SD/MMC host
+ controller slot.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command
+ to.
+ @param[out] MediaPresent The pointer to the media present boolean value.
+
+ @retval EFI_SUCCESS There is no media change happened.
+ @retval EFI_MEDIA_CHANGED There is media change happened.
+ @retval Others The detection fails.
+
+**/
+EFI_STATUS
+DwMmcHcCardDetect (
+ IN UINTN DevBase,
+ IN EFI_HANDLE Controller,
+ IN UINT8 Slot,
+ OUT BOOLEAN *MediaPresent
+ )
+{
+ PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc;
+ EFI_STATUS Status;
+
+ if (MediaPresent == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = gBS->LocateProtocol (
+ &gPlatformDwMmcProtocolGuid,
+ NULL,
+ (VOID **) &PlatformDwMmc
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *MediaPresent = PlatformDwMmc->CardDetect (Controller, Slot);
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+DwMmcHcUpdateClock (
+ IN UINTN DevBase
+ )
+{
+ UINT32 Cmd;
+ UINT32 IntStatus;
+
+ Cmd = BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_UPDATE_CLOCK_ONLY |
+ BIT_CMD_START;
+ MmioWrite32 (DevBase + DW_MMC_CMD, Cmd);
+
+ while (1) {
+ Cmd = MmioRead32 (DevBase + DW_MMC_CMD);
+
+ if (!(Cmd & CMD_START_BIT)) {
+ break;
+ }
+
+ IntStatus = MmioRead32 (DevBase + DW_MMC_RINTSTS);
+
+ if (IntStatus & DW_MMC_INT_HLE) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "DwMmcHcUpdateClock: failed to update mmc clock frequency\n"
+ ));
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Stop SD/MMC card clock.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+
+ @retval EFI_SUCCESS Succeed to stop SD/MMC clock.
+ @retval Others Fail to stop SD/MMC clock.
+
+**/
+EFI_STATUS
+DwMmcHcStopClock (
+ IN UINTN DevBase
+ )
+{
+ EFI_STATUS Status;
+ UINT32 ClkEna;
+
+ //
+ // Disable MMC clock first
+ //
+ ClkEna = 0;
+ MmioWrite32 (DevBase + DW_MMC_CLKENA, ClkEna);
+
+ Status = DwMmcHcUpdateClock (DevBase);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return Status;
+}
+
+/**
+ SD/MMC card clock supply.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcClockSupply (
+ IN UINTN DevBase,
+ IN UINT64 ClockFreq,
+ IN DW_MMC_HC_SLOT_CAP Capability
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BaseClkFreq;
+ UINT32 SettingFreq;
+ UINT32 Divisor;
+ UINT32 Remainder;
+ UINT32 MmcStatus;
+ UINT32 ClkEna;
+ UINT32 ClkSrc;
+
+ //
+ // Calculate a divisor for SD clock frequency
+ //
+ ASSERT (Capability.BaseClkFreq != 0);
+
+ BaseClkFreq = Capability.BaseClkFreq;
+ if (ClockFreq == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ClockFreq > BaseClkFreq) {
+ ClockFreq = BaseClkFreq;
+ }
+
+ //
+ // Calculate the divisor of base frequency.
+ //
+ Divisor = 0;
+ SettingFreq = BaseClkFreq;
+ while (ClockFreq < SettingFreq) {
+ Divisor++;
+
+ SettingFreq = BaseClkFreq / (2 * Divisor);
+ Remainder = BaseClkFreq % (2 * Divisor);
+ if ((ClockFreq == SettingFreq) && (Remainder == 0)) {
+ break;
+ }
+ if ((ClockFreq == SettingFreq) && (Remainder != 0)) {
+ SettingFreq ++;
+ }
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "BaseClkFreq %dKHz Divisor %d ClockFreq %dKhz\n",
+ BaseClkFreq,
+ Divisor,
+ ClockFreq
+ ));
+
+ //
+ // Wait until MMC is idle
+ //
+ do {
+ MmcStatus = MmioRead32 (DevBase + DW_MMC_STATUS);
+ } while (MmcStatus & DW_MMC_STS_DATA_BUSY);
+
+ do {
+ Status = DwMmcHcStopClock (DevBase);
+ } while (EFI_ERROR (Status));
+
+ do {
+ ClkSrc = 0;
+ MmioWrite32 (DevBase + DW_MMC_CLKSRC, ClkSrc);
+ //
+ // Set clock divisor
+ //
+ MmioWrite32 (DevBase + DW_MMC_CLKDIV, Divisor);
+ //
+ // Enable MMC clock
+ //
+ ClkEna = 1;
+ MmioWrite32 (DevBase + DW_MMC_CLKENA, ClkEna);
+
+ Status = DwMmcHcUpdateClock (DevBase);
+ } while (EFI_ERROR (Status));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set the SD/MMC bus width.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] IsDdr A boolean to indicate it's dual data rate or not.
+ @param[in] BusWidth The bus width used by the SD/MMC device, it must be
+ 1, 4 or 8.
+
+ @retval EFI_SUCCESS The bus width is set successfully.
+ @retval Others The bus width isn't set successfully.
+
+**/
+EFI_STATUS
+DwMmcHcSetBusWidth (
+ IN UINTN DevBase,
+ IN BOOLEAN IsDdr,
+ IN UINT16 BusWidth
+ )
+{
+ UINT32 Ctype;
+ UINT32 Uhs;
+
+ switch (BusWidth) {
+ case 1:
+ Ctype = MMC_1BIT_MODE;
+ break;
+ case 4:
+ Ctype = MMC_4BIT_MODE;
+ break;
+ case 8:
+ Ctype = MMC_8BIT_MODE;
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ MmioWrite32 (DevBase + DW_MMC_CTYPE, Ctype);
+
+ Uhs = MmioRead32 (DevBase + DW_MMC_UHSREG);
+
+ if (IsDdr) {
+ Uhs |= UHS_DDR_MODE;
+ } else {
+ Uhs &= ~(UHS_DDR_MODE);
+ }
+
+ MmioWrite32 (DevBase + DW_MMC_UHSREG, Uhs);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Supply SD/MMC card with lowest clock frequency at initialization.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitClockFreq (
+ IN UINTN DevBase,
+ IN DW_MMC_HC_SLOT_CAP Capability
+ )
+{
+ EFI_STATUS Status;
+ UINT32 InitFreq;
+
+ //
+ // Calculate a divisor for SD clock frequency
+ //
+ if (Capability.BaseClkFreq == 0) {
+ //
+ // Don't support get Base Clock Frequency information via another method
+ //
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Supply 400KHz clock frequency at initialization phase.
+ //
+ InitFreq = DWMMC_INIT_CLOCK_FREQ;
+ Status = DwMmcHcClockSupply (DevBase, InitFreq, Capability);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ MicroSecondDelay (100);
+ return Status;
+}
+
+/**
+ Supply SD/MMC card with maximum voltage at initialization.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The voltage is supplied successfully.
+ @retval Others The voltage isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitPowerVoltage (
+ IN UINTN DevBase,
+ IN DW_MMC_HC_SLOT_CAP Capability
+ )
+{
+ UINT32 Data;
+ UINT32 Timeout;
+
+ Data = 0x1;
+ MmioWrite32 (DevBase + DW_MMC_PWREN, Data);
+
+ Data = DW_MMC_CTRL_RESET_ALL;
+ MmioWrite32 (DevBase + DW_MMC_CTRL, Data);
+
+ Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+ while (Timeout > 0) {
+ Data = MmioRead32 (DevBase + DW_MMC_CTRL);
+
+ if ((Data & DW_MMC_CTRL_RESET_ALL) == 0) {
+ break;
+ }
+ gBS->Stall (1);
+
+ Timeout--;
+ }
+
+ if (Timeout <= 0) {
+ DEBUG ((DEBUG_INFO,
+ "DwMmcHcInitPowerVoltage: reset failed due to timeout"));
+
+ return EFI_TIMEOUT;
+ }
+
+ Data = DW_MMC_CTRL_INT_EN;
+ MmioWrite32 (DevBase + DW_MMC_CTRL, Data);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize the Timeout Control register with most conservative value at
+ initialization.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+
+ @retval EFI_SUCCESS The timeout control register is configured
+ successfully.
+ @retval Others The timeout control register isn't configured
+ successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitTimeoutCtrl (
+ IN UINTN DevBase
+ )
+{
+ UINT32 Data;
+
+ Data = ~0;
+ MmioWrite32 (DevBase + DW_MMC_TMOUT, Data);
+
+ Data = 0x00FFFFFF;
+ MmioWrite32 (DevBase + DW_MMC_DEBNCE, Data);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initial SD/MMC host controller with lowest clock frequency, max power and
+ max timeout value at initialization.
+
+ @param[in] DevIo The DEVICE IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command
+ to.
+ @param[in] Capability The capability of the slot.
+
+ @retval EFI_SUCCESS The host controller is initialized successfully.
+ @retval Others The host controller isn't initialized successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitHost (
+ IN UINTN DevBase,
+ IN DW_MMC_HC_SLOT_CAP Capability
+ )
+{
+ EFI_STATUS Status;
+
+ Status = DwMmcHcInitPowerVoltage (DevBase, Capability);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return Status;
+}
+
+EFI_STATUS
+DwMmcHcStartDma (
+ IN DW_MMC_HC_PRIVATE_DATA *Private,
+ IN DW_MMC_HC_TRB *Trb
+ )
+{
+ UINTN DevBase;
+ UINT32 Ctrl;
+ UINT32 Bmod;
+ UINT32 Timeout;
+ UINT32 Data;
+
+// DevIo = Trb->Private->DevIo;
+ DevBase = Trb->Private->DevBase;
+
+ //
+ // Reset DMA
+ //
+ Ctrl = DW_MMC_CTRL_DMA_RESET;
+ MmioWrite32 (DevBase + DW_MMC_CTRL, Ctrl);
+
+ Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+ while (Timeout > 0) {
+ Data = MmioRead32 (DevBase + DW_MMC_CTRL);
+
+ if ((Data & DW_MMC_CTRL_DMA_RESET) == 0) {
+ break;
+ }
+ gBS->Stall (1);
+
+ Timeout--;
+ }
+
+ if (Timeout <= 0) {
+ DEBUG ((DEBUG_ERROR, "Timed out waiting for CTRL_DMA_RESET"));
+
+ return EFI_TIMEOUT;
+ }
+
+ Bmod = DW_MMC_IDMAC_SWRESET | MmioRead32 (DevBase + DW_MMC_BMOD);
+
+ MmioWrite32 (DevBase + DW_MMC_BMOD, Bmod);
+
+ //
+ // Select IDMAC
+ //
+ Ctrl = DW_MMC_CTRL_IDMAC_EN;
+ Ctrl |= MmioRead32 (DevBase + DW_MMC_CTRL);
+ MmioWrite32 (DevBase + DW_MMC_CTRL, Ctrl);
+
+ //
+ // Enable IDMAC
+ //
+ Bmod = DW_MMC_IDMAC_ENABLE | DW_MMC_IDMAC_FB;
+ Bmod |= MmioRead32 (DevBase + DW_MMC_BMOD);
+
+ MmioWrite32 (DevBase + DW_MMC_BMOD, Bmod);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+DwMmcHcStopDma (
+ IN DW_MMC_HC_PRIVATE_DATA *Private,
+ IN DW_MMC_HC_TRB *Trb
+ )
+{
+ UINTN DevBase;
+ UINT32 Ctrl;
+ UINT32 Bmod;
+
+ DevBase = Trb->Private->DevBase;
+
+ //
+ // Disable and reset IDMAC
+ //
+ Ctrl = MmioRead32 (DevBase + DW_MMC_CTRL);
+ Ctrl &= ~DW_MMC_CTRL_IDMAC_EN;
+ Ctrl |= DW_MMC_CTRL_DMA_RESET;
+ MmioWrite32 (DevBase + DW_MMC_CTRL, Ctrl);
+
+ //
+ // Stop IDMAC
+ //
+ Bmod = MmioRead32 (DevBase + DW_MMC_BMOD);
+ Bmod &= ~(DW_MMC_BMOD_FB | DW_MMC_BMOD_DE);
+ Bmod |= DW_MMC_BMOD_SWR;
+ MmioWrite32 (DevBase + DW_MMC_BMOD, Bmod);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Build DMA descriptor table for transfer.
+
+ @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The DMA descriptor table is created successfully.
+ @retval Others The DMA descriptor table isn't created successfully.
+
+**/
+EFI_STATUS
+BuildDmaDescTable (
+ IN DW_MMC_HC_TRB *Trb
+ )
+{
+ EFI_PHYSICAL_ADDRESS Data;
+ UINT64 DataLen;
+ UINT64 Entries;
+ UINT32 Index;
+ UINT64 Remaining;
+ UINTN TableSize;
+ UINTN DevBase;
+ EFI_STATUS Status;
+ UINTN Bytes;
+ UINTN Blocks;
+ DW_MMC_HC_DMA_DESC_LINE *DmaDesc;
+ UINT32 DmaDescPhy;
+ UINT32 Idsts;
+ UINT32 BytCnt;
+ UINT32 BlkSize;
+
+ Data = Trb->DataPhy;
+ DataLen = Trb->DataLen;
+ DevBase = Trb->Private->DevBase;
+ //
+ // Only support 32bit DMA Descriptor Table
+ //
+ if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Address field shall be set on 32-bit boundary (Lower 2-bit is always set
+ // to 0) for 32-bit address descriptor table.
+ //
+ if ((Data & (BIT0 | BIT1)) != 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "The buffer [0x%x] to construct DMA desc is not aligned to 4 bytes!\n",
+ Data
+ ));
+ }
+
+ Entries = (DataLen + DWMMC_DMA_BUF_SIZE - 1) / DWMMC_DMA_BUF_SIZE;
+ TableSize = Entries * sizeof (DW_MMC_HC_DMA_DESC_LINE);
+ Blocks = (DataLen + DW_MMC_BLOCK_SIZE - 1) / DW_MMC_BLOCK_SIZE;
+
+ Trb->DmaDescPages = (UINT32)EFI_SIZE_TO_PAGES (Entries * DWMMC_DMA_BUF_SIZE);
+/* Status = DevIo->AllocateBuffer (
+ DevIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (TableSize),
+ (EFI_PHYSICAL_ADDRESS *)&Trb->DmaDesc
+ );*/
+ Status = DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (TableSize),
+ (VOID *)&Trb->DmaDesc);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ZeroMem (Trb->DmaDesc, TableSize);
+ Bytes = TableSize;
+
+ Status = DmaMap (MapOperationBusMasterCommonBuffer,
+ (EFI_PHYSICAL_ADDRESS *)Trb->DmaDesc,
+ &Bytes, &Trb->DmaDescPhy, &Trb->DmaMap);
+/* Status = DevIo->Map (
+ DevIo,
+ EfiBusMasterCommonBuffer,
+ (EFI_PHYSICAL_ADDRESS *)Trb->DmaDesc,
+ &Bytes,
+ &Trb->DmaDescPhy,
+ &Trb->DmaMap
+ );*/
+
+ if (EFI_ERROR (Status) || (Bytes != TableSize)) {
+ //
+ // Map error or unable to map the whole RFis buffer into a contiguous
+ // region.
+ //
+/* DevIo->FreeBuffer (
+ DevIo,
+ EFI_SIZE_TO_PAGES (TableSize),
+ (EFI_PHYSICAL_ADDRESS)Trb->DmaDesc
+ );*/
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if ((UINT64)(UINTN)Trb->DmaDescPhy > 0x100000000ul) {
+ //
+ // The DMA doesn't support 64bit addressing.
+ //
+ DmaUnmap (Trb->DmaMap);
+/* DevIo->Unmap (
+ DevIo,
+ Trb->DmaMap
+ );*/
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (DataLen < DW_MMC_BLOCK_SIZE) {
+ BlkSize = DataLen;
+ BytCnt = DataLen;
+ Remaining = DataLen;
+ } else {
+ BlkSize = DW_MMC_BLOCK_SIZE;
+ BytCnt = DW_MMC_BLOCK_SIZE * Blocks;
+ Remaining = DW_MMC_BLOCK_SIZE * Blocks;
+ }
+
+ MmioWrite32 (DevBase + DW_MMC_BLKSIZ, BlkSize);
+ MmioWrite32 (DevBase + DW_MMC_BYTCNT, BytCnt);
+ DmaDesc = Trb->DmaDesc;
+ for (Index = 0; Index < Entries; Index++, DmaDesc++) {
+ DmaDesc->Des0 = DW_MMC_IDMAC_DES0_OWN | DW_MMC_IDMAC_DES0_CH |
+ DW_MMC_IDMAC_DES0_DIC;
+ DmaDesc->Des1 = DW_MMC_IDMAC_DES1_BS1 (DWMMC_DMA_BUF_SIZE);
+ //
+ // Buffer Address
+ //
+ DmaDesc->Des2 = (UINT32)((UINTN)Trb->DataPhy +
+ (DWMMC_DMA_BUF_SIZE * Index));
+ //
+ // Next Descriptor Address
+ //
+ DmaDesc->Des3 = (UINT32)((UINTN)Trb->DmaDescPhy +
+ sizeof (DW_MMC_HC_DMA_DESC_LINE) * (Index + 1));
+ Remaining = Remaining - DWMMC_DMA_BUF_SIZE;
+ }
+ //
+ // First Descriptor
+ //
+ Trb->DmaDesc[0].Des0 |= DW_MMC_IDMAC_DES0_FS;
+ //
+ // Last Descriptor
+ //
+ Trb->DmaDesc[Entries - 1].Des0 &= ~(DW_MMC_IDMAC_DES0_CH |
+ DW_MMC_IDMAC_DES0_DIC);
+ Trb->DmaDesc[Entries - 1].Des0 |= DW_MMC_IDMAC_DES0_OWN |
+ DW_MMC_IDMAC_DES0_LD;
+ Trb->DmaDesc[Entries - 1].Des1 = DW_MMC_IDMAC_DES1_BS1 (Remaining +
+ DWMMC_DMA_BUF_SIZE);
+ //
+ // Set the next field of the Last Descriptor
+ //
+ Trb->DmaDesc[Entries - 1].Des3 = 0;
+ DmaDescPhy = (UINT32)Trb->DmaDescPhy;
+
+ MmioWrite32 (DevBase + DW_MMC_DBADDR, DmaDescPhy);
+
+ ArmDataSynchronizationBarrier ();
+ ArmInstructionSynchronizationBarrier ();
+ //
+ // Clear interrupts
+ //
+ Idsts = ~0;
+ MmioWrite32 (DevBase + DW_MMC_IDSTS, Idsts);
+
+ return Status;
+}
+
+EFI_STATUS
+TransferFifo (
+ IN DW_MMC_HC_TRB *Trb
+ )
+{
+ UINTN DevBase;
+ UINT32 Data;
+ UINT32 Received;
+ UINT32 Count;
+ UINT32 Intsts;
+ UINT32 Sts;
+ UINT32 FifoCount;
+ UINT32 Index; /* count with bytes */
+ UINT32 Ascending;
+ UINT32 Descending;
+
+ DevBase = Trb->Private->DevBase;
+ Received = 0;
+ Count = 0;
+ Index = 0;
+ Ascending = 0;
+ Descending = ((Trb->DataLen + 3) & ~3) - 4;
+ do {
+ Intsts = MmioRead32 (DevBase + DW_MMC_RINTSTS);
+
+ if (Trb->DataLen && (Intsts & DW_MMC_INT_TXDR) && !Trb->Read) {
+ Sts = MmioRead32 (DevBase + DW_MMC_STATUS);
+
+ while (!(DW_MMC_STS_FIFO_FULL(Sts))
+ && (Received < Trb->DataLen)
+ && (Intsts & DW_MMC_INT_TXDR)) {
+ if (Trb->UseBE) {
+ Data = SwapBytes32 (*(UINT32 *)((UINTN)Trb->Data + Descending));
+ Descending = Descending - 4;
+ } else {
+ Data = *(UINT32 *)((UINTN)Trb->Data + Ascending);
+ Ascending += 4;
+ }
+ Index += 4;
+ Received += 4;
+
+ MmioWrite32 (DevBase + DW_MMC_FIFO_START, Data);
+
+ Intsts = DW_MMC_INT_TXDR;
+ MmioWrite32 (DevBase + DW_MMC_RINTSTS, Intsts);
+
+ Intsts = MmioRead32 (DevBase + DW_MMC_RINTSTS);
+ Sts = MmioRead32 (DevBase + DW_MMC_STATUS);
+ }
+ continue;
+ }
+
+ if (Trb->DataLen && ((Intsts & DW_MMC_INT_RXDR) ||
+ (Intsts & DW_MMC_INT_DTO)) && Trb->Read) {
+ Sts = MmioRead32 (DevBase + DW_MMC_STATUS);
+ //
+ // Convert to bytes
+ //
+ FifoCount = GET_STS_FIFO_COUNT (Sts) << 2;
+ if ((FifoCount == 0) && (Received < Trb->DataLen)) {
+ continue;
+ }
+ Index = 0;
+ Count = (MIN (FifoCount, Trb->DataLen) + 3) & ~3;
+ while (Index < Count) {
+ Data = MmioRead32 (DevBase + DW_MMC_FIFO_START);
+
+ if (Trb->UseBE) {
+ *(UINT32 *)((UINTN)Trb->Data + Descending) = SwapBytes32 (Data);
+ Descending = Descending - 4;
+ } else {
+ *(UINT32 *)((UINTN)Trb->Data + Ascending) = Data;
+ Ascending += 4;
+ }
+ Index += 4;
+ Received += 4;
+ } /* while */
+ } /* if */
+ } while (((Intsts & DW_MMC_INT_CMD_DONE) == 0) || (Received < Trb->DataLen));
+ //
+ // Clear RINTSTS
+ //
+ Intsts = ~0;
+ MmioWrite32 (DevBase + DW_MMC_RINTSTS, Intsts);
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a new TRB for the SD/MMC cmd request.
+
+ @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command
+ to.
+ @param[in] Packet A pointer to the SD command data structure.
+ @param[in] Event If Event is NULL, blocking I/O is performed. If
+ Event is not NULL, then nonblocking I/O is
+ performed, and Event will be signaled when the
+ Packet completes.
+
+ @return Created Trb or NULL.
+
+**/
+DW_MMC_HC_TRB *
+DwMmcCreateTrb (
+ IN DW_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event
+ )
+{
+ DW_MMC_HC_TRB *Trb;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ EFI_IO_OPERATION_TYPE Flag;
+ UINTN MapLength;
+
+ Trb = AllocateZeroPool (sizeof (DW_MMC_HC_TRB));
+ if (Trb == NULL) {
+ return NULL;
+ }
+
+ Trb->Signature = DW_MMC_HC_TRB_SIG;
+ Trb->Slot = Slot;
+ Trb->BlockSize = 0x200;
+ Trb->Packet = Packet;
+ Trb->Event = Event;
+ Trb->Started = FALSE;
+ Trb->Timeout = Packet->Timeout;
+ Trb->Private = Private;
+
+ if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {
+ Trb->Data = Packet->InDataBuffer;
+ Trb->DataLen = Packet->InTransferLength;
+ Trb->Read = TRUE;
+ ZeroMem (Trb->Data, Trb->DataLen);
+ } else if (Packet->OutTransferLength && (Packet->OutDataBuffer != NULL)) {
+ Trb->Data = Packet->OutDataBuffer;
+ Trb->DataLen = Packet->OutTransferLength;
+ Trb->Read = FALSE;
+ } else if (!Packet->InTransferLength && !Packet->OutTransferLength) {
+ Trb->Data = NULL;
+ Trb->DataLen = 0;
+ } else {
+ goto Error;
+ }
+
+ if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) &&
+ (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) ||
+ ((Private->Slot[Trb->Slot].CardType == SdCardType) &&
+ (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) {
+ Trb->Mode = SdMmcPioMode;
+ } else {
+ if (Trb->Read) {
+ Flag = EfiBusMasterWrite;
+ } else {
+ Flag = EfiBusMasterRead;
+ }
+
+ if (Private->Slot[Trb->Slot].CardType == SdCardType) {
+ Trb->UseFifo = TRUE;
+ } else {
+ Trb->UseFifo = FALSE;
+ if (Trb->DataLen) {
+ MapLength = Trb->DataLen;
+ Status = DmaMap (Flag, Trb->Data, &MapLength, &Trb->DataPhy, &Trb->DataMap);
+/* Status = DevIo->Map (
+ DevIo,
+ Flag,
+ Trb->Data,
+ &MapLength,
+ &Trb->DataPhy,
+ &Trb->DataMap
+ );*/
+ if (EFI_ERROR (Status) || (Trb->DataLen != MapLength)) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Error;
+ }
+
+ Status = BuildDmaDescTable (Trb);
+ if (EFI_ERROR (Status)) {
+ DmaUnmap(Trb->DataMap);
+ goto Error;
+ }
+ Status = DwMmcHcStartDma (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ DmaUnmap(Trb->DataMap);
+ goto Error;
+ }
+ }
+ }
+ } /* TuningBlock */
+
+ if (Event != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Private->Queue, &Trb->TrbList);
+ gBS->RestoreTPL (OldTpl);
+ }
+
+ return Trb;
+
+Error:
+ return NULL;
+}
+
+/**
+ Free the resource used by the TRB.
+
+ @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
+
+**/
+VOID
+DwMmcFreeTrb (
+ IN DW_MMC_HC_TRB *Trb
+ )
+{
+ if (Trb->DmaMap != NULL) {
+ DmaUnmap (Trb->DmaMap);
+ }
+ if (Trb->DataMap != NULL) {
+ DmaUnmap (Trb->DataMap);
+ }
+ FreePool (Trb);
+}
+
+/**
+ Check if the env is ready for execute specified TRB.
+
+ @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The env is ready for TRB execution.
+ @retval EFI_NOT_READY The env is not ready for TRB execution.
+ @retval Others Some erros happen.
+
+**/
+EFI_STATUS
+DwMmcCheckTrbEnv (
+ IN DW_MMC_HC_PRIVATE_DATA *Private,
+ IN DW_MMC_HC_TRB *Trb
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Wait for the env to be ready for execute specified TRB.
+
+ @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The env is ready for TRB execution.
+ @retval EFI_TIMEOUT The env is not ready for TRB execution in time.
+ @retval Others Some erros happen.
+
+**/
+EFI_STATUS
+DwMmcWaitTrbEnv (
+ IN DW_MMC_HC_PRIVATE_DATA *Private,
+ IN DW_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ UINT64 Timeout;
+ BOOLEAN InfiniteWait;
+
+ //
+ // Wait Command Complete Interrupt Status bit in Normal Interrupt Status
+ // Register
+ //
+ Packet = Trb->Packet;
+ Timeout = Packet->Timeout;
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ while (InfiniteWait || (Timeout > 0)) {
+ //
+ // Check Trb execution result by reading Normal Interrupt Status register.
+ //
+ Status = DwMmcCheckTrbEnv (Private, Trb);
+ if (Status != EFI_NOT_READY) {
+ return Status;
+ }
+ //
+ // Stall for 1 microsecond.
+ //
+ gBS->Stall (1);
+
+ Timeout--;
+ }
+
+ return EFI_TIMEOUT;
+}
+
+EFI_STATUS
+DwEmmcExecTrb (
+ IN DW_MMC_HC_PRIVATE_DATA *Private,
+ IN DW_MMC_HC_TRB *Trb
+ )
+{
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ UINTN DevBase;
+ UINT32 Cmd;
+ UINT32 MmcStatus;
+ UINT32 IntStatus;
+ UINT32 Argument;
+ UINT32 ErrMask;
+ UINT32 Timeout;
+
+ Packet = Trb->Packet;
+ DevBase = Trb->Private->DevBase;
+
+ ArmDataSynchronizationBarrier ();
+ ArmInstructionSynchronizationBarrier ();
+ //
+ // Wait until MMC is idle
+ //
+ do {
+ MmcStatus = MmioRead32 (DevBase + DW_MMC_STATUS);
+ } while (MmcStatus & DW_MMC_STS_DATA_BUSY);
+
+ IntStatus = ~0;
+ MmioWrite32 (DevBase + DW_MMC_RINTSTS, IntStatus);
+ Cmd = CMD_INDEX (Packet->SdMmcCmdBlk->CommandIndex);
+ if ((Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAc) ||
+ (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc)) {
+ switch (Packet->SdMmcCmdBlk->CommandIndex) {
+ case EMMC_SET_RELATIVE_ADDR:
+ Cmd |= BIT_CMD_SEND_INIT;
+ break;
+ case EMMC_SEND_STATUS:
+ Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE;
+ break;
+ case EMMC_STOP_TRANSMISSION:
+ Cmd |= BIT_CMD_STOP_ABORT_CMD;
+ break;
+ }
+ if (Packet->InTransferLength) {
+ Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_DATA_EXPECTED |
+ BIT_CMD_READ;
+ } else if (Packet->OutTransferLength) {
+ Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_DATA_EXPECTED |
+ BIT_CMD_WRITE;
+ }
+ Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;
+ } else {
+ switch (Packet->SdMmcCmdBlk->CommandIndex) {
+ case EMMC_GO_IDLE_STATE:
+ Cmd |= BIT_CMD_SEND_INIT;
+ break;
+ case EMMC_SEND_OP_COND:
+ Cmd |= BIT_CMD_RESPONSE_EXPECT;
+ break;
+ case EMMC_ALL_SEND_CID:
+ Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_LONG_RESPONSE |
+ BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_SEND_INIT;
+ break;
+ }
+ }
+ switch (Packet->SdMmcCmdBlk->ResponseType) {
+ case SdMmcResponseTypeR2:
+ Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
+ BIT_CMD_LONG_RESPONSE;
+ break;
+ case SdMmcResponseTypeR3:
+ Cmd |= BIT_CMD_RESPONSE_EXPECT;
+ break;
+ }
+ Cmd |= BIT_CMD_USE_HOLD_REG | BIT_CMD_START;
+
+ Argument = Packet->SdMmcCmdBlk->CommandArgument;
+ MmioWrite32 (DevBase + DW_MMC_CMDARG, Argument);
+
+ ArmDataSynchronizationBarrier ();
+ ArmInstructionSynchronizationBarrier ();
+
+ MmioWrite32 (DevBase + DW_MMC_CMD, Cmd);
+ ArmDataSynchronizationBarrier ();
+ ArmInstructionSynchronizationBarrier ();
+
+ ErrMask = DW_MMC_INT_EBE | DW_MMC_INT_HLE | DW_MMC_INT_RTO |
+ DW_MMC_INT_RCRC | DW_MMC_INT_RE;
+ ErrMask |= DW_MMC_INT_DCRC | DW_MMC_INT_DRT | DW_MMC_INT_SBE;
+ do {
+ Timeout = 10000;
+ if (--Timeout == 0) {
+ break;
+ }
+ IntStatus = MmioRead32 (DevBase + DW_MMC_RINTSTS);
+ if (IntStatus & ErrMask) {
+ return EFI_DEVICE_ERROR;
+ }
+ if (Trb->DataLen && ((IntStatus & DW_MMC_INT_DTO) == 0)) {
+ //
+ // Transfer Not Done
+ //
+ MicroSecondDelay (10);
+ continue;
+ }
+ MicroSecondDelay (10);
+ } while (!(IntStatus & DW_MMC_INT_CMD_DONE));
+ switch (Packet->SdMmcCmdBlk->ResponseType) {
+ case SdMmcResponseTypeR1:
+ case SdMmcResponseTypeR1b:
+ case SdMmcResponseTypeR3:
+ case SdMmcResponseTypeR4:
+ case SdMmcResponseTypeR5:
+ Packet->SdMmcStatusBlk->Resp0 = MmioRead32 (DevBase + DW_MMC_RESP0);
+ break;
+ case SdMmcResponseTypeR2:
+ Packet->SdMmcStatusBlk->Resp0 = MmioRead32 (DevBase + DW_MMC_RESP0);
+ Packet->SdMmcStatusBlk->Resp1 = MmioRead32 (DevBase + DW_MMC_RESP1);
+ Packet->SdMmcStatusBlk->Resp2 = MmioRead32 (DevBase + DW_MMC_RESP2);
+ Packet->SdMmcStatusBlk->Resp3 = MmioRead32 (DevBase + DW_MMC_RESP3);
+ break;
+ }
+
+ //
+ // The workaround on EMMC_SEND_CSD is used to be compatible with SDHC.
+ //
+ if (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_CSD) {
+ {
+ UINT32 Buf[4];
+ ZeroMem (Buf, sizeof (Buf));
+ CopyMem (
+ (UINT8 *)Buf,
+ (UINT8 *)&Packet->SdMmcStatusBlk->Resp0 + 1,
+ sizeof (Buf) - 1
+ );
+ CopyMem (
+ (UINT8 *)&Packet->SdMmcStatusBlk->Resp0,
+ (UINT8 *)Buf,
+ sizeof (Buf) - 1
+ );
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+DwSdExecTrb (
+ IN DW_MMC_HC_PRIVATE_DATA *Private,
+ IN DW_MMC_HC_TRB *Trb
+ )
+{
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ UINTN DevBase;
+ UINT32 Cmd;
+ UINT32 MmcStatus;
+ UINT32 IntStatus;
+ UINT32 Argument;
+ UINT32 ErrMask;
+ UINT32 Timeout;
+ UINT32 Idsts;
+ UINT32 BytCnt;
+ UINT32 BlkSize;
+ EFI_STATUS Status;
+
+ Packet = Trb->Packet;
+ DevBase = Trb->Private->DevBase;
+
+ ArmDataSynchronizationBarrier ();
+ ArmInstructionSynchronizationBarrier ();
+ //
+ // Wait until MMC is idle
+ //
+ do {
+ MmcStatus = MmioRead32 (DevBase + DW_MMC_STATUS);
+ } while (MmcStatus & DW_MMC_STS_DATA_BUSY);
+
+ IntStatus = ~0;
+ MmioWrite32 (DevBase + DW_MMC_RINTSTS, IntStatus);
+ Cmd = CMD_INDEX (Packet->SdMmcCmdBlk->CommandIndex);
+ if ((Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAc) ||
+ (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc)) {
+ switch (Packet->SdMmcCmdBlk->CommandIndex) {
+ case SD_SET_RELATIVE_ADDR:
+ Cmd |= BIT_CMD_SEND_INIT;
+ break;
+ case SD_STOP_TRANSMISSION:
+ Cmd |= BIT_CMD_STOP_ABORT_CMD;
+ break;
+ case SD_SEND_SCR:
+ Trb->UseBE = TRUE;
+ break;
+ }
+ if (Packet->InTransferLength) {
+ Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_DATA_EXPECTED |
+ BIT_CMD_READ;
+ } else if (Packet->OutTransferLength) {
+ Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_DATA_EXPECTED |
+ BIT_CMD_WRITE;
+ }
+ Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
+ BIT_CMD_SEND_AUTO_STOP;
+ } else {
+ switch (Packet->SdMmcCmdBlk->CommandIndex) {
+ case SD_GO_IDLE_STATE:
+ Cmd |= BIT_CMD_SEND_INIT;
+ break;
+ }
+ }
+ switch (Packet->SdMmcCmdBlk->ResponseType) {
+ case SdMmcResponseTypeR2:
+ Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
+ BIT_CMD_LONG_RESPONSE;
+ break;
+ case SdMmcResponseTypeR3:
+ Cmd |= BIT_CMD_RESPONSE_EXPECT;
+ break;
+ case SdMmcResponseTypeR1b:
+ case SdMmcResponseTypeR4:
+ case SdMmcResponseTypeR6:
+ case SdMmcResponseTypeR7:
+ Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;
+ break;
+ }
+ Cmd |= BIT_CMD_USE_HOLD_REG | BIT_CMD_START;
+
+ if (Trb->UseFifo == TRUE) {
+ BytCnt = Trb->Read ? Packet->InTransferLength : Packet->OutTransferLength;
+ MmioWrite32 (DevBase + DW_MMC_BYTCNT, BytCnt);
+ if (Trb->Read) {
+ if (Packet->InTransferLength > DW_MMC_BLOCK_SIZE) {
+ BlkSize = DW_MMC_BLOCK_SIZE;
+ } else {
+ BlkSize = Packet->InTransferLength;
+ }
+ }
+ else {
+ if (Packet->OutTransferLength > DW_MMC_BLOCK_SIZE) {
+ BlkSize = DW_MMC_BLOCK_SIZE;
+ } else {
+ BlkSize = Packet->OutTransferLength;
+ }
+ }
+
+ MmioWrite32 (DevBase + DW_MMC_BLKSIZ, BlkSize);
+ }
+
+ Argument = Packet->SdMmcCmdBlk->CommandArgument;
+ MmioWrite32 (DevBase + DW_MMC_CMDARG, Argument);
+ ArmDataSynchronizationBarrier ();
+ ArmInstructionSynchronizationBarrier ();
+ MmioWrite32 (DevBase + DW_MMC_CMD, Cmd);
+ ArmDataSynchronizationBarrier ();
+ ArmInstructionSynchronizationBarrier ();
+
+ ErrMask = DW_MMC_INT_EBE | DW_MMC_INT_HLE | DW_MMC_INT_RTO |
+ DW_MMC_INT_RCRC | DW_MMC_INT_RE;
+ ErrMask |= DW_MMC_INT_DRT | DW_MMC_INT_SBE;
+ if (Packet->InTransferLength || Packet->OutTransferLength) {
+ ErrMask |= DW_MMC_INT_DCRC;
+ }
+ if (Trb->UseFifo == TRUE) {
+ Status = TransferFifo (Trb);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ Timeout = 10000;
+ do {
+ if (--Timeout == 0) {
+ break;
+ }
+ IntStatus = MmioRead32 (DevBase + DW_MMC_RINTSTS);
+ if (IntStatus & ErrMask) {
+ return EFI_DEVICE_ERROR;
+ }
+ if (Trb->DataLen && ((IntStatus & DW_MMC_INT_DTO) == 0)) {
+ //
+ // Transfer not Done
+ //
+ MicroSecondDelay (10);
+ continue;
+ }
+ MicroSecondDelay (10);
+ } while (!(IntStatus & DW_MMC_INT_CMD_DONE));
+ if (Packet->InTransferLength) {
+ do {
+ Idsts = MmioRead32 (DevBase + DW_MMC_IDSTS);
+ } while ((Idsts & DW_MMC_IDSTS_RI) == 0);
+ Status = DwMmcHcStopDma (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else if (Packet->OutTransferLength) {
+ do {
+ Idsts = MmioRead32 (DevBase + DW_MMC_IDSTS);
+ } while ((Idsts & DW_MMC_IDSTS_TI) == 0);
+ Status = DwMmcHcStopDma (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } /* Packet->InTransferLength */
+ } /* UseFifo */
+ switch (Packet->SdMmcCmdBlk->ResponseType) {
+ case SdMmcResponseTypeR1:
+ case SdMmcResponseTypeR1b:
+ case SdMmcResponseTypeR3:
+ case SdMmcResponseTypeR4:
+ case SdMmcResponseTypeR5:
+ case SdMmcResponseTypeR6:
+ case SdMmcResponseTypeR7:
+ Packet->SdMmcStatusBlk->Resp0 = MmioRead32 (DevBase + DW_MMC_RESP0);
+ break;
+ case SdMmcResponseTypeR2:
+ Packet->SdMmcStatusBlk->Resp0 = MmioRead32 (DevBase + DW_MMC_RESP0);
+ Packet->SdMmcStatusBlk->Resp1 = MmioRead32 (DevBase + DW_MMC_RESP1);
+ Packet->SdMmcStatusBlk->Resp2 = MmioRead32 (DevBase + DW_MMC_RESP2);
+ Packet->SdMmcStatusBlk->Resp3 = MmioRead32 (DevBase + DW_MMC_RESP3);
+ break;
+ }
+
+ //
+ // The workaround on SD_SEND_CSD is used to be compatible with SDHC.
+ //
+ if (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_CSD) {
+ {
+ UINT32 Buf[4];
+ ZeroMem (Buf, sizeof (Buf));
+ CopyMem (
+ (UINT8 *)Buf,
+ (UINT8 *)&Packet->SdMmcStatusBlk->Resp0 + 1,
+ sizeof (Buf) - 1
+ );
+ CopyMem (
+ (UINT8 *)&Packet->SdMmcStatusBlk->Resp0,
+ (UINT8 *)Buf,
+ sizeof (Buf) - 1
+ );
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Execute the specified TRB.
+
+ @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is sent to host controller successfully.
+ @retval Others Some erros happen when sending this request to the
+ host controller.
+
+**/
+EFI_STATUS
+DwMmcExecTrb (
+ IN DW_MMC_HC_PRIVATE_DATA *Private,
+ IN DW_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT32 Slot;
+
+ Slot = Trb->Slot;
+ if (Private->Slot[Slot].CardType == EmmcCardType) {
+ Status = DwEmmcExecTrb (Private, Trb);
+ } else if (Private->Slot[Slot].CardType == SdCardType) {
+ Status = DwSdExecTrb (Private, Trb);
+ } else {
+ ASSERT (0);
+ }
+ return Status;
+}
+
+/**
+ Check the TRB execution result.
+
+ @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval EFI_NOT_READY The TRB is not completed for execution.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+DwMmcCheckTrbResult (
+ IN DW_MMC_HC_PRIVATE_DATA *Private,
+ IN DW_MMC_HC_TRB *Trb
+ )
+{
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ UINT32 Idsts;
+ UINTN DevBase;
+
+ DevBase = Private->DevBase;
+ Packet = Trb->Packet;
+ if (Trb->UseFifo == TRUE) {
+ return EFI_SUCCESS;
+ }
+ if (Packet->InTransferLength) {
+ do {
+ Idsts = MmioRead32 (DevBase + DW_MMC_IDSTS);
+ } while ((Idsts & BIT1) == 0);
+ } else if (Packet->OutTransferLength) {
+ do {
+ Idsts = MmioRead32 (DevBase + DW_MMC_IDSTS);
+ } while ((Idsts & BIT0) == 0);
+ } else {
+ return EFI_SUCCESS;
+ }
+ Idsts = ~0;
+ MmioWrite32 (DevBase + DW_MMC_IDSTS, Idsts);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Wait for the TRB execution result.
+
+ @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+DwMmcWaitTrbResult (
+ IN DW_MMC_HC_PRIVATE_DATA *Private,
+ IN DW_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ UINT64 Timeout;
+ BOOLEAN InfiniteWait;
+
+ Packet = Trb->Packet;
+ //
+ // Wait Command Complete Interrupt Status bit in Normal Interrupt Status
+ // Register
+ //
+ Timeout = Packet->Timeout;
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ while (InfiniteWait || (Timeout > 0)) {
+ //
+ // Check Trb execution result by reading Normal Interrupt Status register.
+ //
+ Status = DwMmcCheckTrbResult (Private, Trb);
+ if (Status != EFI_NOT_READY) {
+ return Status;
+ }
+ //
+ // Stall for 1 microsecond.
+ //
+ gBS->Stall (1);
+
+ Timeout--;
+ }
+
+ return EFI_TIMEOUT;
+}
diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c b/EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
new file mode 100644
index 000000000000..b7a8688c4d2e
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
@@ -0,0 +1,1042 @@
+/** @file
+ This file provides some helper functions which are specific for EMMC device.
+
+ Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2018, Linaro. 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 <IndustryStandard/Emmc.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "DwMmcHcDxe.h"
+
+#define EMMC_GET_STATE(x) (((x) >> 9) & 0xf)
+#define EMMC_STATE_IDLE 0
+#define EMMC_STATE_READY 1
+#define EMMC_STATE_IDENT 2
+#define EMMC_STATE_STBY 3
+#define EMMC_STATE_TRAN 4
+#define EMMC_STATE_DATA 5
+#define EMMC_STATE_RCV 6
+#define EMMC_STATE_PRG 7
+#define EMMC_STATE_DIS 8
+#define EMMC_STATE_BTST 9
+#define EMMC_STATE_SLP 10
+
+#define EMMC_CMD1_CAPACITY_LESS_THAN_2GB 0x00FF8080 // Capacity <= 2GB, byte addressing used
+#define EMMC_CMD1_CAPACITY_GREATER_THAN_2GB 0x40FF8080 // Capacity > 2GB, 512-byte sector addressing used
+
+/**
+ Send command GO_IDLE_STATE (CMD0 with argument of 0x00000000) to the device to
+ make it go to Idle State.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Slot The slot number of the SD card to send the command
+ to.
+
+ @retval EFI_SUCCESS The EMMC device is reset correctly.
+ @retval Others The device reset fails.
+
+**/
+EFI_STATUS
+EmmcReset (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc;
+ SdMmcCmdBlk.ResponseType = 0;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ gBS->Stall (1000);
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_OP_COND to the EMMC device to get the data of the OCR
+ register.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in, out] Argument On input, the argument of SEND_OP_COND is to send
+ to the device.
+ On output, the argument is the value of OCR
+ register.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcGetOcr (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN OUT UINT32 *Argument
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;
+ SdMmcCmdBlk.CommandArgument = *Argument;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ *Argument = SdMmcStatusBlk.Resp0;
+ }
+
+ return Status;
+}
+
+/**
+ Broadcast command ALL_SEND_CID to the bus to ask all the EMMC devices to send
+ the data of their CID registers.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcGetAllCid (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SET_RELATIVE_ADDR to the EMMC device to assign a Relative device
+ Address (RCA).
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Rca The relative device address to be assigned.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSetRca (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT16 Rca
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_CSD to the EMMC device to get the data of the CSD register.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Rca The relative device address of selected device.
+ @param[out] Csd The buffer to store the content of the CSD register.
+ Note the caller should ignore the lowest byte of
+ this buffer as the content of this byte is
+ meaningless even if the operation succeeds.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcGetCsd (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT16 Rca,
+ OUT EMMC_CSD *Csd
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Copy 128bit data for CSD structure.
+ //
+ CopyMem ((VOID *)Csd + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);
+ }
+
+ return Status;
+}
+
+/**
+ Send command SELECT_DESELECT_CARD to the EMMC device to select/deselect it.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Rca The relative device address of selected device.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSelect (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT16 Rca
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_EXT_CSD to the EMMC device to get the data of the EXT_CSD
+ register.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[out] ExtCsd The buffer to store the content of the EXT_CSD
+ register.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcGetExtCsd (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ OUT EMMC_EXT_CSD *ExtCsd
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = 0x00000000;
+
+ Packet.InDataBuffer = ExtCsd;
+ Packet.InTransferLength = sizeof (EMMC_EXT_CSD);
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+ return Status;
+}
+
+/**
+ Send command SWITCH to the EMMC device to switch the mode of operation of the
+ selected Device or modifies the EXT_CSD registers.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Access The access mode of SWTICH command.
+ @param[in] Index The offset of the field to be access.
+ @param[in] Value The value to be set to the specified field of
+ EXT_CSD register.
+ @param[in] CmdSet The value of CmdSet field of EXT_CSD register.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitch (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Access,
+ IN UINT8 Index,
+ IN UINT8 Value,
+ IN UINT8 CmdSet
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SWITCH;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
+ SdMmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | \
+ (Value << 8) | CmdSet;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_STATUS to the addressed EMMC device to get its status
+ register.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Rca The relative device address of addressed device.
+ @param[out] DevStatus The returned device status.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSendStatus (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT16 Rca,
+ OUT UINT32 *DevStatus
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ *DevStatus = SdMmcStatusBlk.Resp0;
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_TUNING_BLOCK to the EMMC device for HS200 optimal sampling
+ point detection.
+
+ It may be sent up to 40 times until the host finishes the tuning procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] BusWidth The bus width to work.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSendTuningBlk (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT8 TuningBlock[128];
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ Packet.InDataBuffer = TuningBlock;
+ if (BusWidth == 8) {
+ Packet.InTransferLength = sizeof (TuningBlock);
+ } else {
+ Packet.InTransferLength = 64;
+ }
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Tunning the clock to get HS200 optimal sampling point.
+
+ Command SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes
+ the tuning procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8.
+
+ @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] BusWidth The bus width to work.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcTuningClkForHs200 (
+ IN UINTN DevBase,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 BusWidth
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Switch the bus width to specified width.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9.
+
+ @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] IsDdr If TRUE, use dual data rate data simpling method.
+ Otherwise use single data rate data simpling method.
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchBusWidth (
+ IN UINTN DevBase,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT16 Rca,
+ IN BOOLEAN IsDdr,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Access;
+ UINT8 Index;
+ UINT8 Value;
+ UINT8 CmdSet;
+ UINT32 DevStatus;
+
+ //
+ // Write Byte, the Value field is written into the byte pointed by Index.
+ //
+ Access = 0x03;
+ Index = OFFSET_OF (EMMC_EXT_CSD, BusWidth);
+ if (BusWidth == 1) {
+ Value = 0;
+ } else {
+ if (BusWidth == 4) {
+ Value = 1;
+ } else if (BusWidth == 8) {
+ Value = 2;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsDdr) {
+ Value += 4;
+ }
+ }
+
+ CmdSet = 0;
+ Status = EmmcSwitch (PassThru, Access, Index, Value, CmdSet);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "EmmcSwitchBusWidth: Switch to bus width %d fails with %r\n",
+ BusWidth,
+ Status
+ ));
+ return Status;
+ }
+
+ do {
+ Status = EmmcSendStatus (PassThru, Rca, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "EmmcSwitchBusWidth: Send status fails with %r\n",
+ Status
+ ));
+ return Status;
+ }
+ //
+ // Check the switch operation is really successful or not.
+ //
+ } while ((DevStatus & 0xf) == EMMC_STATE_PRG);
+
+ Status = DwMmcHcSetBusWidth (DevBase, IsDdr, BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return Status;
+}
+
+/**
+ Switch the clock frequency to the specified value.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.
+
+ @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] HsTiming The value to be written to HS_TIMING field of
+ EXT_CSD register.
+ @param[in] ClockFreq The max clock frequency to be set, the unit is MHz.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchClockFreq (
+ IN UINTN DevBase,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT16 Rca,
+ IN UINT8 HsTiming,
+ IN UINT32 ClockFreq
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Access;
+ UINT8 Index;
+ UINT8 Value;
+ UINT8 CmdSet;
+ UINT32 DevStatus;
+ DW_MMC_HC_PRIVATE_DATA *Private;
+
+ Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+ //
+ // Write Byte, the Value field is written into the byte pointed by Index.
+ //
+ Access = 0x03;
+ Index = OFFSET_OF (EMMC_EXT_CSD, HsTiming);
+ Value = HsTiming;
+ CmdSet = 0;
+
+ Status = EmmcSwitch (PassThru, Access, Index, Value, CmdSet);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "EmmcSwitchClockFreq: Switch to hstiming %d fails with %r\n",
+ HsTiming,
+ Status
+ ));
+ return Status;
+ }
+
+ Status = EmmcSendStatus (PassThru, Rca, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "EmmcSwitchClockFreq: Send status fails with %r\n",
+ Status
+ ));
+ return Status;
+ }
+ //
+ // Check the switch operation is really successful or not.
+ //
+ if ((DevStatus & BIT7) != 0) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "EmmcSwitchClockFreq: The switch operation fails as DevStatus 0x%08x\n",
+ DevStatus
+ ));
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Convert the clock freq unit from MHz to KHz.
+ //
+ Status = DwMmcHcClockSupply (DevBase, ClockFreq * 1000, Private->Capability[0]);
+
+ return Status;
+}
+
+/**
+ Switch to the High Speed timing according to request.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8.
+
+ @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] ClockFreq The max clock frequency to be set.
+ @param[in] IsDdr If TRUE, use dual data rate data simpling method.
+ Otherwise use single data rate data simpling method.
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchToHighSpeed (
+ IN UINTN DevBase,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT16 Rca,
+ IN UINT32 ClockFreq,
+ IN BOOLEAN IsDdr,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HsTiming;
+
+ HsTiming = 1;
+ Status = EmmcSwitchClockFreq (DevBase, PassThru, Rca, HsTiming, ClockFreq);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = EmmcSwitchBusWidth (DevBase, PassThru, Rca, IsDdr, BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Switch to the HS200 timing according to request.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8.
+
+ @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] ClockFreq The max clock frequency to be set.
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchToHS200 (
+ IN UINTN DevBase,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT16 Rca,
+ IN UINT32 ClockFreq,
+ IN UINT8 BusWidth
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Switch the high speed timing according to request.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8.
+
+ @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Rca The relative device address to be assigned.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSetBusMode (
+ IN UINTN DevBase,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT16 Rca
+ )
+{
+ EFI_STATUS Status;
+ EMMC_CSD Csd;
+ EMMC_EXT_CSD ExtCsd;
+ UINT8 HsTiming;
+ BOOLEAN IsDdr;
+ UINT32 DevStatus;
+ UINT32 ClockFreq;
+ UINT8 BusWidth;
+ DW_MMC_HC_PRIVATE_DATA *Private;
+
+ Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+ ASSERT (Private->Capability[0].BaseClkFreq != 0);
+
+ Status = EmmcGetCsd (PassThru, Rca, &Csd);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetCsd fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = EmmcSelect (PassThru, Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: Select fails with %r\n", Status));
+ return Status;
+ }
+
+ do {
+ Status = EmmcSendStatus (PassThru, Rca, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "EmmcSetBusMode: Get Status fails with %r\n",
+ Status
+ ));
+ return Status;
+ }
+ } while (EMMC_GET_STATE (DevStatus) != EMMC_STATE_TRAN);
+
+ BusWidth = 1;
+ Status = EmmcSwitchBusWidth (DevBase, PassThru, Rca, FALSE, BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BusWidth = Private->Capability[0].BusWidth;
+ //
+ // Get Deivce_Type from EXT_CSD register.
+ //
+ Status = EmmcGetExtCsd (PassThru, &ExtCsd);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetExtCsd fails with %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Calculate supported bus speed/bus width/clock frequency.
+ //
+ HsTiming = 0;
+ IsDdr = FALSE;
+ ClockFreq = 0;
+ if (((ExtCsd.DeviceType & (BIT4 | BIT5)) != 0) &&
+ (Private->Capability[0].Sdr104 != 0)) {
+ HsTiming = 2;
+ IsDdr = FALSE;
+ ClockFreq = 200;
+ } else if (((ExtCsd.DeviceType & (BIT2 | BIT3)) != 0) &&
+ (Private->Capability[0].Ddr50 != 0)) {
+ HsTiming = 1;
+ IsDdr = TRUE;
+ ClockFreq = 52;
+ } else if (((ExtCsd.DeviceType & BIT1) != 0) &&
+ (Private->Capability[0].HighSpeed != 0)) {
+ HsTiming = 1;
+ IsDdr = FALSE;
+ ClockFreq = 52;
+ } else if (((ExtCsd.DeviceType & BIT0) != 0) &&
+ (Private->Capability[0].HighSpeed != 0)) {
+ HsTiming = 1;
+ IsDdr = FALSE;
+ ClockFreq = 26;
+ }
+
+ if ((ClockFreq == 0) || (HsTiming == 0)) {
+ //
+ // Continue using default setting.
+ //
+ return EFI_SUCCESS;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "EmmcSetBusMode: HsTiming %d ClockFreq %d BusWidth %d Ddr %a\n",
+ HsTiming,
+ ClockFreq,
+ BusWidth,
+ IsDdr ? "TRUE" : "FALSE"
+ ));
+
+ if (HsTiming == 2) {
+ //
+ // Execute HS200 timing switch procedure
+ //
+ Status = EmmcSwitchToHS200 (DevBase, PassThru, Rca, ClockFreq, BusWidth);
+ } else {
+ //
+ // Execute High Speed timing switch procedure
+ //
+ Status = EmmcSwitchToHighSpeed (
+ DevBase,
+ PassThru,
+ Rca,
+ ClockFreq,
+ IsDdr,
+ BusWidth
+ );
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "EmmcSetBusMode: Switch to %a %r\n",
+ (HsTiming == 3) ? "HS400" : ((HsTiming == 2) ? "HS200" : "HighSpeed"),
+ Status
+ ));
+
+ return Status;
+}
+
+/**
+ Execute EMMC device identification procedure.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+ @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+
+ @retval EFI_SUCCESS There is a EMMC card.
+ @retval Others There is not a EMMC card.
+
+**/
+EFI_STATUS
+EmmcIdentification (
+ IN DW_MMC_HC_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINTN DevBase;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ UINT32 Ocr;
+ UINT16 Rca;
+ UINT32 DevStatus;
+ UINT32 Timeout;
+
+ DevBase = Private->DevBase;
+ PassThru = &Private->PassThru;
+
+ Status = EmmcReset (PassThru);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_INFO,
+ "EmmcIdentification: Executing Cmd0 fails with %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ Timeout = 100;
+ do {
+ Ocr = EMMC_CMD1_CAPACITY_GREATER_THAN_2GB;
+ Status = EmmcGetOcr (PassThru, &Ocr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_INFO,
+ "EmmcIdentification: Executing Cmd1 fails with %r\n",
+ Status
+ ));
+ return Status;
+ }
+ if (--Timeout <= 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ MicroSecondDelay (100);
+ } while ((Ocr & BIT31) == 0);
+
+ Status = EmmcGetAllCid (PassThru);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_INFO,
+ "EmmcIdentification: Executing Cmd2 fails with %r\n",
+ Status
+ ));
+ return Status;
+ }
+ //
+ // valid RCA starts from 1.
+ // Here we takes a simple formula to calculate the RCA.
+ // Don't support multiple devices on the slot, that is
+ // shared bus slot feature.
+ //
+ Rca = 1;
+ Status = EmmcSetRca (PassThru, Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_INFO,
+ "EmmcIdentification: Executing Cmd3 fails with %r\n",
+ Status
+ ));
+ return Status;
+ }
+ //
+ // Enter Data Tranfer Mode.
+ //
+ DEBUG ((
+ DEBUG_INFO,
+ "EmmcIdentification: Found a EMMC device at RCA [%d]\n",
+ Rca
+ ));
+ Private->Slot[0].CardType = EmmcCardType;
+
+ Status = EmmcSetBusMode (DevBase, PassThru, Rca);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Exit DATA Mode.
+ //
+ do {
+ Status = EmmcSendStatus (PassThru, Rca, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_INFO,
+ "EmmcSwitchBusWidth: Send status fails with %r\n",
+ Status
+ ));
+ return Status;
+ }
+ } while ((DevStatus & 0xf) == EMMC_STATE_DATA);
+
+ return Status;
+}
diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c b/EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
new file mode 100644
index 000000000000..63246637b6dd
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
@@ -0,0 +1,1105 @@
+/** @file
+ This file provides some helper functions which are specific for SD card
+ device.
+
+ Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2018, Linaro. 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 <IndustryStandard/Sd.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+
+#include "DwMmcHcDxe.h"
+
+/**
+ Send command GO_IDLE_STATE to the device to make it go to Idle State.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+
+ @retval EFI_SUCCESS The SD device is reset correctly.
+ @retval Others The device reset fails.
+
+**/
+EFI_STATUS
+SdCardReset (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_GO_IDLE_STATE;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+ //Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_IF_COND to the device to inquiry the SD Memory Card
+ interface condition.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] SupplyVoltage The supplied voltage by the host.
+ @param[in] CheckPattern The check pattern to be sent to the device.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardVoltageCheck (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 SupplyVoltage,
+ IN UINT8 CheckPattern
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_IF_COND;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR7;
+ SdMmcCmdBlk.CommandArgument = (SupplyVoltage << 8) | CheckPattern;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+
+ if (!EFI_ERROR (Status)) {
+ if (SdMmcStatusBlk.Resp0 != SdMmcCmdBlk.CommandArgument) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Send command SDIO_SEND_OP_COND to the device to see whether it is SDIO device.
+
+ Refer to SDIO Simplified Spec 3 Section 3.2 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] VoltageWindow The supply voltage window.
+ @param[in] S18R The boolean to show if it should switch to 1.8v.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdioSendOpCond (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT32 VoltageWindow,
+ IN BOOLEAN S18R
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT32 Switch;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SDIO_SEND_OP_COND;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR4;
+
+ Switch = S18R ? BIT24 : 0;
+
+ SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SD_SEND_OP_COND to the device to see whether it is SDIO device.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Rca The relative device address of addressed device.
+ @param[in] VoltageWindow The supply voltage window.
+ @param[in] S18R The boolean to show if it should switch to 1.8v.
+ @param[in] Xpc The boolean to show if it should provide 0.36w
+ power control.
+ @param[in] Hcs The boolean to show if it support host capacity
+ info.
+ @param[out] Ocr The buffer to store returned OCR register value.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSendOpCond (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT16 Rca,
+ IN UINT32 VoltageWindow,
+ IN BOOLEAN S18R,
+ IN BOOLEAN Xpc,
+ IN BOOLEAN Hcs,
+ OUT UINT32 *Ocr
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT32 Switch;
+ UINT32 MaxPower;
+ UINT32 HostCapacity;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_OP_COND;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;
+
+ Switch = S18R ? BIT24 : 0;
+ MaxPower = Xpc ? BIT28 : 0;
+ HostCapacity = Hcs ? BIT30 : 0;
+
+ SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch | \
+ MaxPower | HostCapacity;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ *Ocr = SdMmcStatusBlk.Resp0;
+ }
+
+ return Status;
+}
+
+/**
+ Broadcast command ALL_SEND_CID to the bus to ask all the SD devices to send
+ the data of their CID registers.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardAllSendCid (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_ALL_SEND_CID;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SET_RELATIVE_ADDR to the SD device to assign a Relative device
+ Address (RCA).
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[out] Rca The relative device address to assign.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSetRca (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ OUT UINT16 *Rca
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_CSD to the SD device to get the data of the CSD register.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Rca The relative device address of selected device.
+ @param[out] Csd The buffer to store the content of the CSD register.
+ Note the caller should ignore the lowest byte of
+ this buffer as the content of this byte is meaning-
+ less even if the operation succeeds.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardGetCsd (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT16 Rca,
+ OUT SD_CSD *Csd
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_CSD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1);
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_CSD to the SD device to get the data of the CSD register.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Rca The relative device address of selected device.
+ @param[out] Scr The buffer to store the content of the SCR register.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardGetScr (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT16 Rca,
+ OUT SD_SCR *Scr
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_SCR;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+ Packet.InDataBuffer = Scr;
+ Packet.InTransferLength = sizeof (SD_SCR);
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SELECT_DESELECT_CARD to the SD device to select/deselect it.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Rca The relative device address of selected device.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSelect (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT16 Rca
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ if (Rca != 0) {
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
+ }
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command VOLTAGE_SWITCH to the SD device to switch the voltage of the
+ device.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardVoltageSwitch (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_VOLTAGE_SWITCH;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SET_BUS_WIDTH to the SD device to set the bus width.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Rca The relative device address of addressed device.
+ @param[in] BusWidth The bus width to be set, it could be 1 or 4.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSetBusWidth (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT16 Rca,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT8 Value;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SdMmcCmdBlk.CommandIndex = SD_SET_BUS_WIDTH;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+ if (BusWidth == 1) {
+ Value = 0;
+ } else if (BusWidth == 4) {
+ Value = 2;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SdMmcCmdBlk.CommandArgument = Value & 0x3;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+ return Status;
+}
+
+/**
+ Send command SWITCH_FUNC to the SD device to check switchable function or
+ switch card function.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] AccessMode The value for access mode group.
+ @param[in] CommandSystem The value for command set group.
+ @param[in] DriveStrength The value for drive length group.
+ @param[in] PowerLimit The value for power limit group.
+ @param[in] Mode Switch or check function.
+ @param[out] SwitchResp The return switch function status.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSwitch (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 AccessMode,
+ IN UINT8 CommandSystem,
+ IN UINT8 DriveStrength,
+ IN UINT8 PowerLimit,
+ IN BOOLEAN Mode,
+ OUT UINT8 *SwitchResp
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT32 ModeValue;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SWITCH_FUNC;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+ ModeValue = Mode ? BIT31 : 0;
+ SdMmcCmdBlk.CommandArgument = (AccessMode & 0xF) | \
+ ((PowerLimit & 0xF) << 4) | \
+ ((DriveStrength & 0xF) << 8) | \
+ ((DriveStrength & 0xF) << 12) | \
+ ModeValue;
+
+ Packet.InDataBuffer = SwitchResp;
+ Packet.InTransferLength = 64;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_STATUS to the addressed SD device to get its status
+ register.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Rca The relative device address of addressed device.
+ @param[out] DevStatus The returned device status.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSendStatus (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT16 Rca,
+ OUT UINT32 *DevStatus
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ *DevStatus = SdMmcStatusBlk.Resp0;
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_TUNING_BLOCK to the SD device for HS200 optimal sampling
+ point detection.
+
+ It may be sent up to 40 times until the host finishes the tuning procedure.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSendTuningBlk (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
+ )
+{
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+ EFI_STATUS Status;
+ UINT8 TuningBlock[64];
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_TUNING_BLOCK;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ Packet.InDataBuffer = TuningBlock;
+ Packet.InTransferLength = sizeof (TuningBlock);
+
+ Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Switch the bus width to specified width.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and
+ SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSwitchBusWidth (
+ IN UINTN DevBase,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT16 Rca,
+ IN BOOLEAN IsDdr,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT32 DevStatus;
+
+ Status = SdCardSetBusWidth (PassThru, Rca, BusWidth);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "SdCardSwitchBusWidth: Switch to bus width %d fails with %r\n",
+ BusWidth,
+ Status
+ ));
+ return Status;
+ }
+
+ Status = SdCardSendStatus (PassThru, Rca, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "SdCardSwitchBusWidth: Send status fails with %r\n",
+ Status
+ ));
+ return Status;
+ }
+ //
+ // Check the switch operation is really successful or not.
+ //
+ if ((DevStatus >> 16) != 0) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "SdCardSwitchBusWidth: The switch operation fails as DevStatus 0x%08x\n",
+ DevStatus
+ ));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = DwMmcHcSetBusWidth (DevBase, IsDdr, BusWidth);
+
+ return Status;
+}
+
+/**
+ Switch the high speed timing according to request.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+ instance.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] S18A The boolean to show if it's a UHS-I SD card.
+ @param[in] BusWidths The bus width of the SD card.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSetBusMode (
+ IN UINTN DevBase,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT16 Rca,
+ IN BOOLEAN S18A,
+ IN UINT32 BusWidths
+ )
+{
+ EFI_STATUS Status;
+ DW_MMC_HC_SLOT_CAP *Capability;
+ UINT32 ClockFreq;
+ UINT8 AccessMode;
+ UINT8 SwitchResp[64];
+ DW_MMC_HC_PRIVATE_DATA *Private;
+ BOOLEAN IsDdr;
+
+ Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+
+ Capability = &Private->Capability[0];
+
+ if ((Capability->BusWidth == 1) || (Capability->BusWidth == 4)) {
+ BusWidths &= Capability[0].BusWidth;
+ } else {
+ DEBUG ((
+ DEBUG_ERROR,
+ "SdCardSetBusMode: BusWidths (%d) in capability are wrong\n",
+ Capability->BusWidth
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BusWidths == 0) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "SdCardSetBusMode: Get wrong BusWidths:%d\n",
+ BusWidths
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Private->Capability[0].Ddr50) {
+ IsDdr = TRUE;
+ } else {
+ IsDdr = FALSE;
+ }
+
+ Status = SdCardSwitchBusWidth (DevBase, PassThru, Rca, IsDdr, BusWidths);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "SdCardSetBusMode: Executing SdCardSwitchBusWidth fails with %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ //
+ // Get the supported bus speed from SWITCH cmd return data group #1.
+ //
+ Status = SdCardSwitch (PassThru, 0xF, 0xF, 0xF, 0xF, FALSE, SwitchResp);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Calculate supported bus speed/bus width/clock frequency by host and device
+ // capability.
+ //
+ ClockFreq = 0;
+ if (S18A && (Capability->Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) {
+ ClockFreq = 208;
+ AccessMode = 3;
+ } else if (S18A && (Capability->Sdr50 != 0) &&
+ ((SwitchResp[13] & BIT2) != 0)) {
+ ClockFreq = 100;
+ AccessMode = 2;
+ } else if (S18A && (Capability->Ddr50 != 0) &&
+ ((SwitchResp[13] & BIT4) != 0)) {
+ ClockFreq = 50;
+ AccessMode = 4;
+ } else if ((SwitchResp[13] & BIT1) != 0) {
+ ClockFreq = 50;
+ AccessMode = 1;
+ } else {
+ ClockFreq = 25;
+ AccessMode = 0;
+ }
+
+ Status = SdCardSwitch (PassThru, AccessMode, 0xF, 0xF, 0xF, TRUE, SwitchResp);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((SwitchResp[16] & 0xF) != AccessMode) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "SdCardSetBusMode: Switch to AccessMode %d ClockFreq %d fails! The Switch response is 0x%1x\n",
+ AccessMode,
+ ClockFreq,
+ SwitchResp[16] & 0xF
+ ));
+ return EFI_DEVICE_ERROR;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "SdCardSetBusMode: Switch to AccessMode %d ClockFreq %d \n",
+ AccessMode,
+ ClockFreq
+ ));
+
+ Status = DwMmcHcClockSupply (DevBase, ClockFreq * 1000, *Capability);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+SdCardIdentification (
+ IN DW_MMC_HC_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINTN DevBase;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ UINT32 Ocr;
+ UINT16 Rca;
+ BOOLEAN Xpc;
+ BOOLEAN S18r;
+ UINT64 MaxCurrent;
+ SD_SCR Scr;
+ SD_CSD Csd;
+
+ DevBase = Private->DevBase;
+ PassThru = &Private->PassThru;
+ //
+ // 1. Send Cmd0 to the device
+ //
+ Status = SdCardReset (PassThru);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_INFO,
+ "SdCardIdentification: Executing Cmd0 fails with %r\n",
+ Status
+ ));
+ return Status;
+ }
+ MicroSecondDelay (10000);
+ //
+ // 2. Send Cmd8 to the device
+ //
+ Status = SdCardVoltageCheck (PassThru, 0x1, 0xFF);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_INFO,
+ "SdCardIdentification: Executing Cmd8 fails with %r\n",
+ Status
+ ));
+ return Status;
+ }
+ //
+ // 3. Send Acmd41 with voltage window 0 to the device
+ //
+ Status = SdCardSendOpCond (PassThru, 0, 0, FALSE, FALSE, FALSE, &Ocr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_INFO,
+ "SdCardIdentification: Executing SdCardSendOpCond fails with %r\n",
+ Status
+ ));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Private->Capability[0].Voltage33 != 0) {
+ //
+ // Support 3.3V
+ //
+ MaxCurrent = ((UINT32)Private->MaxCurrent[0] & 0xFF) * 4;
+ S18r = FALSE;
+ } else if (Private->Capability[0].Voltage30 != 0) {
+ //
+ // Support 3.0V
+ //
+ MaxCurrent = (((UINT32)Private->MaxCurrent[0] >> 8) & 0xFF) * 4;
+ S18r = FALSE;
+ } else if (Private->Capability[0].Voltage18 != 0) {
+ //
+ // Support 1.8V
+ //
+ MaxCurrent = (((UINT32)Private->MaxCurrent[0] >> 16) & 0xFF) * 4;
+ S18r = TRUE;
+ } else {
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (MaxCurrent >= 150) {
+ Xpc = TRUE;
+ } else {
+ Xpc = FALSE;
+ }
+
+ //
+ // 4. Repeatly send Acmd41 with supply voltage window to the device.
+ // Note here we only support the cards complied with SD physical
+ // layer simplified spec version 2.0 and version 3.0 and above.
+ //
+ do {
+ Status = SdCardSendOpCond (PassThru, 0, Ocr, S18r, Xpc, TRUE, &Ocr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "SdCardIdentification: SdCardSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n",
+ Status,
+ Ocr,
+ S18r,
+ Xpc
+ ));
+ return EFI_DEVICE_ERROR;
+ }
+ } while ((Ocr & BIT31) == 0);
+
+ Status = SdCardAllSendCid (PassThru);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "SdCardIdentification: Executing SdCardAllSendCid fails with %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ Status = SdCardSetRca (PassThru, &Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "SdCardIdentification: Executing SdCardSetRca fails with %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ Status = SdCardGetCsd (PassThru, Rca, &Csd);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "SdCardIdentification: Executing SdCardGetCsd fails with %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ Status = SdCardSelect (PassThru, Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "SdCardIdentification: Selecting card fails with %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ Status = SdCardGetScr (PassThru, Rca, &Scr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "SdCardIdentification: Executing SdCardGetScr fails with %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ //
+ // Enter Data Tranfer Mode.
+ //
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Found a SD device\n"));
+ Private->Slot[0].CardType = SdCardType;
+
+ Status = SdCardSetBusMode (DevBase, PassThru, Rca, S18r, Scr.SdBusWidths);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private->Slot[0].Initialized = TRUE;
+
+ return Status;
+}
--
2.12.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [edk2-devel] [PATCH V4 1/1] EmbeddedPkg: DwMmcHcDxe: Add support for Designware SDMMC driver
2021-03-19 8:22 ` Loh, Tien Hock
@ 2021-03-19 15:33 ` Michael D Kinney
2021-03-22 3:32 ` Loh, Tien Hock
0 siblings, 1 reply; 4+ messages in thread
From: Michael D Kinney @ 2021-03-19 15:33 UTC (permalink / raw)
To: devel@edk2.groups.io, Loh, Tien Hock, Kinney, Michael D
Cc: thloh85@gmail.com, Leif Lindholm, Ard Biesheuvel
Hello,
The majority of the EDK II files use BSD 2-Clause Plus Patent license with SPDX identifiers in the source file headers:
https://github.com/tianocore/edk2#license-details
https://github.com/tianocore/edk2/blob/master/License.txt
# SPDX-License-Identifier: BSD-2-Clause-Patent
Can this content be updated to use that license and file header style?
Thanks,
Mike
> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Loh, Tien Hock
> Sent: Friday, March 19, 2021 1:22 AM
> To: devel@edk2.groups.io
> Cc: Loh, Tien Hock <tien.hock.loh@intel.com>; thloh85@gmail.com; Leif Lindholm <leif@nuviainc.com>; Ard Biesheuvel
> <ardb+tianocore@kernel.org>
> Subject: [edk2-devel] [PATCH V4 1/1] EmbeddedPkg: DwMmcHcDxe: Add support for Designware SDMMC driver
>
> From: "Tien Hock, Loh" <tien.hock.loh@intel.com>
>
> This adds support for Designware SDMMC driver. The SDMMC driver depends on
> MdeModulePkg/Bus/Sd/, and produces EFI_SD_MMC_PASS_THRU_PROTOCOL. The
> driver uses MMIO to read/write, and uses
> gEdkiiNonDiscoverableDeviceProtocolGuid. Platform needs to register device
> with gEdkiiNonDiscoverableDeviceProtocolGuid.
>
> Signed-off-by: Loh Tien Hock <tien.hock.loh@intel.com>
> Cc: Leif Lindholm <leif@nuviainc.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> ---
> EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec | 40 +
> EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf | 70 +
> EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h | 817 ++++++++++
> EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h | 985 ++++++++++++
> EmbeddedPkg/Include/Protocol/PlatformDwMmc.h | 79 +
> EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c | 214 +++
> EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c | 1296 ++++++++++++++++
> EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c | 1602 ++++++++++++++++++++
> EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c | 1042 +++++++++++++
> EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c | 1105 ++++++++++++++
> 10 files changed, 7250 insertions(+)
>
> diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
> new file mode 100644
> index 000000000000..cf85ccb1a030
> --- /dev/null
> +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
> @@ -0,0 +1,40 @@
> +#/** @file
> +# Framework Module Development Environment Industry Standards
> +#
> +# This Package provides headers and libraries that conform to EFI/PI Industry standards.
> +# Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
> +# Copyright (c) 2012-2014, ARM Ltd. All rights reserved.<BR>
> +# Copyright (c) 2018, Linaro. 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]
> + DEC_SPECIFICATION = 0x00010019
> + PACKAGE_NAME = DwMmcHcDxePkg
> + PACKAGE_GUID = e73097ce-1fe2-41a6-a930-3136bc6d23ef
> + PACKAGE_VERSION = 0.1
> +
> +
> +################################################################################
> +#
> +# Include Section - list of Include Paths that are provided by this package.
> +# Comments are used for Keywords and Module Types.
> +#
> +# Supported Module Types:
> +# BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER
> UEFI_APPLICATION
> +#
> +################################################################################
> +
> +[Guids.common]
> + gDwMmcHcDxeTokenSpaceGuid = { 0x576c132e, 0x7d51, 0x4abb, { 0xbc, 0x60, 0x13, 0x08, 0x04, 0x0e, 0x90, 0x92 }}
> +
> +[Protocols.common]
> + gPlatformDwMmcProtocolGuid = { 0x1d6dfde5, 0x76a7, 0x4404, { 0x85, 0x74, 0x7a, 0xdf, 0x1a, 0x8a, 0xa2, 0x0d }}
> diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
> new file mode 100644
> index 000000000000..4cd0960ef9c3
> --- /dev/null
> +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
> @@ -0,0 +1,70 @@
> +## @file
> +# DwSdMmcHcDxe driver is used to manage those host controllers which comply with
> +# Designware SD Host Controller.
> +#
> +# It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC/eMMC cmds
> +# to specified devices from upper layer.
> +#
> +# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
> +# Copyright (C) 2016, Marvell International Ltd. All rights reserved.<BR>
> +# Copyright (c) 2018, Linaro Ltd. 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 = 0x00010019
> + BASE_NAME = DwMmcHcDxe
> + MODULE_UNI_FILE = DwMmcHcDxe.uni
> + FILE_GUID = 9be4d260-208c-4efe-a524-0b5d3bf77f9d
> + MODULE_TYPE = UEFI_DRIVER
> + VERSION_STRING = 1.0
> + ENTRY_POINT = InitializeDwMmcHcDxe
> +
> +[Sources]
> + ComponentName.c
> + DwMmcHcDxe.c
> + DwMmcHcDxe.h
> + DwMmcHci.c
> + DwMmcHci.h
> + EmmcDevice.c
> + SdDevice.c
> +
> +[Packages]
> + ArmPkg/ArmPkg.dec
> + EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
> + EmbeddedPkg/EmbeddedPkg.dec
> + MdeModulePkg/MdeModulePkg.dec
> + MdePkg/MdePkg.dec
> +
> +[LibraryClasses]
> + ArmLib
> + BaseLib
> + BaseMemoryLib
> + CacheMaintenanceLib
> + DebugLib
> + DevicePathLib
> + DmaLib
> + MemoryAllocationLib
> + TimerLib
> + UefiBootServicesTableLib
> + UefiDriverEntryPoint
> + UefiLib
> + UefiRuntimeServicesTableLib
> +
> +[Protocols]
> + gEdkiiNonDiscoverableDeviceProtocolGuid
> + gEfiDevicePathProtocolGuid ## TO_START
> + gEfiPciIoProtocolGuid ## TO_START
> + gEfiSdMmcPassThruProtocolGuid ## BY_START
> + gPlatformDwMmcProtocolGuid
> +
> +[UserExtensions.TianoCore."ExtraFiles"]
> + DwMmcHcDxeExtra.uni
> diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
> new file mode 100644
> index 000000000000..b783d9830325
> --- /dev/null
> +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
> @@ -0,0 +1,817 @@
> +/** @file
> +
> + Provides some data structure definitions used by the Designware SD/MMC
> + host controller driver.
> +
> + Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
> + Copyright (C) 2018, Linaro Ltd. All rigths 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 _DW_MMC_HC_DXE_H_
> +#define _DW_MMC_HC_DXE_H_
> +
> +#include <Uefi.h>
> +
> +#include <Library/UefiLib.h>
> +
> +#include <Protocol/ComponentName.h>
> +#include <Protocol/ComponentName2.h>
> +#include <Protocol/DeviceIo.h>
> +#include <Protocol/DriverBinding.h>
> +#include <Protocol/SdMmcPassThru.h>
> +
> +#include "DwMmcHci.h"
> +
> +extern EFI_COMPONENT_NAME_PROTOCOL gDwMmcHcComponentName;
> +extern EFI_COMPONENT_NAME2_PROTOCOL gDwMmcHcComponentName2;
> +extern EFI_DRIVER_BINDING_PROTOCOL gDwMmcHcDriverBinding;
> +
> +#define DW_MMC_HC_PRIVATE_SIGNATURE SIGNATURE_32 ('d', 'w', 's', 'd')
> +
> +#define DW_MMC_HC_PRIVATE_FROM_THIS(a) \
> + CR(a, DW_MMC_HC_PRIVATE_DATA, PassThru, DW_MMC_HC_PRIVATE_SIGNATURE)
> +
> +//
> +// Generic time out value, 1 microsecond as unit.
> +//
> +#define DW_MMC_HC_GENERIC_TIMEOUT (1 * 1000 * 1000)
> +
> +//
> +// SD/MMC async transfer timer interval, set by experience.
> +// The unit is 100us, takes 1ms as interval.
> +//
> +#define DW_MMC_HC_ASYNC_TIMER EFI_TIMER_PERIOD_MILLISECONDS(1)
> +//
> +// SD/MMC removable device enumeration timer interval, set by experience.
> +// The unit is 100us, takes 100ms as interval.
> +//
> +#define DW_MMC_HC_ENUM_TIMER EFI_TIMER_PERIOD_MILLISECONDS(100)
> +
> +typedef struct {
> + BOOLEAN Enable;
> + EFI_SD_MMC_SLOT_TYPE SlotType;
> + BOOLEAN MediaPresent;
> + BOOLEAN Initialized;
> + SD_MMC_CARD_TYPE CardType;
> +} DW_MMC_HC_SLOT;
> +
> +typedef struct {
> + UINTN Signature;
> +
> + EFI_HANDLE ControllerHandle;
> +
> + // Mmio base address
> + UINTN DevBase;
> +
> + EFI_SD_MMC_PASS_THRU_PROTOCOL PassThru;
> +
> + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc;
> + //
> + // The field is used to record the previous slot in GetNextSlot().
> + //
> + UINT8 PreviousSlot;
> + //
> + // For Non-blocking operation.
> + //
> + EFI_EVENT TimerEvent;
> + //
> + // For Sd removable device enumeration.
> + //
> + EFI_EVENT ConnectEvent;
> + LIST_ENTRY Queue;
> +
> + DW_MMC_HC_SLOT Slot[DW_MMC_HC_MAX_SLOT];
> + DW_MMC_HC_SLOT_CAP Capability[DW_MMC_HC_MAX_SLOT];
> + UINT64 MaxCurrent[DW_MMC_HC_MAX_SLOT];
> +
> + UINT32 ControllerVersion;
> +} DW_MMC_HC_PRIVATE_DATA;
> +
> +#define DW_MMC_HC_TRB_SIG SIGNATURE_32 ('D', 'T', 'R', 'B')
> +
> +//
> +// TRB (Transfer Request Block) contains information for the cmd request.
> +//
> +typedef struct {
> + UINT32 Signature;
> + LIST_ENTRY TrbList;
> +
> + UINT8 Slot;
> + UINT16 BlockSize;
> +
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
> + VOID *Data;
> + UINT32 DataLen;
> + BOOLEAN Read;
> + EFI_PHYSICAL_ADDRESS DataPhy;
> + VOID *DataMap;
> + DW_MMC_HC_TRANSFER_MODE Mode;
> +
> + EFI_EVENT Event;
> + BOOLEAN Started;
> + UINT64 Timeout;
> +
> + DW_MMC_HC_DMA_DESC_LINE *DmaDesc;
> + EFI_PHYSICAL_ADDRESS DmaDescPhy;
> + UINT32 DmaDescPages;
> + VOID *DmaMap;
> +
> + BOOLEAN UseFifo;
> + BOOLEAN UseBE; // Big-endian
> +
> + DW_MMC_HC_PRIVATE_DATA *Private;
> +} DW_MMC_HC_TRB;
> +
> +#define DW_MMC_HC_TRB_FROM_THIS(a) \
> + CR(a, DW_MMC_HC_TRB, TrbList, DW_MMC_HC_TRB_SIG)
> +
> +//
> +// Task for Non-blocking mode.
> +//
> +typedef struct {
> + UINT32 Signature;
> + LIST_ENTRY Link;
> +
> + UINT8 Slot;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
> + BOOLEAN IsStart;
> + EFI_EVENT Event;
> + UINT64 RetryTimes;
> + BOOLEAN InfiniteWait;
> + VOID *Map;
> + VOID *MapAddress;
> +} DW_MMC_HC_QUEUE;
> +
> +//
> +// Prototypes
> +//
> +/**
> + Execute card identification procedure.
> +
> + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
> +
> + @retval EFI_SUCCESS The card is identified correctly.
> + @retval Others The card can't be identified.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(*DWMMC_CARD_TYPE_DETECT_ROUTINE) (
> + IN DW_MMC_HC_PRIVATE_DATA *Private
> + );
> +
> +/**
> + Sends SD command to an SD card that is attached to the SD controller.
> +
> + The PassThru() function sends the SD command specified by Packet to the SD
> + card specified by Slot.
> +
> + If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.
> +
> + If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is
> + returned.
> +
> + If Slot is not in a valid range for the SD controller, then
> + EFI_INVALID_PARAMETER is returned.
> +
> + If Packet defines a data command but both InDataBuffer and OutDataBuffer are
> + NULL, EFI_INVALID_PARAMETER is returned.
> +
> + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Slot The slot number of the SD card to send the
> + command to.
> + @param[in,out] Packet A pointer to the SD command data structure.
> + @param[in] Event If Event is NULL, blocking I/O is performed. If
> + Event is not NULL, then nonblocking I/O is
> + performed, and Event will be signaled when the
> + Packet completes.
> +
> + @retval EFI_SUCCESS The SD Command Packet was sent by the host.
> + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
> + the SD command Packet.
> + @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is
> + invalid.
> + @retval EFI_INVALID_PARAMETER Packet defines a data command but both
> + InDataBuffer and OutDataBuffer are NULL.
> + @retval EFI_NO_MEDIA SD Device not present in the Slot.
> + @retval EFI_UNSUPPORTED The command described by the SD Command Packet
> + is not supported by the host controller.
> + @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength
> + exceeds the limit supported by SD card ( i.e. if
> + the number of bytes exceed the Last LBA).
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcPassThruPassThru (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> + IN UINT8 Slot,
> + IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
> + IN EFI_EVENT Event OPTIONAL
> + );
> +
> +/**
> + Used to retrieve next slot numbers supported by the SD controller. The
> + function returns information about all available slots (populated or
> + not-populated).
> +
> + The GetNextSlot() function retrieves the next slot number on an SD controller.
> + If on input Slot is 0xFF, then the slot number of the first slot on the SD
> + controller is returned.
> +
> + If Slot is a slot number that was returned on a previous call to
> + GetNextSlot(), then the slot number of the next slot on the SD controller is
> + returned.
> +
> + If Slot is not 0xFF and Slot was not returned on a previous call to
> + GetNextSlot(), EFI_INVALID_PARAMETER is returned.
> +
> + If Slot is the slot number of the last slot on the SD controller, then
> + EFI_NOT_FOUND is returned.
> +
> + @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in,out] Slot On input, a pointer to a slot number on the SD
> + controller.
> + On output, a pointer to the next slot number on
> + the SD controller.
> + An input value of 0xFF retrieves the first slot
> + number on the SD controller.
> +
> + @retval EFI_SUCCESS The next slot number on the SD controller was
> + returned in Slot.
> + @retval EFI_NOT_FOUND There are no more slots on this SD controller.
> + @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a
> + previous call to GetNextSlot().
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcPassThruGetNextSlot (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> + IN OUT UINT8 *Slot
> + );
> +
> +/**
> + Used to allocate and build a device path node for an SD card on the SD
> + controller.
> +
> + The BuildDevicePath() function allocates and builds a single device node
> + for the SD
> + card specified by Slot.
> +
> + If the SD card specified by Slot is not present on the SD controller, then
> + EFI_NOT_FOUND is returned.
> +
> + If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.
> +
> + If there are not enough resources to allocate the device path node, then
> + EFI_OUT_OF_RESOURCES is returned.
> +
> + Otherwise, DevicePath is allocated with the boot service AllocatePool(), the
> + contents of DevicePath are initialized to describe the SD card specified by
> + Slot, and EFI_SUCCESS is returned.
> +
> + @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Slot Specifies the slot number of the SD card for
> + which a device path node is to be allocated and
> + built.
> + @param[in,out] DevicePath A pointer to a single device path node that
> + describes the SD card specified by Slot. This
> + function is responsible for allocating the
> + buffer DevicePath with the boot service
> + AllocatePool(). It is the caller's responsibi-
> + lity to free DevicePath when the caller is
> + finished with DevicePath.
> +
> + @retval EFI_SUCCESS The device path node that describes the SD card
> + specified by Slot was allocated and returned in
> + DevicePath.
> + @retval EFI_NOT_FOUND The SD card specified by Slot does not exist on
> + the SD controller.
> + @retval EFI_INVALID_PARAMETER DevicePath is NULL.
> + @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate
> + DevicePath.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcPassThruBuildDevicePath (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> + IN UINT8 Slot,
> + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
> + );
> +
> +/**
> + This function retrieves an SD card slot number based on the input device path.
> +
> + The GetSlotNumber() function retrieves slot number for the SD card specified
> + by the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is
> + returned.
> +
> + If DevicePath is not a device path node type that the SD Pass Thru driver
> + supports, EFI_UNSUPPORTED is returned.
> +
> + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] DevicePath A pointer to the device path node that describes
> + a SD card on the SD controller.
> + @param[out] Slot On return, points to the slot number of an SD
> + card on the SD controller.
> +
> + @retval EFI_SUCCESS SD card slot number is returned in Slot.
> + @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.
> + @retval EFI_UNSUPPORTED DevicePath is not a device path node type that
> + the SD Pass Thru driver supports.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcPassThruGetSlotNumber (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
> + OUT UINT8 *Slot
> + );
> +
> +/**
> + Resets an SD card that is connected to the SD controller.
> +
> + The ResetDevice() function resets the SD card specified by Slot.
> +
> + If this SD controller does not support a device reset operation,
> + EFI_UNSUPPORTED is returned.
> +
> + If Slot is not in a valid slot number for this SD controller,
> + EFI_INVALID_PARAMETER is returned.
> +
> + If the device reset operation is completed, EFI_SUCCESS is returned.
> +
> + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Slot Specifies the slot number of the SD card to be
> + reset.
> +
> + @retval EFI_SUCCESS The SD card specified by Slot was reset.
> + @retval EFI_UNSUPPORTED The SD controller does not support a device
> + reset operation.
> + @retval EFI_INVALID_PARAMETER Slot number is invalid.
> + @retval EFI_NO_MEDIA SD Device not present in the Slot.
> + @retval EFI_DEVICE_ERROR The reset command failed due to a device error
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcPassThruResetDevice (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> + IN UINT8 Slot
> + );
> +
> +//
> +// Driver model protocol interfaces
> +//
> +/**
> + Tests to see if this driver supports a given controller. If a child device is
> + provided, it further tests to see if this driver supports creating a handle
> + for the specified child device.
> +
> + This function checks to see if the driver specified by This supports the
> + device specified by ControllerHandle. Drivers will typically use the device
> + path attached to ControllerHandle and/or the services from the bus I/O
> + abstraction attached to ControllerHandle to determine if the driver supports
> + ControllerHandle. This function may be called many times during platform
> + initialization. In order to reduce boot times, the tests performed by this
> + function must be very small, and take as little time as possible to execute.
> + This function must not change the state of any hardware devices, and this
> + function must be aware that the device specified by ControllerHandle may
> + already be managed by the same driver or a different driver. This function
> + must match its calls to AllocatePages() with FreePages(), AllocatePool() with
> + FreePool(), and OpenProtocol() with CloseProtocol().
> + Since ControllerHandle may have been previously started by the same driver, if
> + a protocol is already in the opened state, then it must not be closed with
> + CloseProtocol(). This is required to guarantee the state of ControllerHandle
> + is not modified by this function.
> +
> + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
> + instance.
> + @param[in] ControllerHandle The handle of the controller to test. This
> + handle must support a protocol interface that
> + supplies an I/O abstraction to the driver.
> + @param[in] RemainingDevicePath A pointer to the remaining portion of a
> + device path. This parameter is ignored by
> + device drivers, and is optional for bus
> + drivers. For bus drivers, if this parameter
> + is not NULL, then the bus driver must deter-
> + mine if the bus controller specified by
> + ControllerHandle and the child controller
> + specified by RemainingDevicePath are both
> + supported by this bus driver.
> +
> + @retval EFI_SUCCESS The device specified by ControllerHandle and
> + RemainingDevicePath is supported by the
> + driver specified by This.
> + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
> + RemainingDevicePath is already being managed
> + by the driver specified by This.
> + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
> + RemainingDevicePath is already being managed
> + by a different driver or an application that
> + requires exclusive access.
> + Currently not implemented.
> + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
> + RemainingDevicePath is not supported by the
> + driver specified by This.
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcHcDriverBindingSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +/**
> + Starts a device controller or a bus controller.
> +
> + The Start() function is designed to be invoked from the EFI boot service
> + ConnectController().
> + As a result, much of the error checking on the parameters to Start() has been
> + moved into this common boot service. It is legal to call Start() from other
> + locations,
> + but the following calling restrictions must be followed or the system behavior
> + will not be deterministic.
> + 1. ControllerHandle must be a valid EFI_HANDLE.
> + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a natural-
> + ly aligned EFI_DEVICE_PATH_PROTOCOL.
> + 3. Prior to calling Start(), the Supported() function for the driver specified
> + by This must have been called with the same calling parameters, and
> + Supported() must have returned EFI_SUCCESS.
> +
> + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
> + instance.
> + @param[in] ControllerHandle The handle of the controller to start. This
> + handle must support a protocol interface that
> + supplies an I/O abstraction to the driver.
> + @param[in] RemainingDevicePath A pointer to the remaining portion of a
> + device path. This parameter is ignored by
> + device drivers, and is optional for bus dri-
> + vers. For a bus driver, if this parameter is
> + NULL, then handles for all the children of
> + Controller are created by this driver.
> + If this parameter is not NULL and the first
> + Device Path Node is not the End of Device
> + Path Node, then only the handle for the
> + child device specified by the first Device
> + Path Node of RemainingDevicePath is created
> + by this driver.
> + If the first Device Path Node of
> + RemainingDevicePath is the End of Device Path
> + Node, no child handle is created by this
> + driver.
> +
> + @retval EFI_SUCCESS The device was started.
> + @retval EFI_DEVICE_ERROR The device could not be started due to a
> + device error. Currently not implemented.
> + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
> + lack of resources.
> + @retval Others The driver failded to start the device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcHcDriverBindingStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + );
> +
> +/**
> + Stops a device controller or a bus controller.
> +
> + The Stop() function is designed to be invoked from the EFI boot service
> + DisconnectController().
> + As a result, much of the error checking on the parameters to Stop() has been
> + moved into this common boot service. It is legal to call Stop() from other
> + locations, but the following calling restrictions must be followed or the
> + system behavior will not be deterministic.
> + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous
> + call to this same driver's Start() function.
> + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
> + EFI_HANDLE. In addition, all of these handles must have been created in
> + this driver's Start() function, and the Start() function must have called
> + OpenProtocol() on ControllerHandle with an Attribute of
> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
> +
> + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
> + instance.
> + @param[in] ControllerHandle A handle to the device being stopped. The handle
> + must support a bus specific I/O protocol for the
> + driver to use to stop the device.
> + @param[in] NumberOfChildren The number of child device handles in
> + ChildHandleBuffer.
> + @param[in] ChildHandleBuffer An array of child handles to be freed. May be
> + NULL if NumberOfChildren is 0.
> +
> + @retval EFI_SUCCESS The device was stopped.
> + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device
> + error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcHcDriverBindingStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + );
> +
> +//
> +// EFI Component Name Functions
> +//
> +/**
> + Retrieves a Unicode string that is the user readable name of the driver.
> +
> + This function retrieves the user readable name of a driver in the form of a
> + Unicode string. If the driver specified by This has a user readable name in
> + the language specified by Language, then a pointer to the driver name is
> + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
> + by This does not support the language specified by Language,
> + then EFI_UNSUPPORTED is returned.
> +
> + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> +
> + @param Language[in] A pointer to a Null-terminated ASCII string
> + array indicating the language. This is the
> + language of the driver name 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. Language is specified
> + in RFC 4646 or ISO 639-2 language code format.
> +
> + @param DriverName[out] 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
> +DwMmcHcComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + );
> +
> +/**
> + Retrieves a Unicode string that is the user readable name of the controller
> + that is being managed by a driver.
> +
> + This function retrieves the user readable name of the controller specified by
> + ControllerHandle and ChildHandle in the form of a Unicode string. If the
> + driver specified by This has a user readable name in the language specified by
> + Language, then a pointer to the controller name is returned in ControllerName,
> + and EFI_SUCCESS is returned. If the driver specified by This is not currently
> + managing the controller specified by ControllerHandle and ChildHandle,
> + then EFI_UNSUPPORTED is returned. If the driver specified by This does not
> + support the language specified by Language, then EFI_UNSUPPORTED is returned.
> +
> + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> +
> + @param ControllerHandle[in] 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 ChildHandle[in] 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 Language[in] A pointer to a Null-terminated ASCII string
> + array indicating the language. This is the
> + language of the driver name 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. Language is specified in
> + RFC 4646 or ISO 639-2 language code format.
> +
> + @param ControllerName[out] 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
> +DwMmcHcComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_HANDLE ChildHandle, OPTIONAL
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + );
> +
> +/**
> + Create a new TRB for the SD/MMC cmd request.
> +
> + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
> + @param[in] Slot The slot number of the SD card to send the command
> + to.
> + @param[in] Packet A pointer to the SD command data structure.
> + @param[in] Event If Event is NULL, blocking I/O is performed.
> + If Event is not NULL, then nonblocking I/O is
> + performed, and Event will be signaled when the
> + Packet completes.
> +
> + @return Created Trb or NULL.
> +
> +**/
> +DW_MMC_HC_TRB *
> +DwMmcCreateTrb (
> + IN DW_MMC_HC_PRIVATE_DATA *Private,
> + IN UINT8 Slot,
> + IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
> + IN EFI_EVENT Event
> + );
> +
> +/**
> + Free the resource used by the TRB.
> +
> + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> +
> +**/
> +VOID
> +DwMmcFreeTrb (
> + IN DW_MMC_HC_TRB *Trb
> + );
> +
> +/**
> + Check if the env is ready for execute specified TRB.
> +
> + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
> + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> +
> + @retval EFI_SUCCESS The env is ready for TRB execution.
> + @retval EFI_NOT_READY The env is not ready for TRB execution.
> + @retval Others Some erros happen.
> +
> +**/
> +EFI_STATUS
> +DwMmcCheckTrbEnv (
> + IN DW_MMC_HC_PRIVATE_DATA *Private,
> + IN DW_MMC_HC_TRB *Trb
> + );
> +
> +/**
> + Wait for the env to be ready for execute specified TRB.
> +
> + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
> + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> +
> + @retval EFI_SUCCESS The env is ready for TRB execution.
> + @retval EFI_TIMEOUT The env is not ready for TRB execution in time.
> + @retval Others Some erros happen.
> +
> +**/
> +EFI_STATUS
> +DwMmcWaitTrbEnv (
> + IN DW_MMC_HC_PRIVATE_DATA *Private,
> + IN DW_MMC_HC_TRB *Trb
> + );
> +
> +/**
> + Execute the specified TRB.
> +
> + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
> + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> +
> + @retval EFI_SUCCESS The TRB is sent to host controller successfully.
> + @retval Others Some erros happen when sending this request to the
> + host controller.
> +
> +**/
> +EFI_STATUS
> +DwMmcExecTrb (
> + IN DW_MMC_HC_PRIVATE_DATA *Private,
> + IN DW_MMC_HC_TRB *Trb
> + );
> +
> +/**
> + Check the TRB execution result.
> +
> + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
> + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> +
> + @retval EFI_SUCCESS The TRB is executed successfully.
> + @retval EFI_NOT_READY The TRB is not completed for execution.
> + @retval Others Some erros happen when executing this request.
> +
> +**/
> +EFI_STATUS
> +DwMmcCheckTrbResult (
> + IN DW_MMC_HC_PRIVATE_DATA *Private,
> + IN DW_MMC_HC_TRB *Trb
> + );
> +
> +/**
> + Wait for the TRB execution result.
> +
> + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
> + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> +
> + @retval EFI_SUCCESS The TRB is executed successfully.
> + @retval Others Some erros happen when executing this request.
> +
> +**/
> +EFI_STATUS
> +DwMmcWaitTrbResult (
> + IN DW_MMC_HC_PRIVATE_DATA *Private,
> + IN DW_MMC_HC_TRB *Trb
> + );
> +
> +/**
> + Execute EMMC device identification procedure.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
> +
> + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
> +
> + @retval EFI_SUCCESS There is a EMMC card.
> + @retval Others There is not a EMMC card.
> +
> +**/
> +EFI_STATUS
> +EmmcIdentification (
> + IN DW_MMC_HC_PRIVATE_DATA *Private
> + );
> +
> +/**
> + Execute EMMC device identification procedure.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
> +
> + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
> +
> + @retval EFI_SUCCESS There is a EMMC card.
> + @retval Others There is not a EMMC card.
> +
> +**/
> +EFI_STATUS
> +SdCardIdentification (
> + IN DW_MMC_HC_PRIVATE_DATA *Private
> + );
> +
> +#endif /* _DW_MMC_HC_DXE_H_ */
> diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
> new file mode 100644
> index 000000000000..12ef58a37368
> --- /dev/null
> +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
> @@ -0,0 +1,985 @@
> +/** @file
> +
> + Provides some data structure definitions used by the SD/MMC host controller
> + driver.
> +
> + Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
> + Copyright (c) 2018, Linaro Ltd. 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 _DW_MMC_HCI_H_
> +#define _DW_MMC_HCI_H_
> +
> +#include <Library/CacheMaintenanceLib.h>
> +#include <Library/TimerLib.h>
> +
> +#include <Protocol/PlatformDwMmc.h>
> +
> +//
> +// SD Host Controller SlotInfo Register Offset
> +//
> +#define DW_MMC_HC_SLOT_OFFSET 0x40
> +
> +#define DW_MMC_HC_MAX_SLOT 1
> +
> +//
> +// SD Host Controller MMIO Register Offset
> +//
> +#define DW_MMC_CTRL 0x000
> +#define DW_MMC_PWREN 0x004
> +#define DW_MMC_CLKDIV 0x008
> +#define DW_MMC_CLKSRC 0x00c
> +#define DW_MMC_CLKENA 0x010
> +#define DW_MMC_TMOUT 0x014
> +#define DW_MMC_CTYPE 0x018
> +#define DW_MMC_BLKSIZ 0x01c
> +#define DW_MMC_BYTCNT 0x020
> +#define DW_MMC_INTMASK 0x024
> +#define DW_MMC_CMDARG 0x028
> +#define DW_MMC_CMD 0x02c
> +#define DW_MMC_RESP0 0x030
> +#define DW_MMC_RESP1 0x034
> +#define DW_MMC_RESP2 0x038
> +#define DW_MMC_RESP3 0x03c
> +#define DW_MMC_RINTSTS 0x044
> +#define DW_MMC_STATUS 0x048
> +#define DW_MMC_FIFOTH 0x04c
> +#define DW_MMC_GPIO 0x058
> +#define DW_MMC_DEBNCE 0x064
> +#define DW_MMC_USRID 0x068
> +#define DW_MMC_VERID 0x06c
> +#define DW_MMC_HCON 0x070
> +#define DW_MMC_UHSREG 0x074
> +#define DW_MMC_BMOD 0x080
> +#define DW_MMC_DBADDR 0x088
> +#define DW_MMC_IDSTS 0x08c
> +#define DW_MMC_IDINTEN 0x090
> +#define DW_MMC_DSCADDR 0x094
> +#define DW_MMC_BUFADDR 0x098
> +#define DW_MMC_CARDTHRCTL 0x100
> +#define DW_MMC_UHSREG_EXT 0x108
> +#define DW_MMC_ENABLE_SHIFT 0x110
> +#define DW_MMC_FIFO_START 0x200
> +
> +#define GET_IDSTS_DMAC_FSM(x) (((x) >> 13) & 0xf)
> +#define IDSTS_FSM_DMA_IDLE 0
> +#define IDSTS_FSM_DMA_SUSPEND 1
> +#define IDSTS_FSM_DESC_RD 2
> +#define IDSTS_FSM_DESC_CHK 3
> +#define IDSTS_FSM_DMA_RD_REQ_WAIT 4
> +#define IDSTS_FSM_DMA_WR_REQ_WAIT 5
> +#define IDSTS_FSM_DMA_RD 6
> +#define IDSTS_FSM_DMA_WR 7
> +#define IDSTS_FSM_DESC_CLOSE 8
> +#define IDSTS_FSM_MASK 0xf
> +
> +#define CMD_UPDATE_CLK 0x80202000
> +#define CMD_START_BIT (1 << 31)
> +
> +#define MMC_8BIT_MODE (1 << 16)
> +#define MMC_4BIT_MODE (1 << 0)
> +#define MMC_1BIT_MODE 0
> +
> +#define DW_MMC_BLOCK_SIZE 512
> +
> +#define CMD_INDEX_MASK 0x3F
> +#define BIT_CMD_RESPONSE_EXPECT (1 << 6)
> +#define BIT_CMD_LONG_RESPONSE (1 << 7)
> +#define BIT_CMD_CHECK_RESPONSE_CRC (1 << 8)
> +#define BIT_CMD_DATA_EXPECTED (1 << 9)
> +#define BIT_CMD_READ (0 << 10)
> +#define BIT_CMD_WRITE (1 << 10)
> +#define BIT_CMD_BLOCK_TRANSFER (0 << 11)
> +#define BIT_CMD_STREAM_TRANSFER (1 << 11)
> +#define BIT_CMD_SEND_AUTO_STOP (1 << 12)
> +#define BIT_CMD_WAIT_PRVDATA_COMPLETE (1 << 13)
> +#define BIT_CMD_STOP_ABORT_CMD (1 << 14)
> +#define BIT_CMD_SEND_INIT (1 << 15)
> +#define BIT_CMD_UPDATE_CLOCK_ONLY (1 << 21)
> +#define BIT_CMD_READ_CEATA_DEVICE (1 << 22)
> +#define BIT_CMD_CCS_EXPECTED (1 << 23)
> +#define BIT_CMD_ENABLE_BOOT (1 << 24)
> +#define BIT_CMD_EXPECT_BOOT_ACK (1 << 25)
> +#define BIT_CMD_DISABLE_BOOT (1 << 26)
> +#define BIT_CMD_MANDATORY_BOOT (0 << 27)
> +#define BIT_CMD_ALTERNATE_BOOT (1 << 27)
> +#define BIT_CMD_VOLT_SWITCH (1 << 28)
> +#define BIT_CMD_USE_HOLD_REG (1 << 29)
> +#define BIT_CMD_START (1 << 31)
> +
> +#define CMD_INDEX(x) ((x) & CMD_INDEX_MASK)
> +
> +#define DW_MMC_INT_EBE (1 << 15) /* End-bit Err */
> +#define DW_MMC_INT_SBE (1 << 13) /* Start-bit Err */
> +#define DW_MMC_INT_HLE (1 << 12) /* Hardware-lock Err */
> +#define DW_MMC_INT_FRUN (1 << 11) /* FIFO UN/OV RUN */
> +#define DW_MMC_INT_DRT (1 << 9) /* Data timeout */
> +#define DW_MMC_INT_RTO (1 << 8) /* Response timeout */
> +#define DW_MMC_INT_DCRC (1 << 7) /* Data CRC err */
> +#define DW_MMC_INT_RCRC (1 << 6) /* Response CRC err */
> +#define DW_MMC_INT_RXDR (1 << 5) /* Receive FIFO data request */
> +#define DW_MMC_INT_TXDR (1 << 4) /* Transmit FIFO data request */
> +#define DW_MMC_INT_DTO (1 << 3) /* Data trans over */
> +#define DW_MMC_INT_CMD_DONE (1 << 2) /* Command done */
> +#define DW_MMC_INT_RE (1 << 1) /* Response error */
> +
> +#define DW_MMC_IDMAC_DES0_DIC (1 << 1)
> +#define DW_MMC_IDMAC_DES0_LD (1 << 2)
> +#define DW_MMC_IDMAC_DES0_FS (1 << 3)
> +#define DW_MMC_IDMAC_DES0_CH (1 << 4)
> +#define DW_MMC_IDMAC_DES0_ER (1 << 5)
> +#define DW_MMC_IDMAC_DES0_CES (1 << 30)
> +#define DW_MMC_IDMAC_DES0_OWN (1 << 31)
> +#define DW_MMC_IDMAC_DES1_BS1(x) ((x) & 0x1fff)
> +#define DW_MMC_IDMAC_DES2_BS2(x) (((x) & 0x1fff) << 13)
> +#define DW_MMC_IDMAC_SWRESET (1 << 0)
> +#define DW_MMC_IDMAC_FB (1 << 1)
> +#define DW_MMC_IDMAC_ENABLE (1 << 7)
> +
> +#define DW_MMC_CTRL_RESET (1 << 0)
> +#define DW_MMC_CTRL_FIFO_RESET (1 << 1)
> +#define DW_MMC_CTRL_DMA_RESET (1 << 2)
> +#define DW_MMC_CTRL_INT_EN (1 << 4)
> +#define DW_MMC_CTRL_DMA_EN (1 << 5)
> +#define DW_MMC_CTRL_IDMAC_EN (1 << 25)
> +#define DW_MMC_CTRL_RESET_ALL (DW_MMC_CTRL_RESET | DW_MMC_CTRL_FIFO_RESET | DW_MMC_CTRL_DMA_RESET)
> +
> +#define DW_MMC_STS_DATA_BUSY (1 << 9)
> +#define DW_MMC_STS_FIFO_COUNT(x) (((x) & 0x1fff) << 17) /* Number of filled locations in FIFO */
> +#define GET_STS_FIFO_COUNT(x) (((x) >> 17) & 0x1fff)
> +#define DW_MMC_STS_FIFO_FULL(x) (((x) >> 3) & 1)
> +
> +#define DW_MMC_BMOD_SWR (1 << 0) /* Software Reset */
> +#define DW_MMC_BMOD_FB (1 << 1) /* Fix Burst */
> +#define DW_MMC_BMOD_DE (1 << 7) /* IDMAC Enable */
> +
> +#define DW_MMC_IDSTS_TI (1 << 0) /* Transmit Interrupt */
> +#define DW_MMC_IDSTS_RI (1 << 1) /* Receive Interrupt */
> +
> +#define DW_MMC_FIFO_TWMARK(x) ((x) & 0xfff)
> +#define DW_MMC_FIFO_RWMARK(x) (((x) & 0x1ff) << 16)
> +#define DW_MMC_DMA_BURST_SIZE(x) (((x) & 0x7) << 28)
> +
> +#define DW_MMC_CARD_RD_THR(x) (((x) & 0xfff) << 16)
> +#define DW_MMC_CARD_RD_THR_EN (1 << 0)
> +
> +#define UHS_DDR_MODE (1 << 16)
> +
> +#define GENCLK_DIV 7
> +
> +#define DW_MMC_GPIO_CLK_DIV(x) (((x) & 0xf) << 8)
> +#define DW_MMC_GPIO_USE_SAMPLE_DLY(x) (((x) & 1) << 13)
> +#define DW_MMC_GPIO_CLK_ENABLE BIT16
> +
> +#define UHSEXT_SAMPLE_PHASE(x) (((x) & 0x1f) << 16)
> +#define UHSEXT_SAMPLE_DRVPHASE(x) (((x) & 0x1f) << 21)
> +#define UHSEXT_SAMPLE_DLY(x) (((x) & 0x1f) << 26)
> +
> +#define DWMMC_DMA_BUF_SIZE (512 * 8)
> +#define DWMMC_FIFO_THRESHOLD 16
> +
> +#define DWMMC_INIT_CLOCK_FREQ 400 /* KHz */
> +
> +//
> +// The transfer modes supported by SD Host Controller
> +// Simplified Spec 3.0 Table 1-2
> +//
> +typedef enum {
> + SdMmcNoData,
> + SdMmcPioMode,
> + SdMmcSdmaMode,
> + SdMmcAdmaMode
> +} DW_MMC_HC_TRANSFER_MODE;
> +
> +//
> +// The maximum data length of each descriptor line
> +//
> +#define ADMA_MAX_DATA_PER_LINE 0x10000
> +
> +typedef struct {
> + UINT32 Des0;
> + UINT32 Des1;
> + UINT32 Des2;
> + UINT32 Des3;
> +} DW_MMC_HC_DMA_DESC_LINE;
> +
> +#define SD_MMC_SDMA_BOUNDARY 512 * 1024
> +#define SD_MMC_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1))
> +
> +typedef struct {
> + UINT8 FirstBar:3; // bit 0:2
> + UINT8 Reserved:1; // bit 3
> + UINT8 SlotNum:3; // bit 4:6
> + UINT8 Reserved1:1; // bit 7
> +} DW_MMC_HC_SLOT_INFO;
> +
> +/**
> + Dump the content of SD/MMC host controller's Capability Register.
> +
> + @param[in] Slot The slot number of the SD card to send the command to.
> + @param[in] Capability The buffer to store the capability data.
> +
> +**/
> +VOID
> +DumpCapabilityReg (
> + IN UINT8 Slot,
> + IN DW_MMC_HC_SLOT_CAP *Capability
> + );
> +
> +#if 0
> +/**
> + Read SlotInfo register from SD/MMC host controller pci config space.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[out] FirstBar The buffer to store the first BAR value.
> + @param[out] SlotNum The buffer to store the supported slot number.
> +
> + @retval EFI_SUCCESS The operation succeeds.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcHcGetSlotInfo (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + OUT UINT8 *FirstBar,
> + OUT UINT8 *SlotNum
> + );
> +#endif
> +
> +#ifdef DWMMC_PCI
> +/**
> + Read/Write specified SD/MMC host controller mmio register.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[in] BarIndex The BAR index of the standard PCI Configuration
> + header to use as the base address for the memory
> + operation to perform.
> + @param[in] Offset The offset within the selected BAR to start the
> + memory operation.
> + @param[in] Read A boolean to indicate it's read or write operation.
> + @param[in] Count The width of the mmio register in bytes.
> + Must be 1, 2 , 4 or 8 bytes.
> + @param[in, out] Data For read operations, the destination buffer to store
> + the results. For write operations, the source buffer
> + to write data from. The caller is responsible for
> + having ownership of the data buffer and ensuring its
> + size not less than Count bytes.
> +
> + @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid.
> + @retval EFI_SUCCESS The read/write operation succeeds.
> + @retval Others The read/write operation fails.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcHcRwMmio (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN UINT8 BarIndex,
> + IN UINT32 Offset,
> + IN BOOLEAN Read,
> + IN UINT8 Count,
> + IN OUT VOID *Data
> + );
> +#else
> +/**
> + Read/Write specified SD/MMC host controller mmio register.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] Offset The offset within the selected BAR to start the
> + memory operation.
> + @param[in] Read A boolean to indicate it's read or write operation.
> + @param[in] Count The width of the mmio register in bytes.
> + Must be 1, 2 , 4 or 8 bytes.
> + @param[in, out] Data For read operations, the destination buffer to store
> + the results. For write operations, the source buffer
> + to write data from. The caller is responsible for
> + having ownership of the data buffer and ensuring its
> + size not less than Count bytes.
> +
> + @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid.
> + @retval EFI_SUCCESS The read/write operation succeeds.
> + @retval Others The read/write operation fails.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcHcRwMmio (
> + IN UINTN DevBase,
> + IN UINT32 Offset,
> + IN BOOLEAN Read,
> + IN UINT8 Count,
> + IN OUT VOID *Data
> + );
> +#endif
> +
> +#ifdef DWMMC_PCI
> +/**
> + Do OR operation with the value of the specified SD/MMC host controller mmio register.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[in] BarIndex The BAR index of the standard PCI Configuration
> + header to use as the base address for the memory
> + operation to perform.
> + @param[in] Offset The offset within the selected BAR to start the
> + memory operation.
> + @param[in] Count The width of the mmio register in bytes.
> + Must be 1, 2 , 4 or 8 bytes.
> + @param[in] OrData The pointer to the data used to do OR operation.
> + The caller is responsible for having ownership of
> + the data buffer and ensuring its size not less than
> + Count bytes.
> +
> + @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid.
> + @retval EFI_SUCCESS The OR operation succeeds.
> + @retval Others The OR operation fails.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcHcOrMmio (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN UINT8 BarIndex,
> + IN UINT32 Offset,
> + IN UINT8 Count,
> + IN VOID *OrData
> + );
> +#else
> +/**
> + Do OR operation with the value of the specified SD/MMC host controller mmio register.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] BarIndex The BAR index of the standard PCI Configuration
> + header to use as the base address for the memory
> + operation to perform.
> + @param[in] Offset The offset within the selected BAR to start the
> + memory operation.
> + @param[in] Count The width of the mmio register in bytes.
> + Must be 1, 2 , 4 or 8 bytes.
> + @param[in] OrData The pointer to the data used to do OR operation.
> + The caller is responsible for having ownership of
> + the data buffer and ensuring its size not less than
> + Count bytes.
> +
> + @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid.
> + @retval EFI_SUCCESS The OR operation succeeds.
> + @retval Others The OR operation fails.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcHcOrMmio (
> + IN UINTN DevBase,
> + IN UINT32 Offset,
> + IN UINT8 Count,
> + IN VOID *OrData
> + );
> +#endif
> +
> +#ifdef DWMMC_PCI
> +/**
> + Do AND operation with the value of the specified SD/MMC host controller mmio register.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[in] BarIndex The BAR index of the standard PCI Configuration
> + header to use as the base address for the memory
> + operation to perform.
> + @param[in] Offset The offset within the selected BAR to start the
> + memory operation.
> + @param[in] Count The width of the mmio register in bytes.
> + Must be 1, 2 , 4 or 8 bytes.
> + @param[in] AndData The pointer to the data used to do AND operation.
> + The caller is responsible for having ownership of
> + the data buffer and ensuring its size not less than
> + Count bytes.
> +
> + @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid.
> + @retval EFI_SUCCESS The AND operation succeeds.
> + @retval Others The AND operation fails.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcHcAndMmio (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN UINT8 BarIndex,
> + IN UINT32 Offset,
> + IN UINT8 Count,
> + IN VOID *AndData
> + );
> +#else
> +/**
> + Do AND operation with the value of the specified SD/MMC host controller mmio register.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] Offset The offset within the selected BAR to start the
> + memory operation.
> + @param[in] Count The width of the mmio register in bytes.
> + Must be 1, 2 , 4 or 8 bytes.
> + @param[in] AndData The pointer to the data used to do AND operation.
> + The caller is responsible for having ownership of
> + the data buffer and ensuring its size not less than
> + Count bytes.
> +
> + @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid.
> + @retval EFI_SUCCESS The AND operation succeeds.
> + @retval Others The AND operation fails.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcHcAndMmio (
> + IN UINTN DevBase,
> + IN UINT32 Offset,
> + IN UINT8 Count,
> + IN VOID *AndData
> + );
> +#endif
> +
> +#ifdef DWMMC_PCI
> +/**
> + Wait for the value of the specified MMIO register set to the test value.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[in] BarIndex The BAR index of the standard PCI Configuration
> + header to use as the base address for the memory
> + operation to perform.
> + @param[in] Offset The offset within the selected BAR to start the
> + memory operation.
> + @param[in] Count The width of the mmio register in bytes.
> + Must be 1, 2, 4 or 8 bytes.
> + @param[in] MaskValue The mask value of memory.
> + @param[in] TestValue The test value of memory.
> + @param[in] Timeout The time out value for wait memory set, uses 1
> + microsecond as a unit.
> +
> + @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout
> + range.
> + @retval EFI_SUCCESS The MMIO register has expected value.
> + @retval Others The MMIO operation fails.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcHcWaitMmioSet (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN UINT8 BarIndex,
> + IN UINT32 Offset,
> + IN UINT8 Count,
> + IN UINT64 MaskValue,
> + IN UINT64 TestValue,
> + IN UINT64 Timeout
> + );
> +#else
> +/**
> + Wait for the value of the specified MMIO register set to the test value.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] Offset The offset within the selected BAR to start the
> + memory operation.
> + @param[in] Count The width of the mmio register in bytes.
> + Must be 1, 2, 4 or 8 bytes.
> + @param[in] MaskValue The mask value of memory.
> + @param[in] TestValue The test value of memory.
> + @param[in] Timeout The time out value for wait memory set, uses 1
> + microsecond as a unit.
> +
> + @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout
> + range.
> + @retval EFI_SUCCESS The MMIO register has expected value.
> + @retval Others The MMIO operation fails.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcHcWaitMmioSet (
> + IN UINTN DevBase,
> + IN UINT32 Offset,
> + IN UINT8 Count,
> + IN UINT64 MaskValue,
> + IN UINT64 TestValue,
> + IN UINT64 Timeout
> + );
> +#endif
> +
> +#ifdef DWMMC_PCI
> +/**
> + Software reset the specified SD/MMC host controller.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command to.
> +
> + @retval EFI_SUCCESS The software reset executes successfully.
> + @retval Others The software reset fails.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcReset (
> +fark
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN UINT8 Slot,
> + IN DW_MMC_HC_SLOT_CAP Capability
> + );
> +#else
> +/**
> + Software reset the specified SD/MMC host controller.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> +
> + @retval EFI_SUCCESS The software reset executes successfully.
> + @retval Others The software reset fails.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcReset (
> + IN UINTN DevBase,
> + IN DW_MMC_HC_SLOT_CAP Capability
> + );
> +#endif
> +
> +#ifdef DWMMC_PCI
> +/**
> + Set all interrupt status bits in Normal and Error Interrupt Status Enable
> + register.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command to.
> +
> + @retval EFI_SUCCESS The operation executes successfully.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcEnableInterrupt (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN UINT8 Slot
> + );
> +#else
> +/**
> + Set all interrupt status bits in Normal and Error Interrupt Status Enable
> + register.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command to.
> +
> + @retval EFI_SUCCESS The operation executes successfully.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcEnableInterrupt (
> + IN UINTN DevBase
> + );
> +#endif
> +
> +#ifdef DWMMC_PCI
> +/**
> + Get the capability data from the specified slot.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command to.
> + @param[out] Capability The buffer to store the capability data.
> +
> + @retval EFI_SUCCESS The operation executes successfully.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcGetCapability (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN EFI_HANDLE Controller,
> + IN UINT8 Slot,
> + OUT DW_MMC_HC_SLOT_CAP *Capability
> + );
> +#else
> +/**
> + Get the capability data from the specified slot.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command to.
> + @param[out] Capability The buffer to store the capability data.
> +
> + @retval EFI_SUCCESS The operation executes successfully.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcGetCapability (
> + IN UINTN DevBase,
> + IN EFI_HANDLE Controller,
> + IN UINT8 Slot,
> + OUT DW_MMC_HC_SLOT_CAP *Capability
> + );
> +#endif
> +
> +#if 0
> +/**
> + Get the maximum current capability data from the specified slot.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command to.
> + @param[out] MaxCurrent The buffer to store the maximum current capability data.
> +
> + @retval EFI_SUCCESS The operation executes successfully.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcGetMaxCurrent (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN UINT8 Slot,
> + OUT UINT64 *MaxCurrent
> + );
> +#endif
> +
> +#ifdef DWMMC_PCI
> +/**
> + Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller
> + slot.
> +
> + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command to.
> + @param[out] MediaPresent The pointer to the media present boolean value.
> +
> + @retval EFI_SUCCESS There is no media change happened.
> + @retval EFI_MEDIA_CHANGED There is media change happened.
> + @retval Others The detection fails.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcCardDetect (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN EFI_HANDLE Controller,
> + IN UINT8 Slot,
> + OUT BOOLEAN *MediaPresent
> + );
> +#else
> +/**
> + Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller
> + slot.
> +
> + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command to.
> + @param[out] MediaPresent The pointer to the media present boolean value.
> +
> + @retval EFI_SUCCESS There is no media change happened.
> + @retval EFI_MEDIA_CHANGED There is media change happened.
> + @retval Others The detection fails.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcCardDetect (
> + IN UINTN DevBase,
> + IN EFI_HANDLE Controller,
> + IN UINT8 Slot,
> + OUT BOOLEAN *MediaPresent
> + );
> +#endif
> +
> +#ifdef DWMMC_PCI
> +/**
> + Stop SD/MMC card clock.
> +
> + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command to.
> +
> + @retval EFI_SUCCESS Succeed to stop SD/MMC clock.
> + @retval Others Fail to stop SD/MMC clock.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcStopClock (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN UINT8 Slot
> + );
> +
> +/**
> + SD/MMC card clock supply.
> +
> + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command to.
> + @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
> + @param[in] Capability The capability of the slot.
> +
> + @retval EFI_SUCCESS The clock is supplied successfully.
> + @retval Others The clock isn't supplied successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcClockSupply (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN UINT8 Slot,
> + IN UINT64 ClockFreq,
> + IN DW_MMC_HC_SLOT_CAP Capability
> + );
> +#else
> +/**
> + Stop SD/MMC card clock.
> +
> + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> +
> + @retval EFI_SUCCESS Succeed to stop SD/MMC clock.
> + @retval Others Fail to stop SD/MMC clock.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcStopClock (
> + IN UINTN DevBase
> + );
> +
> +/**
> + SD/MMC card clock supply.
> +
> + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
> + @param[in] Capability The capability of the slot.
> +
> + @retval EFI_SUCCESS The clock is supplied successfully.
> + @retval Others The clock isn't supplied successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcClockSupply (
> + IN UINTN DevBase,
> + IN UINT64 ClockFreq,
> + IN DW_MMC_HC_SLOT_CAP Capability
> + );
> +#endif
> +
> +#if 0
> +/**
> + SD/MMC bus power control.
> +
> + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command to.
> + @param[in] PowerCtrl The value setting to the power control register.
> +
> + @retval TRUE There is a SD/MMC card attached.
> + @retval FALSE There is no a SD/MMC card attached.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcPowerControl (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN UINT8 Slot,
> + IN UINT8 PowerCtrl
> + );
> +#endif
> +
> +#ifdef DWMMC_PCI
> +/**
> + Set the SD/MMC bus width.
> +
> + Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command to.
> + @param[in] BusWidth The bus width used by the SD/MMC device, it must be 1, 4 or 8.
> +
> + @retval EFI_SUCCESS The bus width is set successfully.
> + @retval Others The bus width isn't set successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcSetBusWidth (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN UINT8 Slot,
> + IN BOOLEAN IsDdr,
> + IN UINT16 BusWidth
> + );
> +#else
> +/**
> + Set the SD/MMC bus width.
> +
> + Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] BusWidth The bus width used by the SD/MMC device, it must be 1, 4 or 8.
> +
> + @retval EFI_SUCCESS The bus width is set successfully.
> + @retval Others The bus width isn't set successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcSetBusWidth (
> + IN UINTN DevBase,
> + IN BOOLEAN IsDdr,
> + IN UINT16 BusWidth
> + );
> +#endif
> +
> +#ifdef DWMMC_PCI
> +/**
> + Supply SD/MMC card with lowest clock frequency at initialization.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command to.
> + @param[in] Capability The capability of the slot.
> +
> + @retval EFI_SUCCESS The clock is supplied successfully.
> + @retval Others The clock isn't supplied successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcInitClockFreq (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN UINT8 Slot,
> + IN DW_MMC_HC_SLOT_CAP Capability
> + );
> +#else
> +/**
> + Supply SD/MMC card with lowest clock frequency at initialization.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] Capability The capability of the slot.
> +
> + @retval EFI_SUCCESS The clock is supplied successfully.
> + @retval Others The clock isn't supplied successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcInitClockFreq (
> + IN UINTN DevBase,
> + IN DW_MMC_HC_SLOT_CAP Capability
> + );
> +#endif
> +
> +#ifdef DWMMC_PCI
> +/**
> + Supply SD/MMC card with maximum voltage at initialization.
> +
> + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command to.
> + @param[in] Capability The capability of the slot.
> +
> + @retval EFI_SUCCESS The voltage is supplied successfully.
> + @retval Others The voltage isn't supplied successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcInitPowerVoltage (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN UINT8 Slot,
> + IN DW_MMC_HC_SLOT_CAP Capability
> + );
> +#else
> +/**
> + Supply SD/MMC card with maximum voltage at initialization.
> +
> + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] Capability The capability of the slot.
> +
> + @retval EFI_SUCCESS The voltage is supplied successfully.
> + @retval Others The voltage isn't supplied successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcInitPowerVoltage (
> + IN UINTN DevBase,
> + IN DW_MMC_HC_SLOT_CAP Capability
> + );
> +#endif
> +
> +#ifdef DWMMC_PCI
> +/**
> + Initialize the Timeout Control register with most conservative value at initialization.
> +
> + Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command to.
> +
> + @retval EFI_SUCCESS The timeout control register is configured successfully.
> + @retval Others The timeout control register isn't configured successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcInitTimeoutCtrl (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN UINT8 Slot
> + );
> +#else
> +/**
> + Initialize the Timeout Control register with most conservative value at initialization.
> +
> + Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command to.
> +
> + @retval EFI_SUCCESS The timeout control register is configured successfully.
> + @retval Others The timeout control register isn't configured successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcInitTimeoutCtrl (
> + IN UINTN DevBase
> + );
> +#endif
> +
> +#ifdef DWMMC_PCI
> +/**
> + Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value
> + at initialization.
> +
> + @param[in] PciIo The PCI IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command to.
> + @param[in] Capability The capability of the slot.
> +
> + @retval EFI_SUCCESS The host controller is initialized successfully.
> + @retval Others The host controller isn't initialized successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcInitHost (
> + IN EFI_PCI_IO_PROTOCOL *PciIo,
> + IN UINT8 Slot,
> + IN DW_MMC_HC_SLOT_CAP Capability
> + );
> +#else
> +/**
> + Initial SD/MMC host controller with lowest clock frequency, max power and
> + max timeout value at initialization.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] Capability The capability of the slot.
> +
> + @retval EFI_SUCCESS The host controller is initialized successfully.
> + @retval Others The host controller isn't initialized successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcInitHost (
> + IN UINTN DevBase,
> + IN DW_MMC_HC_SLOT_CAP Capability
> + );
> +#endif
> +
> +#endif /* _DW_MMC_HCI_H_ */
> diff --git a/EmbeddedPkg/Include/Protocol/PlatformDwMmc.h b/EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
> new file mode 100644
> index 000000000000..acbc3e153dac
> --- /dev/null
> +++ b/EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
> @@ -0,0 +1,79 @@
> +/** @file
> +
> + Copyright (c) 2018, Linaro. All rights reserved.
> +
> + This program and the accompanying materials are licensed and made available
> + under the terms and conditions of the BSD License which accompanies this
> + distribution. The full text of the license may be found at
> + http://opensource.org/licenses/bsd-license.php
> +
> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef __PLATFORM_DW_MMC_H__
> +#define __PLATFORM_DW_MMC_H__
> +
> +typedef enum {
> + RemovableSlot,
> + EmbeddedSlot,
> + SharedBusSlot,
> + UnknownSlot
> +} EFI_SD_MMC_SLOT_TYPE;
> +
> +typedef enum {
> + UnknownCardType,
> + SdCardType,
> + SdioCardType,
> + MmcCardType,
> + EmmcCardType
> +} SD_MMC_CARD_TYPE;
> +
> +typedef struct {
> + UINT32 DefaultSpeed:1; // bit 0
> + UINT32 HighSpeed:1; // bit 1
> + UINT32 Sdr12:1; // bit 2
> + UINT32 Sdr25:1; // bit 3
> + UINT32 Sdr50:1; // bit 4
> + UINT32 Sdr104:1; // bit 5
> + UINT32 Ddr50:1; // bit 6
> + UINT32 SysBus64:1; // bit 7
> + UINT32 BusWidth:4; // bit 11:8
> + UINT32 SlotType:2; // bit 13:12
> + UINT32 CardType:3; // bit 16:14
> + UINT32 Voltage18:1; // bit 17
> + UINT32 Voltage30:1; // bit 18
> + UINT32 Voltage33:1; // bit 19
> + UINT32 BaseClkFreq;
> + EFI_HANDLE Controller;
> +} DW_MMC_HC_SLOT_CAP;
> +
> +//
> +// Protocol interface structure
> +//
> +typedef struct _PLATFORM_DW_MMC_PROTOCOL PLATFORM_DW_MMC_PROTOCOL;
> +
> +typedef
> +EFI_STATUS
> +(EFIAPI *PLATFORM_DW_MMC_GET_CAPABILITY) (
> + IN EFI_HANDLE Controller,
> + IN UINT8 Slot,
> + OUT DW_MMC_HC_SLOT_CAP *Capability
> + );
> +
> +typedef
> +BOOLEAN
> +(EFIAPI *PLATFORM_DW_MMC_CARD_DETECT) (
> + IN EFI_HANDLE Controller,
> + IN UINT8 Slot
> + );
> +
> +struct _PLATFORM_DW_MMC_PROTOCOL {
> + PLATFORM_DW_MMC_GET_CAPABILITY GetCapability;
> + PLATFORM_DW_MMC_CARD_DETECT CardDetect;
> +};
> +
> +extern EFI_GUID gPlatformDwMmcProtocolGuid;
> +
> +#endif /* __PLATFORM_DW_MMC_H__ */
> diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c b/EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
> new file mode 100644
> index 000000000000..1edade69d091
> --- /dev/null
> +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
> @@ -0,0 +1,214 @@
> +/** @file
> + UEFI Component Name(2) protocol implementation for Designware SD/MMC host
> + controller driver.
> +
> + Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
> + Copyright (c) 2018, Linaro Ltd. 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 "DwMmcHcDxe.h"
> +
> +//
> +// EFI Component Name Protocol
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gDwMmcHcComponentName = {
> + DwMmcHcComponentNameGetDriverName,
> + DwMmcHcComponentNameGetControllerName,
> + "eng"
> +};
> +
> +//
> +// EFI Component Name 2 Protocol
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gDwMmcHcComponentName2 = {
> + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) DwMmcHcComponentNameGetDriverName,
> + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) DwMmcHcComponentNameGetControllerName,
> + "en"
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mDwMmcHcDriverNameTable[] = {
> + { "eng;en", L"Designware Sd/Mmc Host Controller Driver" },
> + { NULL , NULL }
> +};
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mDwMmcHcControllerNameTable[] = {
> + { "eng;en", L"Designware Sd/Mmc Host Controller" },
> + { NULL , NULL }
> +};
> +
> +/**
> + Retrieves a Unicode string that is the user readable name of the driver.
> +
> + This function retrieves the user readable name of a driver in the form of a
> + Unicode string. If the driver specified by This has a user readable name in
> + the language specified by Language, then a pointer to the driver name is
> + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
> + by This does not support the language specified by Language,
> + then EFI_UNSUPPORTED is returned.
> +
> + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> +
> + @param Language[in] A pointer to a Null-terminated ASCII string
> + array indicating the language. This is the
> + language of the driver name 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. Language is specified
> + in RFC 4646 or ISO 639-2 language code format.
> +
> + @param DriverName[out] 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
> +DwMmcHcComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + )
> +{
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + mDwMmcHcDriverNameTable,
> + DriverName,
> + (BOOLEAN)(This == &gDwMmcHcComponentName)
> + );
> +}
> +
> +/**
> + Retrieves a Unicode string that is the user readable name of the controller
> + that is being managed by a driver.
> +
> + This function retrieves the user readable name of the controller specified by
> + ControllerHandle and ChildHandle in the form of a Unicode string. If the
> + driver specified by This has a user readable name in the language specified by
> + Language, then a pointer to the controller name is returned in ControllerName,
> + and EFI_SUCCESS is returned. If the driver specified by This is not currently
> + managing the controller specified by ControllerHandle and ChildHandle,
> + then EFI_UNSUPPORTED is returned. If the driver specified by This does not
> + support the language specified by Language, then EFI_UNSUPPORTED is returned.
> +
> + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> +
> + @param ControllerHandle[in] 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 ChildHandle[in] 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 Language[in] A pointer to a Null-terminated ASCII string
> + array indicating the language. This is the
> + language of the driver name 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. Language is specified in
> + RFC 4646 or ISO 639-2 language code format.
> +
> + @param ControllerName[out] 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
> +DwMmcHcComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_HANDLE ChildHandle, OPTIONAL
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + )
> +{
> + EFI_STATUS Status;
> +
> + if (Language == NULL || ControllerName == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // This is a device driver, so ChildHandle must be NULL.
> + //
> + if (ChildHandle != NULL) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + //
> + // Make sure this driver is currently managing ControllerHandle
> + //
> + Status = EfiTestManagedDevice (
> + ControllerHandle,
> + gDwMmcHcDriverBinding.DriverBindingHandle,
> + &gEfiPciIoProtocolGuid
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + mDwMmcHcControllerNameTable,
> + ControllerName,
> + (BOOLEAN)(This == &gDwMmcHcComponentName)
> + );
> +}
> diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
> new file mode 100644
> index 000000000000..aea12170d2cc
> --- /dev/null
> +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
> @@ -0,0 +1,1296 @@
> +/** @file
> + This driver is used to manage Designware SD/MMC host controller.
> +
> + It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.
> +
> + Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
> + Copyright (C) 2016 Marvell International Ltd. All rigths reserved.<BR>
> + Copyright (C) 2018, Linaro Ltd. All rigths 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 <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Protocol/NonDiscoverableDevice.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiDriverEntryPoint.h>
> +
> +#include <Protocol/DevicePath.h>
> +#include <Protocol/PlatformDwMmc.h>
> +
> +#include "DwMmcHcDxe.h"
> +
> +//
> +// Driver Global Variables
> +//
> +EFI_DRIVER_BINDING_PROTOCOL gDwMmcHcDriverBinding = {
> + DwMmcHcDriverBindingSupported,
> + DwMmcHcDriverBindingStart,
> + DwMmcHcDriverBindingStop,
> + 0x10,
> + NULL,
> + NULL
> +};
> +
> +//
> +// Template for Designware SD/MMC host controller private data.
> +//
> +DW_MMC_HC_PRIVATE_DATA gDwMmcHcTemplate = {
> + DW_MMC_HC_PRIVATE_SIGNATURE, // Signature
> + NULL, // ControllerHandle
> + 0x0, // Mmio base address
> + { // PassThru
> + sizeof (UINT32),
> + DwMmcPassThruPassThru,
> + DwMmcPassThruGetNextSlot,
> + DwMmcPassThruBuildDevicePath,
> + DwMmcPassThruGetSlotNumber,
> + DwMmcPassThruResetDevice
> + },
> + NULL, // PlatformDwMmc
> + 0, // PreviousSlot
> + NULL, // TimerEvent
> + NULL, // ConnectEvent
> + // Queue
> + INITIALIZE_LIST_HEAD_VARIABLE (gDwMmcHcTemplate.Queue),
> + { // Slot
> + {0, UnknownSlot, 0, 0, 0}
> + },
> + { // Capability
> + {0}
> + },
> + { // MaxCurrent
> + 0
> + },
> + 0 // ControllerVersion
> +};
> +
> +SD_DEVICE_PATH mSdDpTemplate = {
> + {
> + MESSAGING_DEVICE_PATH,
> + MSG_SD_DP,
> + {
> + (UINT8) (sizeof (SD_DEVICE_PATH)),
> + (UINT8) ((sizeof (SD_DEVICE_PATH)) >> 8)
> + }
> + },
> + 0
> +};
> +
> +EMMC_DEVICE_PATH mEmmcDpTemplate = {
> + {
> + MESSAGING_DEVICE_PATH,
> + MSG_EMMC_DP,
> + {
> + (UINT8) (sizeof (EMMC_DEVICE_PATH)),
> + (UINT8) ((sizeof (EMMC_DEVICE_PATH)) >> 8)
> + }
> + },
> + 0
> +};
> +
> +//
> +// Prioritized function list to detect card type.
> +// User could add other card detection logic here.
> +//
> +DWMMC_CARD_TYPE_DETECT_ROUTINE mCardTypeDetectRoutineTable[] = {
> + EmmcIdentification,
> + SdCardIdentification,
> + NULL
> +};
> +
> +/**
> + The entry point for SD host controller driver, used to install this driver on the ImageHandle.
> +
> + @param[in] ImageHandle The firmware allocated handle for this driver image.
> + @param[in] SystemTable Pointer to the EFI system table.
> +
> + @retval EFI_SUCCESS Driver loaded.
> + @retval other Driver not loaded.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +InitializeDwMmcHcDxe (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + EFI_STATUS Status;
> +
> + Status = EfiLibInstallDriverBindingComponentName2 (
> + ImageHandle,
> + SystemTable,
> + &gDwMmcHcDriverBinding,
> + ImageHandle,
> + &gDwMmcHcComponentName,
> + &gDwMmcHcComponentName2
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + return Status;
> +}
> +
> +/**
> + Call back function when the timer event is signaled.
> +
> + @param[in] Event The Event this notify function registered to.
> + @param[in] Context Pointer to the context data registered to the
> + Event.
> +
> +**/
> +VOID
> +EFIAPI
> +ProcessAsyncTaskList (
> + IN EFI_EVENT Event,
> + IN VOID* Context
> + )
> +{
> + DW_MMC_HC_PRIVATE_DATA *Private;
> + LIST_ENTRY *Link;
> + DW_MMC_HC_TRB *Trb;
> + EFI_STATUS Status;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
> + BOOLEAN InfiniteWait;
> + EFI_EVENT TrbEvent;
> +
> + Private = (DW_MMC_HC_PRIVATE_DATA *)Context;
> +
> + //
> + // Check if the first entry in the async I/O queue is done or not.
> + //
> + Status = EFI_SUCCESS;
> + Trb = NULL;
> + Link = GetFirstNode (&Private->Queue);
> + if (!IsNull (&Private->Queue, Link)) {
> + Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
> + if (!Private->Slot[Trb->Slot].MediaPresent) {
> + Status = EFI_NO_MEDIA;
> + goto Done;
> + }
> + if (!Trb->Started) {
> + //
> + // Check whether the cmd/data line is ready for transfer.
> + //
> + Status = DwMmcCheckTrbEnv (Private, Trb);
> + if (!EFI_ERROR (Status)) {
> + Trb->Started = TRUE;
> + Status = DwMmcExecTrb (Private, Trb);
> + if (EFI_ERROR (Status)) {
> + goto Done;
> + }
> + } else {
> + goto Done;
> + }
> + }
> + Status = DwMmcCheckTrbResult (Private, Trb);
> + }
> +
> +Done:
> + if ((Trb != NULL) && (Status == EFI_NOT_READY)) {
> + Packet = Trb->Packet;
> + if (Packet->Timeout == 0) {
> + InfiniteWait = TRUE;
> + } else {
> + InfiniteWait = FALSE;
> + }
> + if ((!InfiniteWait) && (Trb->Timeout-- == 0)) {
> + RemoveEntryList (Link);
> + Trb->Packet->TransactionStatus = EFI_TIMEOUT;
> + TrbEvent = Trb->Event;
> + DwMmcFreeTrb (Trb);
> + DEBUG ((
> + DEBUG_VERBOSE,
> + "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT\n",
> + TrbEvent
> + ));
> + gBS->SignalEvent (TrbEvent);
> + return;
> + }
> + }
> + if ((Trb != NULL) && (Status != EFI_NOT_READY)) {
> + RemoveEntryList (Link);
> + Trb->Packet->TransactionStatus = Status;
> + TrbEvent = Trb->Event;
> + DwMmcFreeTrb (Trb);
> + DEBUG ((
> + DEBUG_VERBOSE,
> + "ProcessAsyncTaskList(): Signal Event %p with %r\n",
> + TrbEvent,
> + Status
> + ));
> + gBS->SignalEvent (TrbEvent);
> + }
> + return;
> +}
> +
> +/**
> + Sd removable device enumeration callback function when the timer event is signaled.
> +
> + @param[in] Event The Event this notify function registered to.
> + @param[in] Context Pointer to the context data registered to the
> + Event.
> +
> +**/
> +VOID
> +EFIAPI
> +DwMmcHcEnumerateDevice (
> + IN EFI_EVENT Event,
> + IN VOID* Context
> + )
> +{
> + DW_MMC_HC_PRIVATE_DATA *Private;
> + EFI_STATUS Status;
> + BOOLEAN MediaPresent;
> + UINT32 RoutineNum;
> + DWMMC_CARD_TYPE_DETECT_ROUTINE *Routine;
> + UINTN Index;
> + LIST_ENTRY *Link;
> + LIST_ENTRY *NextLink;
> + DW_MMC_HC_TRB *Trb;
> + EFI_TPL OldTpl;
> +
> + Private = (DW_MMC_HC_PRIVATE_DATA *)Context;
> +
> + if ((Private->Slot[0].Enable) &&
> + (Private->Slot[0].SlotType == RemovableSlot)) {
> + Status = DwMmcHcCardDetect (
> + Private->DevBase,
> + Private->ControllerHandle,
> + 0,
> + &MediaPresent
> + );
> + if ((Status == EFI_MEDIA_CHANGED) && !MediaPresent) {
> + DEBUG ((
> + DEBUG_INFO,
> + "DwMmcHcEnumerateDevice: device disconnected at %p\n",
> + Private->DevBase
> + ));
> + Private->Slot[0].MediaPresent = FALSE;
> + //
> + // Signal all async task events at the slot with EFI_NO_MEDIA status.
> + //
> + OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> + for (Link = GetFirstNode (&Private->Queue);
> + !IsNull (&Private->Queue, Link);
> + Link = NextLink) {
> + NextLink = GetNextNode (&Private->Queue, Link);
> + Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
> + if (Trb->Slot == 0) {
> + RemoveEntryList (Link);
> + Trb->Packet->TransactionStatus = EFI_NO_MEDIA;
> + gBS->SignalEvent (Trb->Event);
> + DwMmcFreeTrb (Trb);
> + }
> + }
> + gBS->RestoreTPL (OldTpl);
> + //
> + // Notify the upper layer the connect state change through
> + // ReinstallProtocolInterface.
> + //
> + gBS->ReinstallProtocolInterface (
> + Private->ControllerHandle,
> + &gEfiSdMmcPassThruProtocolGuid,
> + &Private->PassThru,
> + &Private->PassThru
> + );
> + }
> + if ((Status == EFI_MEDIA_CHANGED) && MediaPresent) {
> + DEBUG ((
> + DEBUG_INFO,
> + "DwMmcHcEnumerateDevice: device connected at %p\n",
> + Private->DevBase
> + ));
> + //
> + // Initialize slot and start identification process for the new
> + // attached device
> + //
> + Status = DwMmcHcInitHost (Private->DevBase, Private->Capability[0]);
> + if (EFI_ERROR (Status)) {
> + return;
> + }
> + //
> + // Reset the specified slot of the SD/MMC Pci Host Controller
> + //
> + Status = DwMmcHcReset (Private->DevBase, Private->Capability[0]);
> + if (EFI_ERROR (Status)) {
> + return;
> + }
> +
> + Private->Slot[0].MediaPresent = TRUE;
> + RoutineNum = sizeof (mCardTypeDetectRoutineTable) /
> + sizeof (DWMMC_CARD_TYPE_DETECT_ROUTINE);
> + for (Index = 0; Index < RoutineNum; Index++) {
> + Routine = &mCardTypeDetectRoutineTable[Index];
> + if (*Routine != NULL) {
> + Status = (*Routine) (Private);
> + if (!EFI_ERROR (Status)) {
> + break;
> + }
> + }
> + }
> + //
> + // This card doesn't get initialized correctly.
> + //
> + if (Index == RoutineNum) {
> + return;
> + }
> +
> + //
> + // Notify the upper layer the connect state change through
> + // ReinstallProtocolInterface.
> + //
> + gBS->ReinstallProtocolInterface (
> + Private->ControllerHandle,
> + &gEfiSdMmcPassThruProtocolGuid,
> + &Private->PassThru,
> + &Private->PassThru
> + );
> + }
> + }
> +
> + return;
> +}
> +
> +/**
> + Reset the specified SD/MMC host controller and enable all interrupts.
> +
> + @param[in] DevBase The Mmio Device Base Address.
> +
> + @retval EFI_SUCCESS The software reset executes successfully.
> + @retval Others The software reset fails.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcReset (
> + IN UINTN DevBase,
> + IN DW_MMC_HC_SLOT_CAP Capability
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 BlkSize;
> +
> + //
> + // Enable all interrupt after reset all.
> + //
> + Status = DwMmcHcEnableInterrupt (DevBase);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "DwMmcHcReset: enable interrupts fail: %r\n", Status));
> + return Status;
> + }
> + Status = DwMmcHcInitTimeoutCtrl (DevBase);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + BlkSize = DW_MMC_BLOCK_SIZE;
> + MmioWrite32 (DevBase + DW_MMC_BLKSIZ, BlkSize);
> +
> + Status = DwMmcHcInitClockFreq (DevBase, Capability);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = DwMmcHcSetBusWidth (DevBase, FALSE, 1);
> +
> + return Status;
> +}
> +
> +/**
> + Tests to see if this driver supports a given controller. If a child device
> + is provided, it further tests to see if this driver supports creating a
> + handle for the specified child device.
> +
> + This function checks to see if the driver specified by This supports the
> + device specified by ControllerHandle. Drivers will typically use the device
> + path attached to ControllerHandle and/or the services from the bus I/O
> + abstraction attached to ControllerHandle to determine if the driver supports
> + ControllerHandle. This function may be called many times during platform
> + initialization. In order to reduce boot times, the tests performed by this
> + function must be very small, and take as little time as possible to execute.
> + This function must not change the state of any hardware devices, and this
> + function must be aware that the device specified by ControllerHandle may
> + already be managed by the same driver or a different driver. This function
> + must match its calls to AllocatePages() with FreePages(), AllocatePool() with
> + FreePool(), and OpenProtocol() with CloseProtocol(). Since ControllerHandle
> + may have been previously started by the same driver, if a protocol is already
> + in the opened state, then it must not be closed with CloseProtocol(). This is
> + required to guarantee the state of ControllerHandle is not modified by this
> + function.
> +
> + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
> + instance.
> + @param[in] ControllerHandle The handle of the controller to test. This
> + handle must support a protocol interface that
> + supplies an I/O abstraction to the driver.
> + @param[in] RemainingDevicePath A pointer to the remaining portion of a
> + device path. This parameter is ignored by
> + device drivers, and is optional for bus
> + drivers. For bus drivers, if this parameter
> + is not NULL, then the bus driver must deter-
> + mine if the bus controller specified by
> + ControllerHandle and the child controller
> + specified by RemainingDevicePath are both
> + supported by this bus driver.
> +
> + @retval EFI_SUCCESS The device specified by ControllerHandle and
> + RemainingDevicePath is supported by the
> + driver specified by This.
> + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
> + RemainingDevicePath is already being managed
> + by the driver specified by This.
> + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
> + RemainingDevicePath is already being managed
> + by a different driver or an application that
> + requires exclusive access.
> + Currently not implemented.
> + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
> + RemainingDevicePath is not supported by the
> + driver specified by This.
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcHcDriverBindingSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
> + NON_DISCOVERABLE_DEVICE *Dev;
> + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc;
> +
> + ParentDevicePath = NULL;
> +
> + Status = gBS->LocateProtocol (
> + &gPlatformDwMmcProtocolGuid,
> + NULL,
> + (VOID **) &PlatformDwMmc
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Status = gBS->OpenProtocol (
> + Controller,
> + &gEfiDevicePathProtocolGuid,
> + (VOID *) &ParentDevicePath,
> + This->DriverBindingHandle,
> + Controller,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + //
> + // EFI_ALREADY_STARTED is also an error.
> + //
> + return Status;
> + }
> + //
> + // Close the protocol because we don't use it here.
> + //
> + gBS->CloseProtocol (
> + Controller,
> + &gEfiDevicePathProtocolGuid,
> + This->DriverBindingHandle,
> + Controller
> + );
> +
> + //
> + // Now test the EmbeddedNonDiscoverableIoProtocol.
> + //
> + Status = gBS->OpenProtocol (
> + Controller,
> + &gEdkiiNonDiscoverableDeviceProtocolGuid,
> + (VOID **) &Dev,
> + This->DriverBindingHandle,
> + Controller,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + gBS->CloseProtocol (
> + Controller,
> + &gEdkiiNonDiscoverableDeviceProtocolGuid,
> + This->DriverBindingHandle,
> + Controller
> + );
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Starts a device controller or a bus controller.
> +
> + The Start() function is designed to be invoked from the EFI boot service
> + ConnectController().
> + As a result, much of the error checking on the parameters to Start() has
> + been moved into this
> + common boot service. It is legal to call Start() from other locations,
> + but the following calling restrictions must be followed or the system
> + behavior will not be deterministic.
> + 1. ControllerHandle must be a valid EFI_HANDLE.
> + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a
> + naturally aligned EFI_DEVICE_PATH_PROTOCOL.
> + 3. Prior to calling Start(), the Supported() function for the driver
> + specified by This must have been called with the same calling parameters,
> + and Supported() must have returned EFI_SUCCESS.
> +
> + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
> + instance.
> + @param[in] ControllerHandle The handle of the controller to start. This
> + handle must support a protocol interface
> + that supplies an I/O abstraction to the
> + driver.
> + @param[in] RemainingDevicePath A pointer to the remaining portion of a
> + device path. This parameter is ignored by
> + device drivers, and is optional for bus
> + drivers.
> + For a bus driver, if this parameter is NULL,
> + then handles for all the children of
> + Controller are created by this driver.
> + If this parameter is not NULL and the first
> + Device Path Node is not the End of Device
> + Path Node, then only the handle for the
> + child device specified by the first Device
> + Path Node of RemainingDevicePath is created
> + by this driver.
> + If the first Device Path Node of
> + RemainingDevicePath is the End of Device Path
> + Node, no child handle is created by this
> + driver.
> +
> + @retval EFI_SUCCESS The device was started.
> + @retval EFI_DEVICE_ERROR The device could not be started due to a
> + device error. Currently not implemented.
> + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
> + lack of resources.
> + @retval Others The driver failded to start the device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcHcDriverBindingStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + DW_MMC_HC_PRIVATE_DATA *Private;
> +
> + NON_DISCOVERABLE_DEVICE *Dev;
> +
> + BOOLEAN MediaPresent;
> + DWMMC_CARD_TYPE_DETECT_ROUTINE *Routine;
> + UINT8 Index;
> + UINT32 RoutineNum;
> + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc;
> +
> + Status = gBS->LocateProtocol (
> + &gPlatformDwMmcProtocolGuid,
> + NULL,
> + (VOID **) &PlatformDwMmc
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "err %d", __LINE__));
> + return Status;
> + }
> +
> + Status = gBS->OpenProtocol (
> + Controller,
> + &gEdkiiNonDiscoverableDeviceProtocolGuid,
> + (VOID **) &Dev,
> + This->DriverBindingHandle,
> + Controller,
> + EFI_OPEN_PROTOCOL_BY_DRIVER
> + );
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "err %d", __LINE__));
> + return Status;
> + }
> +
> + Private = AllocateCopyPool (sizeof (DW_MMC_HC_PRIVATE_DATA), &gDwMmcHcTemplate);
> + if (Private == NULL) {
> + DEBUG ((DEBUG_ERROR, "err %d", __LINE__));
> + Status = EFI_OUT_OF_RESOURCES;
> + goto Done;
> + }
> +
> + Private->ControllerHandle = Controller;
> + Private->DevBase = Dev->Resources[0].AddrRangeMin;
> + Private->PlatformDwMmc = PlatformDwMmc;
> + InitializeListHead (&Private->Queue);
> +
> + Status = Private->PlatformDwMmc->GetCapability (Controller, 0, &Private->Capability[0]);
> +
> + if (EFI_ERROR (Status)) {
> + goto Done;
> + }
> +
> + if (Private->Capability[0].BaseClkFreq == 0) {
> + goto Done;
> + }
> +
> + DumpCapabilityReg (0, &Private->Capability[0]);
> +
> + MediaPresent = FALSE;
> +
> + Status = Private->PlatformDwMmc->CardDetect (Controller, 0);
> + Status = DwMmcHcCardDetect (Private->DevBase, Controller, 0, &MediaPresent);
> + if (MediaPresent == FALSE) {
> + goto Done;
> + }
> +
> + //
> + // Initialize slot and start identification process for the new attached device
> + //
> + Status = DwMmcHcInitHost (Private->DevBase, Private->Capability[0]);
> + if (EFI_ERROR (Status)) {
> + goto Done;
> + }
> +
> + //
> + // Reset HC
> + //
> + Status = DwMmcHcReset (Private->DevBase, Private->Capability[0]);
> + if (EFI_ERROR (Status)) {
> + goto Done;
> + }
> +
> + Private->Slot[0].CardType = Private->Capability[0].CardType;
> + Private->Slot[0].Enable = TRUE;
> + Private->Slot[0].MediaPresent = TRUE;
> +
> + RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (DWMMC_CARD_TYPE_DETECT_ROUTINE);
> + for (Index = 0; Index < RoutineNum; Index++) {
> + Routine = &mCardTypeDetectRoutineTable[Index];
> + if (*Routine != NULL) {
> + Status = (*Routine) (Private);
> + if (!EFI_ERROR (Status)) {
> + break;
> + }
> + }
> + }
> +
> + //
> + // Start the asynchronous I/O monitor
> + //
> + Status = gBS->CreateEvent (
> + EVT_TIMER | EVT_NOTIFY_SIGNAL,
> + TPL_NOTIFY,
> + ProcessAsyncTaskList,
> + Private,
> + &Private->TimerEvent
> + );
> + if (EFI_ERROR (Status)) {
> + goto Done;
> + }
> +
> + Status = gBS->SetTimer (Private->TimerEvent, TimerPeriodic, DW_MMC_HC_ASYNC_TIMER);
> + if (EFI_ERROR (Status)) {
> + goto Done;
> + }
> +
> + //
> + // Start the Sd removable device connection enumeration
> + //
> + Status = gBS->CreateEvent (
> + EVT_TIMER | EVT_NOTIFY_SIGNAL,
> + TPL_CALLBACK,
> + DwMmcHcEnumerateDevice,
> + Private,
> + &Private->ConnectEvent
> + );
> + if (EFI_ERROR (Status)) {
> + goto Done;
> + }
> +
> + Status = gBS->SetTimer (Private->ConnectEvent, TimerPeriodic, DW_MMC_HC_ENUM_TIMER);
> + if (EFI_ERROR (Status)) {
> + goto Done;
> + }
> +
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &Controller,
> + &gEfiSdMmcPassThruProtocolGuid,
> + &(Private->PassThru),
> + NULL
> + );
> +
> + DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStart: %r End on %x\n", Status, Controller));
> +
> +Done:
> + if (EFI_ERROR (Status)) {
> + if ((Private != NULL) && (Private->TimerEvent != NULL)) {
> + gBS->CloseEvent (Private->TimerEvent);
> + }
> +
> + if ((Private != NULL) && (Private->ConnectEvent != NULL)) {
> + gBS->CloseEvent (Private->ConnectEvent);
> + }
> +
> + if (Private != NULL) {
> + FreePool (Private);
> + }
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Stops a device controller or a bus controller.
> +
> + The Stop() function is designed to be invoked from the EFI boot service
> + DisconnectController().
> + As a result, much of the error checking on the parameters to Stop() has been
> + moved into this common boot service. It is legal to call Stop() from other
> + locations, but the following calling restrictions must be followed or the
> + system behavior will not be deterministic.
> + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous
> + call to this same driver's Start() function.
> + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
> + EFI_HANDLE. In addition, all of these handles must have been created in
> + this driver's Start() function, and the Start() function must have called
> + OpenProtocol() on ControllerHandle with an Attribute of
> + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
> +
> + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
> + instance.
> + @param[in] ControllerHandle A handle to the device being stopped. The handle
> + must support a bus specific I/O protocol for the
> + driver to use to stop the device.
> + @param[in] NumberOfChildren The number of child device handles in
> + ChildHandleBuffer.
> + @param[in] ChildHandleBuffer An array of child handles to be freed. May be
> + NULL if NumberOfChildren is 0.
> +
> + @retval EFI_SUCCESS The device was stopped.
> + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device
> + error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcHcDriverBindingStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + )
> +{
> + EFI_STATUS Status;
> + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
> + DW_MMC_HC_PRIVATE_DATA *Private;
> + LIST_ENTRY *Link;
> + LIST_ENTRY *NextLink;
> + DW_MMC_HC_TRB *Trb;
> +
> + DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStop: Start\n"));
> +
> + Status = gBS->OpenProtocol (
> + Controller,
> + &gEfiSdMmcPassThruProtocolGuid,
> + (VOID**) &PassThru,
> + This->DriverBindingHandle,
> + Controller,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru);
> + //
> + // Close Non-Blocking timer and free Task list.
> + //
> + if (Private->TimerEvent != NULL) {
> + gBS->CloseEvent (Private->TimerEvent);
> + Private->TimerEvent = NULL;
> + }
> + if (Private->ConnectEvent != NULL) {
> + gBS->CloseEvent (Private->ConnectEvent);
> + Private->ConnectEvent = NULL;
> + }
> + //
> + // As the timer is closed, there is no needs to use TPL lock to
> + // protect the critical region "queue".
> + //
> + for (Link = GetFirstNode (&Private->Queue);
> + !IsNull (&Private->Queue, Link);
> + Link = NextLink) {
> + NextLink = GetNextNode (&Private->Queue, Link);
> + RemoveEntryList (Link);
> + Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
> + Trb->Packet->TransactionStatus = EFI_ABORTED;
> + gBS->SignalEvent (Trb->Event);
> + DwMmcFreeTrb (Trb);
> + }
> +
> + //
> + // Uninstall Block I/O protocol from the device handle
> + //
> + Status = gBS->UninstallProtocolInterface (
> + Controller,
> + &gEfiSdMmcPassThruProtocolGuid,
> + &(Private->PassThru)
> + );
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + gBS->CloseProtocol (
> + Controller,
> + &gEfiPciIoProtocolGuid,
> + This->DriverBindingHandle,
> + Controller
> + );
> +
> + FreePool (Private);
> +
> + DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStop: End with %r\n", Status));
> +
> + return Status;
> +}
> +
> +/**
> + Sends SD command to an SD card that is attached to the SD controller.
> +
> + The PassThru() function sends the SD command specified by Packet to the SD
> + card specified by Slot.
> +
> + If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.
> +
> + If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is
> + returned.
> +
> + If Slot is not in a valid range for the SD controller, then
> + EFI_INVALID_PARAMETER is returned.
> +
> + If Packet defines a data command but both InDataBuffer and OutDataBuffer are
> + NULL, EFI_INVALID_PARAMETER is returned.
> +
> + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Slot The slot number of the SD card to send the
> + command to.
> + @param[in,out] Packet A pointer to the SD command data structure.
> + @param[in] Event If Event is NULL, blocking I/O is performed. If
> + Event is not NULL, then nonblocking I/O is
> + performed, and Event will be signaled when the
> + Packet completes.
> +
> + @retval EFI_SUCCESS The SD Command Packet was sent by the host.
> + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
> + the SD command Packet.
> + @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is
> + invalid.
> + @retval EFI_INVALID_PARAMETER Packet defines a data command but both
> + InDataBuffer and OutDataBuffer are NULL.
> + @retval EFI_NO_MEDIA SD Device not present in the Slot.
> + @retval EFI_UNSUPPORTED The command described by the SD Command Packet
> + is not supported by the host controller.
> + @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength
> + exceeds the limit supported by SD card
> + ( i.e. if the number of bytes exceed the Last
> + LBA).
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcPassThruPassThru (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> + IN UINT8 Slot,
> + IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
> + IN EFI_EVENT Event OPTIONAL
> + )
> +{
> + EFI_STATUS Status;
> + DW_MMC_HC_PRIVATE_DATA *Private;
> + DW_MMC_HC_TRB *Trb;
> + EFI_TPL OldTpl;
> +
> + if ((This == NULL) || (Packet == NULL)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if ((Packet->SdMmcCmdBlk == NULL) || (Packet->SdMmcStatusBlk == NULL)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
> +
> + if (!Private->Slot[Slot].Enable) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (!Private->Slot[Slot].MediaPresent) {
> + return EFI_NO_MEDIA;
> + }
> +
> + Trb = DwMmcCreateTrb (Private, Slot, Packet, Event);
> + if (Trb == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> + //
> + // Immediately return for async I/O.
> + //
> + if (Event != NULL) {
> + return EFI_SUCCESS;
> + }
> +
> + //
> + // Wait async I/O list is empty before execute sync I/O operation.
> + //
> + while (TRUE) {
> + OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> + if (IsListEmpty (&Private->Queue)) {
> + gBS->RestoreTPL (OldTpl);
> + break;
> + }
> + gBS->RestoreTPL (OldTpl);
> + }
> +
> + Status = DwMmcWaitTrbEnv (Private, Trb);
> + if (EFI_ERROR (Status)) {
> + goto Done;
> + }
> +
> + Status = DwMmcExecTrb (Private, Trb);
> + if (EFI_ERROR (Status)) {
> + goto Done;
> + }
> +
> + Status = DwMmcWaitTrbResult (Private, Trb);
> + if (EFI_ERROR (Status)) {
> + goto Done;
> + }
> +
> +Done:
> + if (Trb != NULL) {
> + DwMmcFreeTrb (Trb);
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Used to retrieve next slot numbers supported by the SD controller. The
> + function returns information about all available slots (populated or
> + not-populated).
> +
> + The GetNextSlot() function retrieves the next slot number on an SD controller.
> + If on input Slot is 0xFF, then the slot number of the first slot on the SD
> + controller is returned.
> +
> + If Slot is a slot number that was returned on a previous call to
> + GetNextSlot(), then the slot number of the next slot on the SD controller is
> + returned.
> +
> + If Slot is not 0xFF and Slot was not returned on a previous call to
> + GetNextSlot(), EFI_INVALID_PARAMETER is returned.
> +
> + If Slot is the slot number of the last slot on the SD controller, then
> + EFI_NOT_FOUND is returned.
> +
> + @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in,out] Slot On input, a pointer to a slot number on the SD
> + controller.
> + On output, a pointer to the next slot number on
> + the SD controller.
> + An input value of 0xFF retrieves the first slot
> + number on the SD controller.
> +
> + @retval EFI_SUCCESS The next slot number on the SD controller was
> + returned in Slot.
> + @retval EFI_NOT_FOUND There are no more slots on this SD controller.
> + @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a
> + previous call to GetNextSlot().
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcPassThruGetNextSlot (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> + IN OUT UINT8 *Slot
> + )
> +{
> + DW_MMC_HC_PRIVATE_DATA *Private;
> +
> + if ((This == NULL) || (Slot == NULL)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
> +
> + if (*Slot == 0xFF) {
> + if (Private->Slot[0].Enable) {
> + *Slot = 0;
> + Private->PreviousSlot = 0;
> + return EFI_SUCCESS;
> + }
> + return EFI_NOT_FOUND;
> + } else if (*Slot == Private->PreviousSlot) {
> + return EFI_NOT_FOUND;
> + } else {
> + return EFI_INVALID_PARAMETER;
> + }
> +}
> +
> +/**
> + Used to allocate and build a device path node for an SD card on the SD
> + controller.
> +
> + The BuildDevicePath() function allocates and builds a single device node
> + for the SD card specified by Slot.
> +
> + If the SD card specified by Slot is not present on the SD controller, then
> + EFI_NOT_FOUND is returned.
> +
> + If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.
> +
> + If there are not enough resources to allocate the device path node, then
> + EFI_OUT_OF_RESOURCES is returned.
> +
> + Otherwise, DevicePath is allocated with the boot service AllocatePool(),
> + the contents of DevicePath are initialized to describe the SD card specified
> + by Slot, and EFI_SUCCESS is returned.
> +
> + @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Slot Specifies the slot number of the SD card for
> + which a device path node is to be allocated and
> + built.
> + @param[in,out] DevicePath A pointer to a single device path node that
> + describes the SD card specified by Slot. This
> + function is responsible for allocating the
> + buffer DevicePath with the boot service
> + AllocatePool(). It is the caller's responsi-
> + bility to free DevicePath when the caller is
> + finished with DevicePath.
> +
> + @retval EFI_SUCCESS The device path node that describes the SD card
> + specified by Slot was allocated and returned in
> + DevicePath.
> + @retval EFI_NOT_FOUND The SD card specified by Slot does not exist on
> + the SD controller.
> + @retval EFI_INVALID_PARAMETER DevicePath is NULL.
> + @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate
> + DevicePath.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcPassThruBuildDevicePath (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> + IN UINT8 Slot,
> + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
> + )
> +{
> + DW_MMC_HC_PRIVATE_DATA *Private;
> + SD_DEVICE_PATH *SdNode;
> + EMMC_DEVICE_PATH *EmmcNode;
> +
> + if ((This == NULL) || (DevicePath == NULL) || (Slot >= DW_MMC_HC_MAX_SLOT)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
> +
> + if ((!Private->Slot[Slot].Enable) || (!Private->Slot[Slot].MediaPresent)) {
> + return EFI_NOT_FOUND;
> + }
> +
> + if (Private->Slot[Slot].CardType == SdCardType) {
> + SdNode = AllocateCopyPool (sizeof (SD_DEVICE_PATH), &mSdDpTemplate);
> + if (SdNode == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> + SdNode->SlotNumber = Slot;
> +
> + *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) SdNode;
> + } else if (Private->Slot[Slot].CardType == EmmcCardType) {
> + EmmcNode = AllocateCopyPool (sizeof (EMMC_DEVICE_PATH), &mEmmcDpTemplate);
> + if (EmmcNode == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> + EmmcNode->SlotNumber = Slot;
> +
> + *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) EmmcNode;
> + } else {
> + //
> + // Currently we only support SD and EMMC two device nodes.
> + //
> + return EFI_NOT_FOUND;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This function retrieves an SD card slot number based on the input device path.
> +
> + The GetSlotNumber() function retrieves slot number for the SD card specified
> + by the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is
> + returned.
> +
> + If DevicePath is not a device path node type that the SD Pass Thru driver
> + supports, EFI_UNSUPPORTED is returned.
> +
> + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] DevicePath A pointer to the device path node that describes
> + a SD card on the SD controller.
> + @param[out] Slot On return, points to the slot number of an SD
> + card on the SD controller.
> +
> + @retval EFI_SUCCESS SD card slot number is returned in Slot.
> + @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.
> + @retval EFI_UNSUPPORTED DevicePath is not a device path node type that
> + the SD Pass Thru driver supports.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcPassThruGetSlotNumber (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
> + OUT UINT8 *Slot
> + )
> +{
> + DW_MMC_HC_PRIVATE_DATA *Private;
> + SD_DEVICE_PATH *SdNode;
> + EMMC_DEVICE_PATH *EmmcNode;
> + UINT8 SlotNumber;
> +
> + if ((This == NULL) || (DevicePath == NULL) || (Slot == NULL)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
> +
> + //
> + // Check whether the DevicePath belongs to SD_DEVICE_PATH or EMMC_DEVICE_PATH
> + //
> + if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
> + ((DevicePath->SubType != MSG_SD_DP) &&
> + (DevicePath->SubType != MSG_EMMC_DP)) ||
> + (DevicePathNodeLength(DevicePath) != sizeof(SD_DEVICE_PATH)) ||
> + (DevicePathNodeLength(DevicePath) != sizeof(EMMC_DEVICE_PATH))) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + if (DevicePath->SubType == MSG_SD_DP) {
> + SdNode = (SD_DEVICE_PATH *) DevicePath;
> + SlotNumber = SdNode->SlotNumber;
> + } else {
> + EmmcNode = (EMMC_DEVICE_PATH *) DevicePath;
> + SlotNumber = EmmcNode->SlotNumber;
> + }
> +
> + if (SlotNumber >= DW_MMC_HC_MAX_SLOT) {
> + return EFI_NOT_FOUND;
> + }
> +
> + if (Private->Slot[SlotNumber].Enable) {
> + *Slot = SlotNumber;
> + return EFI_SUCCESS;
> + } else {
> + return EFI_NOT_FOUND;
> + }
> +}
> +
> +/**
> + Resets an SD card that is connected to the SD controller.
> +
> + The ResetDevice() function resets the SD card specified by Slot.
> +
> + If this SD controller does not support a device reset operation,
> + EFI_UNSUPPORTED is returned.
> +
> + If Slot is not in a valid slot number for this SD controller,
> + EFI_INVALID_PARAMETER is returned.
> +
> + If the device reset operation is completed, EFI_SUCCESS is returned.
> +
> + @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Slot Specifies the slot number of the SD card to be
> + reset.
> +
> + @retval EFI_SUCCESS The SD card specified by Slot was reset.
> + @retval EFI_UNSUPPORTED The SD controller does not support a device
> + reset operation.
> + @retval EFI_INVALID_PARAMETER Slot number is invalid.
> + @retval EFI_NO_MEDIA SD Device not present in the Slot.
> + @retval EFI_DEVICE_ERROR The reset command failed due to a device error
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +DwMmcPassThruResetDevice (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> + IN UINT8 Slot
> + )
> +{
> + DW_MMC_HC_PRIVATE_DATA *Private;
> + LIST_ENTRY *Link;
> + LIST_ENTRY *NextLink;
> + DW_MMC_HC_TRB *Trb;
> + EFI_TPL OldTpl;
> +
> + if (This == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
> +
> + if (!Private->Slot[Slot].Enable) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (!Private->Slot[Slot].MediaPresent) {
> + return EFI_NO_MEDIA;
> + }
> +
> + //
> + // Free all async I/O requests in the queue
> + //
> + OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> +
> + for (Link = GetFirstNode (&Private->Queue);
> + !IsNull (&Private->Queue, Link);
> + Link = NextLink) {
> + NextLink = GetNextNode (&Private->Queue, Link);
> + RemoveEntryList (Link);
> + Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
> + Trb->Packet->TransactionStatus = EFI_ABORTED;
> + gBS->SignalEvent (Trb->Event);
> + DwMmcFreeTrb (Trb);
> + }
> +
> + gBS->RestoreTPL (OldTpl);
> +
> + return EFI_SUCCESS;
> +}
> diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
> new file mode 100644
> index 000000000000..b091f9803b2e
> --- /dev/null
> +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
> @@ -0,0 +1,1602 @@
> +/** @file
> + This driver is used to manage Designware SD/MMC PCI host controllers.
> +
> + It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.
> +
> + Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR>
> + Copyright (c) 2018, Linaro Ltd. 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 <IndustryStandard/Emmc.h>
> +#include <IndustryStandard/Sd.h>
> +
> +#include <Library/ArmLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DmaLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +
> +#include "DwMmcHcDxe.h"
> +
> +/**
> + Dump the content of SD/MMC host controller's Capability Register.
> +
> + @param[in] Slot The slot number of the SD card to send the
> + command to.
> + @param[in] Capability The buffer to store the capability data.
> +
> +**/
> +VOID
> +DumpCapabilityReg (
> + IN UINT8 Slot,
> + IN DW_MMC_HC_SLOT_CAP *Capability
> + )
> +{
> + //
> + // Dump Capability Data
> + //
> + DEBUG ((
> + DEBUG_INFO,
> + " == Slot [%d] Capability is 0x%x ==\n",
> + Slot,
> + Capability
> + ));
> + DEBUG ((
> + DEBUG_INFO,
> + " Base Clk Freq %dKHz\n",
> + Capability->BaseClkFreq
> + ));
> + DEBUG ((
> + DEBUG_INFO,
> + " BusWidth %d\n",
> + Capability->BusWidth
> + ));
> + DEBUG ((
> + DEBUG_INFO,
> + " HighSpeed Support %a\n",
> + Capability->HighSpeed ? "TRUE" : "FALSE"
> + ));
> + DEBUG ((
> + DEBUG_INFO,
> + " Voltage 1.8 %a\n",
> + Capability->Voltage18 ? "TRUE" : "FALSE"
> + ));
> + DEBUG ((
> + DEBUG_INFO,
> + " 64-bit Sys Bus %a\n",
> + Capability->SysBus64 ? "TRUE" : "FALSE"
> + ));
> + DEBUG ((DEBUG_INFO, " SlotType "));
> + if (Capability->SlotType == 0x00) {
> + DEBUG ((DEBUG_INFO, "%a\n", "Removable Slot"));
> + } else if (Capability->SlotType == 0x01) {
> + DEBUG ((DEBUG_INFO, "%a\n", "Embedded Slot"));
> + } else if (Capability->SlotType == 0x02) {
> + DEBUG ((DEBUG_INFO, "%a\n", "Shared Bus Slot"));
> + } else {
> + DEBUG ((DEBUG_INFO, "%a\n", "Reserved"));
> + }
> + DEBUG ((
> + DEBUG_INFO,
> + " SDR50 Support %a\n",
> + Capability->Sdr50 ? "TRUE" : "FALSE"
> + ));
> + DEBUG ((
> + DEBUG_INFO,
> + " SDR104 Support %a\n",
> + Capability->Sdr104 ? "TRUE" : "FALSE"
> + ));
> + DEBUG ((
> + DEBUG_INFO,
> + " DDR50 Support %a\n",
> + Capability->Ddr50 ? "TRUE" : "FALSE"
> + ));
> + return;
> +}
> +
> +/**
> + Set all interrupt status bits in Normal and Error Interrupt Status Enable
> + register.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> +
> + @retval EFI_SUCCESS The operation executes successfully.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcEnableInterrupt (
> + UINTN DevBase
> + )
> +{
> + UINT32 IntStatus;
> + UINT32 IdIntEn;
> + UINT32 IdSts;
> +
> + //
> + // Enable all bits in Interrupt Mask Register
> + //
> + IntStatus = 0;
> + MmioWrite32 (DevBase + DW_MMC_INTMASK, IntStatus);
> +
> + //
> + // Clear status in Interrupt Status Register
> + //
> + IntStatus = ~0;
> + MmioWrite32 (DevBase + DW_MMC_RINTSTS, IntStatus);
> +
> + IdIntEn = ~0;
> + MmioWrite32 (DevBase + DW_MMC_IDINTEN, IdIntEn);
> +
> + IdSts = ~0;
> + MmioWrite32 (DevBase + DW_MMC_IDSTS, IdSts);
> +
> + return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +DwMmcHcGetCapability (
> + IN UINTN DevBase,
> + IN EFI_HANDLE Controller,
> + IN UINT8 Slot,
> + OUT DW_MMC_HC_SLOT_CAP *Capacity
> + )
> +{
> + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc;
> + EFI_STATUS Status;
> +
> + if (Capacity == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> + Status = gBS->LocateProtocol (
> + &gPlatformDwMmcProtocolGuid,
> + NULL,
> + (VOID **) &PlatformDwMmc
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + Status = PlatformDwMmc->GetCapability (Controller, Slot, Capacity);
> + return Status;
> +}
> +
> +/**
> + Detect whether there is a SD/MMC card attached at the specified SD/MMC host
> + controller slot.
> +
> + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command
> + to.
> + @param[out] MediaPresent The pointer to the media present boolean value.
> +
> + @retval EFI_SUCCESS There is no media change happened.
> + @retval EFI_MEDIA_CHANGED There is media change happened.
> + @retval Others The detection fails.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcCardDetect (
> + IN UINTN DevBase,
> + IN EFI_HANDLE Controller,
> + IN UINT8 Slot,
> + OUT BOOLEAN *MediaPresent
> + )
> +{
> + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc;
> + EFI_STATUS Status;
> +
> + if (MediaPresent == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> + Status = gBS->LocateProtocol (
> + &gPlatformDwMmcProtocolGuid,
> + NULL,
> + (VOID **) &PlatformDwMmc
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + *MediaPresent = PlatformDwMmc->CardDetect (Controller, Slot);
> + return EFI_SUCCESS;
> +}
> +
> +STATIC
> +EFI_STATUS
> +DwMmcHcUpdateClock (
> + IN UINTN DevBase
> + )
> +{
> + UINT32 Cmd;
> + UINT32 IntStatus;
> +
> + Cmd = BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_UPDATE_CLOCK_ONLY |
> + BIT_CMD_START;
> + MmioWrite32 (DevBase + DW_MMC_CMD, Cmd);
> +
> + while (1) {
> + Cmd = MmioRead32 (DevBase + DW_MMC_CMD);
> +
> + if (!(Cmd & CMD_START_BIT)) {
> + break;
> + }
> +
> + IntStatus = MmioRead32 (DevBase + DW_MMC_RINTSTS);
> +
> + if (IntStatus & DW_MMC_INT_HLE) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "DwMmcHcUpdateClock: failed to update mmc clock frequency\n"
> + ));
> + return EFI_DEVICE_ERROR;
> + }
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Stop SD/MMC card clock.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> +
> + @retval EFI_SUCCESS Succeed to stop SD/MMC clock.
> + @retval Others Fail to stop SD/MMC clock.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcStopClock (
> + IN UINTN DevBase
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 ClkEna;
> +
> + //
> + // Disable MMC clock first
> + //
> + ClkEna = 0;
> + MmioWrite32 (DevBase + DW_MMC_CLKENA, ClkEna);
> +
> + Status = DwMmcHcUpdateClock (DevBase);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + return Status;
> +}
> +
> +/**
> + SD/MMC card clock supply.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
> + @param[in] Capability The capability of the slot.
> +
> + @retval EFI_SUCCESS The clock is supplied successfully.
> + @retval Others The clock isn't supplied successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcClockSupply (
> + IN UINTN DevBase,
> + IN UINT64 ClockFreq,
> + IN DW_MMC_HC_SLOT_CAP Capability
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 BaseClkFreq;
> + UINT32 SettingFreq;
> + UINT32 Divisor;
> + UINT32 Remainder;
> + UINT32 MmcStatus;
> + UINT32 ClkEna;
> + UINT32 ClkSrc;
> +
> + //
> + // Calculate a divisor for SD clock frequency
> + //
> + ASSERT (Capability.BaseClkFreq != 0);
> +
> + BaseClkFreq = Capability.BaseClkFreq;
> + if (ClockFreq == 0) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (ClockFreq > BaseClkFreq) {
> + ClockFreq = BaseClkFreq;
> + }
> +
> + //
> + // Calculate the divisor of base frequency.
> + //
> + Divisor = 0;
> + SettingFreq = BaseClkFreq;
> + while (ClockFreq < SettingFreq) {
> + Divisor++;
> +
> + SettingFreq = BaseClkFreq / (2 * Divisor);
> + Remainder = BaseClkFreq % (2 * Divisor);
> + if ((ClockFreq == SettingFreq) && (Remainder == 0)) {
> + break;
> + }
> + if ((ClockFreq == SettingFreq) && (Remainder != 0)) {
> + SettingFreq ++;
> + }
> + }
> +
> + DEBUG ((
> + DEBUG_INFO,
> + "BaseClkFreq %dKHz Divisor %d ClockFreq %dKhz\n",
> + BaseClkFreq,
> + Divisor,
> + ClockFreq
> + ));
> +
> + //
> + // Wait until MMC is idle
> + //
> + do {
> + MmcStatus = MmioRead32 (DevBase + DW_MMC_STATUS);
> + } while (MmcStatus & DW_MMC_STS_DATA_BUSY);
> +
> + do {
> + Status = DwMmcHcStopClock (DevBase);
> + } while (EFI_ERROR (Status));
> +
> + do {
> + ClkSrc = 0;
> + MmioWrite32 (DevBase + DW_MMC_CLKSRC, ClkSrc);
> + //
> + // Set clock divisor
> + //
> + MmioWrite32 (DevBase + DW_MMC_CLKDIV, Divisor);
> + //
> + // Enable MMC clock
> + //
> + ClkEna = 1;
> + MmioWrite32 (DevBase + DW_MMC_CLKENA, ClkEna);
> +
> + Status = DwMmcHcUpdateClock (DevBase);
> + } while (EFI_ERROR (Status));
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Set the SD/MMC bus width.
> +
> + Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] IsDdr A boolean to indicate it's dual data rate or not.
> + @param[in] BusWidth The bus width used by the SD/MMC device, it must be
> + 1, 4 or 8.
> +
> + @retval EFI_SUCCESS The bus width is set successfully.
> + @retval Others The bus width isn't set successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcSetBusWidth (
> + IN UINTN DevBase,
> + IN BOOLEAN IsDdr,
> + IN UINT16 BusWidth
> + )
> +{
> + UINT32 Ctype;
> + UINT32 Uhs;
> +
> + switch (BusWidth) {
> + case 1:
> + Ctype = MMC_1BIT_MODE;
> + break;
> + case 4:
> + Ctype = MMC_4BIT_MODE;
> + break;
> + case 8:
> + Ctype = MMC_8BIT_MODE;
> + break;
> + default:
> + return EFI_INVALID_PARAMETER;
> + }
> + MmioWrite32 (DevBase + DW_MMC_CTYPE, Ctype);
> +
> + Uhs = MmioRead32 (DevBase + DW_MMC_UHSREG);
> +
> + if (IsDdr) {
> + Uhs |= UHS_DDR_MODE;
> + } else {
> + Uhs &= ~(UHS_DDR_MODE);
> + }
> +
> + MmioWrite32 (DevBase + DW_MMC_UHSREG, Uhs);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Supply SD/MMC card with lowest clock frequency at initialization.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] Capability The capability of the slot.
> +
> + @retval EFI_SUCCESS The clock is supplied successfully.
> + @retval Others The clock isn't supplied successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcInitClockFreq (
> + IN UINTN DevBase,
> + IN DW_MMC_HC_SLOT_CAP Capability
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 InitFreq;
> +
> + //
> + // Calculate a divisor for SD clock frequency
> + //
> + if (Capability.BaseClkFreq == 0) {
> + //
> + // Don't support get Base Clock Frequency information via another method
> + //
> + return EFI_UNSUPPORTED;
> + }
> + //
> + // Supply 400KHz clock frequency at initialization phase.
> + //
> + InitFreq = DWMMC_INIT_CLOCK_FREQ;
> + Status = DwMmcHcClockSupply (DevBase, InitFreq, Capability);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + MicroSecondDelay (100);
> + return Status;
> +}
> +
> +/**
> + Supply SD/MMC card with maximum voltage at initialization.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] Capability The capability of the slot.
> +
> + @retval EFI_SUCCESS The voltage is supplied successfully.
> + @retval Others The voltage isn't supplied successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcInitPowerVoltage (
> + IN UINTN DevBase,
> + IN DW_MMC_HC_SLOT_CAP Capability
> + )
> +{
> + UINT32 Data;
> + UINT32 Timeout;
> +
> + Data = 0x1;
> + MmioWrite32 (DevBase + DW_MMC_PWREN, Data);
> +
> + Data = DW_MMC_CTRL_RESET_ALL;
> + MmioWrite32 (DevBase + DW_MMC_CTRL, Data);
> +
> + Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> + while (Timeout > 0) {
> + Data = MmioRead32 (DevBase + DW_MMC_CTRL);
> +
> + if ((Data & DW_MMC_CTRL_RESET_ALL) == 0) {
> + break;
> + }
> + gBS->Stall (1);
> +
> + Timeout--;
> + }
> +
> + if (Timeout <= 0) {
> + DEBUG ((DEBUG_INFO,
> + "DwMmcHcInitPowerVoltage: reset failed due to timeout"));
> +
> + return EFI_TIMEOUT;
> + }
> +
> + Data = DW_MMC_CTRL_INT_EN;
> + MmioWrite32 (DevBase + DW_MMC_CTRL, Data);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Initialize the Timeout Control register with most conservative value at
> + initialization.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> +
> + @retval EFI_SUCCESS The timeout control register is configured
> + successfully.
> + @retval Others The timeout control register isn't configured
> + successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcInitTimeoutCtrl (
> + IN UINTN DevBase
> + )
> +{
> + UINT32 Data;
> +
> + Data = ~0;
> + MmioWrite32 (DevBase + DW_MMC_TMOUT, Data);
> +
> + Data = 0x00FFFFFF;
> + MmioWrite32 (DevBase + DW_MMC_DEBNCE, Data);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Initial SD/MMC host controller with lowest clock frequency, max power and
> + max timeout value at initialization.
> +
> + @param[in] DevIo The DEVICE IO protocol instance.
> + @param[in] Slot The slot number of the SD card to send the command
> + to.
> + @param[in] Capability The capability of the slot.
> +
> + @retval EFI_SUCCESS The host controller is initialized successfully.
> + @retval Others The host controller isn't initialized successfully.
> +
> +**/
> +EFI_STATUS
> +DwMmcHcInitHost (
> + IN UINTN DevBase,
> + IN DW_MMC_HC_SLOT_CAP Capability
> + )
> +{
> + EFI_STATUS Status;
> +
> + Status = DwMmcHcInitPowerVoltage (DevBase, Capability);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + return Status;
> +}
> +
> +EFI_STATUS
> +DwMmcHcStartDma (
> + IN DW_MMC_HC_PRIVATE_DATA *Private,
> + IN DW_MMC_HC_TRB *Trb
> + )
> +{
> + UINTN DevBase;
> + UINT32 Ctrl;
> + UINT32 Bmod;
> + UINT32 Timeout;
> + UINT32 Data;
> +
> +// DevIo = Trb->Private->DevIo;
> + DevBase = Trb->Private->DevBase;
> +
> + //
> + // Reset DMA
> + //
> + Ctrl = DW_MMC_CTRL_DMA_RESET;
> + MmioWrite32 (DevBase + DW_MMC_CTRL, Ctrl);
> +
> + Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> + while (Timeout > 0) {
> + Data = MmioRead32 (DevBase + DW_MMC_CTRL);
> +
> + if ((Data & DW_MMC_CTRL_DMA_RESET) == 0) {
> + break;
> + }
> + gBS->Stall (1);
> +
> + Timeout--;
> + }
> +
> + if (Timeout <= 0) {
> + DEBUG ((DEBUG_ERROR, "Timed out waiting for CTRL_DMA_RESET"));
> +
> + return EFI_TIMEOUT;
> + }
> +
> + Bmod = DW_MMC_IDMAC_SWRESET | MmioRead32 (DevBase + DW_MMC_BMOD);
> +
> + MmioWrite32 (DevBase + DW_MMC_BMOD, Bmod);
> +
> + //
> + // Select IDMAC
> + //
> + Ctrl = DW_MMC_CTRL_IDMAC_EN;
> + Ctrl |= MmioRead32 (DevBase + DW_MMC_CTRL);
> + MmioWrite32 (DevBase + DW_MMC_CTRL, Ctrl);
> +
> + //
> + // Enable IDMAC
> + //
> + Bmod = DW_MMC_IDMAC_ENABLE | DW_MMC_IDMAC_FB;
> + Bmod |= MmioRead32 (DevBase + DW_MMC_BMOD);
> +
> + MmioWrite32 (DevBase + DW_MMC_BMOD, Bmod);
> +
> + return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +DwMmcHcStopDma (
> + IN DW_MMC_HC_PRIVATE_DATA *Private,
> + IN DW_MMC_HC_TRB *Trb
> + )
> +{
> + UINTN DevBase;
> + UINT32 Ctrl;
> + UINT32 Bmod;
> +
> + DevBase = Trb->Private->DevBase;
> +
> + //
> + // Disable and reset IDMAC
> + //
> + Ctrl = MmioRead32 (DevBase + DW_MMC_CTRL);
> + Ctrl &= ~DW_MMC_CTRL_IDMAC_EN;
> + Ctrl |= DW_MMC_CTRL_DMA_RESET;
> + MmioWrite32 (DevBase + DW_MMC_CTRL, Ctrl);
> +
> + //
> + // Stop IDMAC
> + //
> + Bmod = MmioRead32 (DevBase + DW_MMC_BMOD);
> + Bmod &= ~(DW_MMC_BMOD_FB | DW_MMC_BMOD_DE);
> + Bmod |= DW_MMC_BMOD_SWR;
> + MmioWrite32 (DevBase + DW_MMC_BMOD, Bmod);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Build DMA descriptor table for transfer.
> +
> + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> +
> + @retval EFI_SUCCESS The DMA descriptor table is created successfully.
> + @retval Others The DMA descriptor table isn't created successfully.
> +
> +**/
> +EFI_STATUS
> +BuildDmaDescTable (
> + IN DW_MMC_HC_TRB *Trb
> + )
> +{
> + EFI_PHYSICAL_ADDRESS Data;
> + UINT64 DataLen;
> + UINT64 Entries;
> + UINT32 Index;
> + UINT64 Remaining;
> + UINTN TableSize;
> + UINTN DevBase;
> + EFI_STATUS Status;
> + UINTN Bytes;
> + UINTN Blocks;
> + DW_MMC_HC_DMA_DESC_LINE *DmaDesc;
> + UINT32 DmaDescPhy;
> + UINT32 Idsts;
> + UINT32 BytCnt;
> + UINT32 BlkSize;
> +
> + Data = Trb->DataPhy;
> + DataLen = Trb->DataLen;
> + DevBase = Trb->Private->DevBase;
> + //
> + // Only support 32bit DMA Descriptor Table
> + //
> + if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {
> + return EFI_INVALID_PARAMETER;
> + }
> + //
> + // Address field shall be set on 32-bit boundary (Lower 2-bit is always set
> + // to 0) for 32-bit address descriptor table.
> + //
> + if ((Data & (BIT0 | BIT1)) != 0) {
> + DEBUG ((
> + DEBUG_INFO,
> + "The buffer [0x%x] to construct DMA desc is not aligned to 4 bytes!\n",
> + Data
> + ));
> + }
> +
> + Entries = (DataLen + DWMMC_DMA_BUF_SIZE - 1) / DWMMC_DMA_BUF_SIZE;
> + TableSize = Entries * sizeof (DW_MMC_HC_DMA_DESC_LINE);
> + Blocks = (DataLen + DW_MMC_BLOCK_SIZE - 1) / DW_MMC_BLOCK_SIZE;
> +
> + Trb->DmaDescPages = (UINT32)EFI_SIZE_TO_PAGES (Entries * DWMMC_DMA_BUF_SIZE);
> +/* Status = DevIo->AllocateBuffer (
> + DevIo,
> + AllocateAnyPages,
> + EfiBootServicesData,
> + EFI_SIZE_TO_PAGES (TableSize),
> + (EFI_PHYSICAL_ADDRESS *)&Trb->DmaDesc
> + );*/
> + Status = DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES (TableSize),
> + (VOID *)&Trb->DmaDesc);
> + if (EFI_ERROR (Status)) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + ZeroMem (Trb->DmaDesc, TableSize);
> + Bytes = TableSize;
> +
> + Status = DmaMap (MapOperationBusMasterCommonBuffer,
> + (EFI_PHYSICAL_ADDRESS *)Trb->DmaDesc,
> + &Bytes, &Trb->DmaDescPhy, &Trb->DmaMap);
> +/* Status = DevIo->Map (
> + DevIo,
> + EfiBusMasterCommonBuffer,
> + (EFI_PHYSICAL_ADDRESS *)Trb->DmaDesc,
> + &Bytes,
> + &Trb->DmaDescPhy,
> + &Trb->DmaMap
> + );*/
> +
> + if (EFI_ERROR (Status) || (Bytes != TableSize)) {
> + //
> + // Map error or unable to map the whole RFis buffer into a contiguous
> + // region.
> + //
> +/* DevIo->FreeBuffer (
> + DevIo,
> + EFI_SIZE_TO_PAGES (TableSize),
> + (EFI_PHYSICAL_ADDRESS)Trb->DmaDesc
> + );*/
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + if ((UINT64)(UINTN)Trb->DmaDescPhy > 0x100000000ul) {
> + //
> + // The DMA doesn't support 64bit addressing.
> + //
> + DmaUnmap (Trb->DmaMap);
> +/* DevIo->Unmap (
> + DevIo,
> + Trb->DmaMap
> + );*/
> + return EFI_DEVICE_ERROR;
> + }
> +
> + if (DataLen < DW_MMC_BLOCK_SIZE) {
> + BlkSize = DataLen;
> + BytCnt = DataLen;
> + Remaining = DataLen;
> + } else {
> + BlkSize = DW_MMC_BLOCK_SIZE;
> + BytCnt = DW_MMC_BLOCK_SIZE * Blocks;
> + Remaining = DW_MMC_BLOCK_SIZE * Blocks;
> + }
> +
> + MmioWrite32 (DevBase + DW_MMC_BLKSIZ, BlkSize);
> + MmioWrite32 (DevBase + DW_MMC_BYTCNT, BytCnt);
> + DmaDesc = Trb->DmaDesc;
> + for (Index = 0; Index < Entries; Index++, DmaDesc++) {
> + DmaDesc->Des0 = DW_MMC_IDMAC_DES0_OWN | DW_MMC_IDMAC_DES0_CH |
> + DW_MMC_IDMAC_DES0_DIC;
> + DmaDesc->Des1 = DW_MMC_IDMAC_DES1_BS1 (DWMMC_DMA_BUF_SIZE);
> + //
> + // Buffer Address
> + //
> + DmaDesc->Des2 = (UINT32)((UINTN)Trb->DataPhy +
> + (DWMMC_DMA_BUF_SIZE * Index));
> + //
> + // Next Descriptor Address
> + //
> + DmaDesc->Des3 = (UINT32)((UINTN)Trb->DmaDescPhy +
> + sizeof (DW_MMC_HC_DMA_DESC_LINE) * (Index + 1));
> + Remaining = Remaining - DWMMC_DMA_BUF_SIZE;
> + }
> + //
> + // First Descriptor
> + //
> + Trb->DmaDesc[0].Des0 |= DW_MMC_IDMAC_DES0_FS;
> + //
> + // Last Descriptor
> + //
> + Trb->DmaDesc[Entries - 1].Des0 &= ~(DW_MMC_IDMAC_DES0_CH |
> + DW_MMC_IDMAC_DES0_DIC);
> + Trb->DmaDesc[Entries - 1].Des0 |= DW_MMC_IDMAC_DES0_OWN |
> + DW_MMC_IDMAC_DES0_LD;
> + Trb->DmaDesc[Entries - 1].Des1 = DW_MMC_IDMAC_DES1_BS1 (Remaining +
> + DWMMC_DMA_BUF_SIZE);
> + //
> + // Set the next field of the Last Descriptor
> + //
> + Trb->DmaDesc[Entries - 1].Des3 = 0;
> + DmaDescPhy = (UINT32)Trb->DmaDescPhy;
> +
> + MmioWrite32 (DevBase + DW_MMC_DBADDR, DmaDescPhy);
> +
> + ArmDataSynchronizationBarrier ();
> + ArmInstructionSynchronizationBarrier ();
> + //
> + // Clear interrupts
> + //
> + Idsts = ~0;
> + MmioWrite32 (DevBase + DW_MMC_IDSTS, Idsts);
> +
> + return Status;
> +}
> +
> +EFI_STATUS
> +TransferFifo (
> + IN DW_MMC_HC_TRB *Trb
> + )
> +{
> + UINTN DevBase;
> + UINT32 Data;
> + UINT32 Received;
> + UINT32 Count;
> + UINT32 Intsts;
> + UINT32 Sts;
> + UINT32 FifoCount;
> + UINT32 Index; /* count with bytes */
> + UINT32 Ascending;
> + UINT32 Descending;
> +
> + DevBase = Trb->Private->DevBase;
> + Received = 0;
> + Count = 0;
> + Index = 0;
> + Ascending = 0;
> + Descending = ((Trb->DataLen + 3) & ~3) - 4;
> + do {
> + Intsts = MmioRead32 (DevBase + DW_MMC_RINTSTS);
> +
> + if (Trb->DataLen && (Intsts & DW_MMC_INT_TXDR) && !Trb->Read) {
> + Sts = MmioRead32 (DevBase + DW_MMC_STATUS);
> +
> + while (!(DW_MMC_STS_FIFO_FULL(Sts))
> + && (Received < Trb->DataLen)
> + && (Intsts & DW_MMC_INT_TXDR)) {
> + if (Trb->UseBE) {
> + Data = SwapBytes32 (*(UINT32 *)((UINTN)Trb->Data + Descending));
> + Descending = Descending - 4;
> + } else {
> + Data = *(UINT32 *)((UINTN)Trb->Data + Ascending);
> + Ascending += 4;
> + }
> + Index += 4;
> + Received += 4;
> +
> + MmioWrite32 (DevBase + DW_MMC_FIFO_START, Data);
> +
> + Intsts = DW_MMC_INT_TXDR;
> + MmioWrite32 (DevBase + DW_MMC_RINTSTS, Intsts);
> +
> + Intsts = MmioRead32 (DevBase + DW_MMC_RINTSTS);
> + Sts = MmioRead32 (DevBase + DW_MMC_STATUS);
> + }
> + continue;
> + }
> +
> + if (Trb->DataLen && ((Intsts & DW_MMC_INT_RXDR) ||
> + (Intsts & DW_MMC_INT_DTO)) && Trb->Read) {
> + Sts = MmioRead32 (DevBase + DW_MMC_STATUS);
> + //
> + // Convert to bytes
> + //
> + FifoCount = GET_STS_FIFO_COUNT (Sts) << 2;
> + if ((FifoCount == 0) && (Received < Trb->DataLen)) {
> + continue;
> + }
> + Index = 0;
> + Count = (MIN (FifoCount, Trb->DataLen) + 3) & ~3;
> + while (Index < Count) {
> + Data = MmioRead32 (DevBase + DW_MMC_FIFO_START);
> +
> + if (Trb->UseBE) {
> + *(UINT32 *)((UINTN)Trb->Data + Descending) = SwapBytes32 (Data);
> + Descending = Descending - 4;
> + } else {
> + *(UINT32 *)((UINTN)Trb->Data + Ascending) = Data;
> + Ascending += 4;
> + }
> + Index += 4;
> + Received += 4;
> + } /* while */
> + } /* if */
> + } while (((Intsts & DW_MMC_INT_CMD_DONE) == 0) || (Received < Trb->DataLen));
> + //
> + // Clear RINTSTS
> + //
> + Intsts = ~0;
> + MmioWrite32 (DevBase + DW_MMC_RINTSTS, Intsts);
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Create a new TRB for the SD/MMC cmd request.
> +
> + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
> + @param[in] Slot The slot number of the SD card to send the command
> + to.
> + @param[in] Packet A pointer to the SD command data structure.
> + @param[in] Event If Event is NULL, blocking I/O is performed. If
> + Event is not NULL, then nonblocking I/O is
> + performed, and Event will be signaled when the
> + Packet completes.
> +
> + @return Created Trb or NULL.
> +
> +**/
> +DW_MMC_HC_TRB *
> +DwMmcCreateTrb (
> + IN DW_MMC_HC_PRIVATE_DATA *Private,
> + IN UINT8 Slot,
> + IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
> + IN EFI_EVENT Event
> + )
> +{
> + DW_MMC_HC_TRB *Trb;
> + EFI_STATUS Status;
> + EFI_TPL OldTpl;
> + EFI_IO_OPERATION_TYPE Flag;
> + UINTN MapLength;
> +
> + Trb = AllocateZeroPool (sizeof (DW_MMC_HC_TRB));
> + if (Trb == NULL) {
> + return NULL;
> + }
> +
> + Trb->Signature = DW_MMC_HC_TRB_SIG;
> + Trb->Slot = Slot;
> + Trb->BlockSize = 0x200;
> + Trb->Packet = Packet;
> + Trb->Event = Event;
> + Trb->Started = FALSE;
> + Trb->Timeout = Packet->Timeout;
> + Trb->Private = Private;
> +
> + if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {
> + Trb->Data = Packet->InDataBuffer;
> + Trb->DataLen = Packet->InTransferLength;
> + Trb->Read = TRUE;
> + ZeroMem (Trb->Data, Trb->DataLen);
> + } else if (Packet->OutTransferLength && (Packet->OutDataBuffer != NULL)) {
> + Trb->Data = Packet->OutDataBuffer;
> + Trb->DataLen = Packet->OutTransferLength;
> + Trb->Read = FALSE;
> + } else if (!Packet->InTransferLength && !Packet->OutTransferLength) {
> + Trb->Data = NULL;
> + Trb->DataLen = 0;
> + } else {
> + goto Error;
> + }
> +
> + if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) &&
> + (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) ||
> + ((Private->Slot[Trb->Slot].CardType == SdCardType) &&
> + (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) {
> + Trb->Mode = SdMmcPioMode;
> + } else {
> + if (Trb->Read) {
> + Flag = EfiBusMasterWrite;
> + } else {
> + Flag = EfiBusMasterRead;
> + }
> +
> + if (Private->Slot[Trb->Slot].CardType == SdCardType) {
> + Trb->UseFifo = TRUE;
> + } else {
> + Trb->UseFifo = FALSE;
> + if (Trb->DataLen) {
> + MapLength = Trb->DataLen;
> + Status = DmaMap (Flag, Trb->Data, &MapLength, &Trb->DataPhy, &Trb->DataMap);
> +/* Status = DevIo->Map (
> + DevIo,
> + Flag,
> + Trb->Data,
> + &MapLength,
> + &Trb->DataPhy,
> + &Trb->DataMap
> + );*/
> + if (EFI_ERROR (Status) || (Trb->DataLen != MapLength)) {
> + Status = EFI_BAD_BUFFER_SIZE;
> + goto Error;
> + }
> +
> + Status = BuildDmaDescTable (Trb);
> + if (EFI_ERROR (Status)) {
> + DmaUnmap(Trb->DataMap);
> + goto Error;
> + }
> + Status = DwMmcHcStartDma (Private, Trb);
> + if (EFI_ERROR (Status)) {
> + DmaUnmap(Trb->DataMap);
> + goto Error;
> + }
> + }
> + }
> + } /* TuningBlock */
> +
> + if (Event != NULL) {
> + OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> + InsertTailList (&Private->Queue, &Trb->TrbList);
> + gBS->RestoreTPL (OldTpl);
> + }
> +
> + return Trb;
> +
> +Error:
> + return NULL;
> +}
> +
> +/**
> + Free the resource used by the TRB.
> +
> + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> +
> +**/
> +VOID
> +DwMmcFreeTrb (
> + IN DW_MMC_HC_TRB *Trb
> + )
> +{
> + if (Trb->DmaMap != NULL) {
> + DmaUnmap (Trb->DmaMap);
> + }
> + if (Trb->DataMap != NULL) {
> + DmaUnmap (Trb->DataMap);
> + }
> + FreePool (Trb);
> +}
> +
> +/**
> + Check if the env is ready for execute specified TRB.
> +
> + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
> + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> +
> + @retval EFI_SUCCESS The env is ready for TRB execution.
> + @retval EFI_NOT_READY The env is not ready for TRB execution.
> + @retval Others Some erros happen.
> +
> +**/
> +EFI_STATUS
> +DwMmcCheckTrbEnv (
> + IN DW_MMC_HC_PRIVATE_DATA *Private,
> + IN DW_MMC_HC_TRB *Trb
> + )
> +{
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Wait for the env to be ready for execute specified TRB.
> +
> + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
> + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> +
> + @retval EFI_SUCCESS The env is ready for TRB execution.
> + @retval EFI_TIMEOUT The env is not ready for TRB execution in time.
> + @retval Others Some erros happen.
> +
> +**/
> +EFI_STATUS
> +DwMmcWaitTrbEnv (
> + IN DW_MMC_HC_PRIVATE_DATA *Private,
> + IN DW_MMC_HC_TRB *Trb
> + )
> +{
> + EFI_STATUS Status;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
> + UINT64 Timeout;
> + BOOLEAN InfiniteWait;
> +
> + //
> + // Wait Command Complete Interrupt Status bit in Normal Interrupt Status
> + // Register
> + //
> + Packet = Trb->Packet;
> + Timeout = Packet->Timeout;
> + if (Timeout == 0) {
> + InfiniteWait = TRUE;
> + } else {
> + InfiniteWait = FALSE;
> + }
> +
> + while (InfiniteWait || (Timeout > 0)) {
> + //
> + // Check Trb execution result by reading Normal Interrupt Status register.
> + //
> + Status = DwMmcCheckTrbEnv (Private, Trb);
> + if (Status != EFI_NOT_READY) {
> + return Status;
> + }
> + //
> + // Stall for 1 microsecond.
> + //
> + gBS->Stall (1);
> +
> + Timeout--;
> + }
> +
> + return EFI_TIMEOUT;
> +}
> +
> +EFI_STATUS
> +DwEmmcExecTrb (
> + IN DW_MMC_HC_PRIVATE_DATA *Private,
> + IN DW_MMC_HC_TRB *Trb
> + )
> +{
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
> + UINTN DevBase;
> + UINT32 Cmd;
> + UINT32 MmcStatus;
> + UINT32 IntStatus;
> + UINT32 Argument;
> + UINT32 ErrMask;
> + UINT32 Timeout;
> +
> + Packet = Trb->Packet;
> + DevBase = Trb->Private->DevBase;
> +
> + ArmDataSynchronizationBarrier ();
> + ArmInstructionSynchronizationBarrier ();
> + //
> + // Wait until MMC is idle
> + //
> + do {
> + MmcStatus = MmioRead32 (DevBase + DW_MMC_STATUS);
> + } while (MmcStatus & DW_MMC_STS_DATA_BUSY);
> +
> + IntStatus = ~0;
> + MmioWrite32 (DevBase + DW_MMC_RINTSTS, IntStatus);
> + Cmd = CMD_INDEX (Packet->SdMmcCmdBlk->CommandIndex);
> + if ((Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAc) ||
> + (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc)) {
> + switch (Packet->SdMmcCmdBlk->CommandIndex) {
> + case EMMC_SET_RELATIVE_ADDR:
> + Cmd |= BIT_CMD_SEND_INIT;
> + break;
> + case EMMC_SEND_STATUS:
> + Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE;
> + break;
> + case EMMC_STOP_TRANSMISSION:
> + Cmd |= BIT_CMD_STOP_ABORT_CMD;
> + break;
> + }
> + if (Packet->InTransferLength) {
> + Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_DATA_EXPECTED |
> + BIT_CMD_READ;
> + } else if (Packet->OutTransferLength) {
> + Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_DATA_EXPECTED |
> + BIT_CMD_WRITE;
> + }
> + Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;
> + } else {
> + switch (Packet->SdMmcCmdBlk->CommandIndex) {
> + case EMMC_GO_IDLE_STATE:
> + Cmd |= BIT_CMD_SEND_INIT;
> + break;
> + case EMMC_SEND_OP_COND:
> + Cmd |= BIT_CMD_RESPONSE_EXPECT;
> + break;
> + case EMMC_ALL_SEND_CID:
> + Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_LONG_RESPONSE |
> + BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_SEND_INIT;
> + break;
> + }
> + }
> + switch (Packet->SdMmcCmdBlk->ResponseType) {
> + case SdMmcResponseTypeR2:
> + Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
> + BIT_CMD_LONG_RESPONSE;
> + break;
> + case SdMmcResponseTypeR3:
> + Cmd |= BIT_CMD_RESPONSE_EXPECT;
> + break;
> + }
> + Cmd |= BIT_CMD_USE_HOLD_REG | BIT_CMD_START;
> +
> + Argument = Packet->SdMmcCmdBlk->CommandArgument;
> + MmioWrite32 (DevBase + DW_MMC_CMDARG, Argument);
> +
> + ArmDataSynchronizationBarrier ();
> + ArmInstructionSynchronizationBarrier ();
> +
> + MmioWrite32 (DevBase + DW_MMC_CMD, Cmd);
> + ArmDataSynchronizationBarrier ();
> + ArmInstructionSynchronizationBarrier ();
> +
> + ErrMask = DW_MMC_INT_EBE | DW_MMC_INT_HLE | DW_MMC_INT_RTO |
> + DW_MMC_INT_RCRC | DW_MMC_INT_RE;
> + ErrMask |= DW_MMC_INT_DCRC | DW_MMC_INT_DRT | DW_MMC_INT_SBE;
> + do {
> + Timeout = 10000;
> + if (--Timeout == 0) {
> + break;
> + }
> + IntStatus = MmioRead32 (DevBase + DW_MMC_RINTSTS);
> + if (IntStatus & ErrMask) {
> + return EFI_DEVICE_ERROR;
> + }
> + if (Trb->DataLen && ((IntStatus & DW_MMC_INT_DTO) == 0)) {
> + //
> + // Transfer Not Done
> + //
> + MicroSecondDelay (10);
> + continue;
> + }
> + MicroSecondDelay (10);
> + } while (!(IntStatus & DW_MMC_INT_CMD_DONE));
> + switch (Packet->SdMmcCmdBlk->ResponseType) {
> + case SdMmcResponseTypeR1:
> + case SdMmcResponseTypeR1b:
> + case SdMmcResponseTypeR3:
> + case SdMmcResponseTypeR4:
> + case SdMmcResponseTypeR5:
> + Packet->SdMmcStatusBlk->Resp0 = MmioRead32 (DevBase + DW_MMC_RESP0);
> + break;
> + case SdMmcResponseTypeR2:
> + Packet->SdMmcStatusBlk->Resp0 = MmioRead32 (DevBase + DW_MMC_RESP0);
> + Packet->SdMmcStatusBlk->Resp1 = MmioRead32 (DevBase + DW_MMC_RESP1);
> + Packet->SdMmcStatusBlk->Resp2 = MmioRead32 (DevBase + DW_MMC_RESP2);
> + Packet->SdMmcStatusBlk->Resp3 = MmioRead32 (DevBase + DW_MMC_RESP3);
> + break;
> + }
> +
> + //
> + // The workaround on EMMC_SEND_CSD is used to be compatible with SDHC.
> + //
> + if (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_CSD) {
> + {
> + UINT32 Buf[4];
> + ZeroMem (Buf, sizeof (Buf));
> + CopyMem (
> + (UINT8 *)Buf,
> + (UINT8 *)&Packet->SdMmcStatusBlk->Resp0 + 1,
> + sizeof (Buf) - 1
> + );
> + CopyMem (
> + (UINT8 *)&Packet->SdMmcStatusBlk->Resp0,
> + (UINT8 *)Buf,
> + sizeof (Buf) - 1
> + );
> + }
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +DwSdExecTrb (
> + IN DW_MMC_HC_PRIVATE_DATA *Private,
> + IN DW_MMC_HC_TRB *Trb
> + )
> +{
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
> + UINTN DevBase;
> + UINT32 Cmd;
> + UINT32 MmcStatus;
> + UINT32 IntStatus;
> + UINT32 Argument;
> + UINT32 ErrMask;
> + UINT32 Timeout;
> + UINT32 Idsts;
> + UINT32 BytCnt;
> + UINT32 BlkSize;
> + EFI_STATUS Status;
> +
> + Packet = Trb->Packet;
> + DevBase = Trb->Private->DevBase;
> +
> + ArmDataSynchronizationBarrier ();
> + ArmInstructionSynchronizationBarrier ();
> + //
> + // Wait until MMC is idle
> + //
> + do {
> + MmcStatus = MmioRead32 (DevBase + DW_MMC_STATUS);
> + } while (MmcStatus & DW_MMC_STS_DATA_BUSY);
> +
> + IntStatus = ~0;
> + MmioWrite32 (DevBase + DW_MMC_RINTSTS, IntStatus);
> + Cmd = CMD_INDEX (Packet->SdMmcCmdBlk->CommandIndex);
> + if ((Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAc) ||
> + (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc)) {
> + switch (Packet->SdMmcCmdBlk->CommandIndex) {
> + case SD_SET_RELATIVE_ADDR:
> + Cmd |= BIT_CMD_SEND_INIT;
> + break;
> + case SD_STOP_TRANSMISSION:
> + Cmd |= BIT_CMD_STOP_ABORT_CMD;
> + break;
> + case SD_SEND_SCR:
> + Trb->UseBE = TRUE;
> + break;
> + }
> + if (Packet->InTransferLength) {
> + Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_DATA_EXPECTED |
> + BIT_CMD_READ;
> + } else if (Packet->OutTransferLength) {
> + Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_DATA_EXPECTED |
> + BIT_CMD_WRITE;
> + }
> + Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
> + BIT_CMD_SEND_AUTO_STOP;
> + } else {
> + switch (Packet->SdMmcCmdBlk->CommandIndex) {
> + case SD_GO_IDLE_STATE:
> + Cmd |= BIT_CMD_SEND_INIT;
> + break;
> + }
> + }
> + switch (Packet->SdMmcCmdBlk->ResponseType) {
> + case SdMmcResponseTypeR2:
> + Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
> + BIT_CMD_LONG_RESPONSE;
> + break;
> + case SdMmcResponseTypeR3:
> + Cmd |= BIT_CMD_RESPONSE_EXPECT;
> + break;
> + case SdMmcResponseTypeR1b:
> + case SdMmcResponseTypeR4:
> + case SdMmcResponseTypeR6:
> + case SdMmcResponseTypeR7:
> + Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;
> + break;
> + }
> + Cmd |= BIT_CMD_USE_HOLD_REG | BIT_CMD_START;
> +
> + if (Trb->UseFifo == TRUE) {
> + BytCnt = Trb->Read ? Packet->InTransferLength : Packet->OutTransferLength;
> + MmioWrite32 (DevBase + DW_MMC_BYTCNT, BytCnt);
> + if (Trb->Read) {
> + if (Packet->InTransferLength > DW_MMC_BLOCK_SIZE) {
> + BlkSize = DW_MMC_BLOCK_SIZE;
> + } else {
> + BlkSize = Packet->InTransferLength;
> + }
> + }
> + else {
> + if (Packet->OutTransferLength > DW_MMC_BLOCK_SIZE) {
> + BlkSize = DW_MMC_BLOCK_SIZE;
> + } else {
> + BlkSize = Packet->OutTransferLength;
> + }
> + }
> +
> + MmioWrite32 (DevBase + DW_MMC_BLKSIZ, BlkSize);
> + }
> +
> + Argument = Packet->SdMmcCmdBlk->CommandArgument;
> + MmioWrite32 (DevBase + DW_MMC_CMDARG, Argument);
> + ArmDataSynchronizationBarrier ();
> + ArmInstructionSynchronizationBarrier ();
> + MmioWrite32 (DevBase + DW_MMC_CMD, Cmd);
> + ArmDataSynchronizationBarrier ();
> + ArmInstructionSynchronizationBarrier ();
> +
> + ErrMask = DW_MMC_INT_EBE | DW_MMC_INT_HLE | DW_MMC_INT_RTO |
> + DW_MMC_INT_RCRC | DW_MMC_INT_RE;
> + ErrMask |= DW_MMC_INT_DRT | DW_MMC_INT_SBE;
> + if (Packet->InTransferLength || Packet->OutTransferLength) {
> + ErrMask |= DW_MMC_INT_DCRC;
> + }
> + if (Trb->UseFifo == TRUE) {
> + Status = TransferFifo (Trb);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + } else {
> + Timeout = 10000;
> + do {
> + if (--Timeout == 0) {
> + break;
> + }
> + IntStatus = MmioRead32 (DevBase + DW_MMC_RINTSTS);
> + if (IntStatus & ErrMask) {
> + return EFI_DEVICE_ERROR;
> + }
> + if (Trb->DataLen && ((IntStatus & DW_MMC_INT_DTO) == 0)) {
> + //
> + // Transfer not Done
> + //
> + MicroSecondDelay (10);
> + continue;
> + }
> + MicroSecondDelay (10);
> + } while (!(IntStatus & DW_MMC_INT_CMD_DONE));
> + if (Packet->InTransferLength) {
> + do {
> + Idsts = MmioRead32 (DevBase + DW_MMC_IDSTS);
> + } while ((Idsts & DW_MMC_IDSTS_RI) == 0);
> + Status = DwMmcHcStopDma (Private, Trb);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + } else if (Packet->OutTransferLength) {
> + do {
> + Idsts = MmioRead32 (DevBase + DW_MMC_IDSTS);
> + } while ((Idsts & DW_MMC_IDSTS_TI) == 0);
> + Status = DwMmcHcStopDma (Private, Trb);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + } /* Packet->InTransferLength */
> + } /* UseFifo */
> + switch (Packet->SdMmcCmdBlk->ResponseType) {
> + case SdMmcResponseTypeR1:
> + case SdMmcResponseTypeR1b:
> + case SdMmcResponseTypeR3:
> + case SdMmcResponseTypeR4:
> + case SdMmcResponseTypeR5:
> + case SdMmcResponseTypeR6:
> + case SdMmcResponseTypeR7:
> + Packet->SdMmcStatusBlk->Resp0 = MmioRead32 (DevBase + DW_MMC_RESP0);
> + break;
> + case SdMmcResponseTypeR2:
> + Packet->SdMmcStatusBlk->Resp0 = MmioRead32 (DevBase + DW_MMC_RESP0);
> + Packet->SdMmcStatusBlk->Resp1 = MmioRead32 (DevBase + DW_MMC_RESP1);
> + Packet->SdMmcStatusBlk->Resp2 = MmioRead32 (DevBase + DW_MMC_RESP2);
> + Packet->SdMmcStatusBlk->Resp3 = MmioRead32 (DevBase + DW_MMC_RESP3);
> + break;
> + }
> +
> + //
> + // The workaround on SD_SEND_CSD is used to be compatible with SDHC.
> + //
> + if (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_CSD) {
> + {
> + UINT32 Buf[4];
> + ZeroMem (Buf, sizeof (Buf));
> + CopyMem (
> + (UINT8 *)Buf,
> + (UINT8 *)&Packet->SdMmcStatusBlk->Resp0 + 1,
> + sizeof (Buf) - 1
> + );
> + CopyMem (
> + (UINT8 *)&Packet->SdMmcStatusBlk->Resp0,
> + (UINT8 *)Buf,
> + sizeof (Buf) - 1
> + );
> + }
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Execute the specified TRB.
> +
> + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
> + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> +
> + @retval EFI_SUCCESS The TRB is sent to host controller successfully.
> + @retval Others Some erros happen when sending this request to the
> + host controller.
> +
> +**/
> +EFI_STATUS
> +DwMmcExecTrb (
> + IN DW_MMC_HC_PRIVATE_DATA *Private,
> + IN DW_MMC_HC_TRB *Trb
> + )
> +{
> + EFI_STATUS Status = EFI_SUCCESS;
> + UINT32 Slot;
> +
> + Slot = Trb->Slot;
> + if (Private->Slot[Slot].CardType == EmmcCardType) {
> + Status = DwEmmcExecTrb (Private, Trb);
> + } else if (Private->Slot[Slot].CardType == SdCardType) {
> + Status = DwSdExecTrb (Private, Trb);
> + } else {
> + ASSERT (0);
> + }
> + return Status;
> +}
> +
> +/**
> + Check the TRB execution result.
> +
> + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
> + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> +
> + @retval EFI_SUCCESS The TRB is executed successfully.
> + @retval EFI_NOT_READY The TRB is not completed for execution.
> + @retval Others Some erros happen when executing this request.
> +
> +**/
> +EFI_STATUS
> +DwMmcCheckTrbResult (
> + IN DW_MMC_HC_PRIVATE_DATA *Private,
> + IN DW_MMC_HC_TRB *Trb
> + )
> +{
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
> + UINT32 Idsts;
> + UINTN DevBase;
> +
> + DevBase = Private->DevBase;
> + Packet = Trb->Packet;
> + if (Trb->UseFifo == TRUE) {
> + return EFI_SUCCESS;
> + }
> + if (Packet->InTransferLength) {
> + do {
> + Idsts = MmioRead32 (DevBase + DW_MMC_IDSTS);
> + } while ((Idsts & BIT1) == 0);
> + } else if (Packet->OutTransferLength) {
> + do {
> + Idsts = MmioRead32 (DevBase + DW_MMC_IDSTS);
> + } while ((Idsts & BIT0) == 0);
> + } else {
> + return EFI_SUCCESS;
> + }
> + Idsts = ~0;
> + MmioWrite32 (DevBase + DW_MMC_IDSTS, Idsts);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Wait for the TRB execution result.
> +
> + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
> + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> +
> + @retval EFI_SUCCESS The TRB is executed successfully.
> + @retval Others Some erros happen when executing this request.
> +
> +**/
> +EFI_STATUS
> +DwMmcWaitTrbResult (
> + IN DW_MMC_HC_PRIVATE_DATA *Private,
> + IN DW_MMC_HC_TRB *Trb
> + )
> +{
> + EFI_STATUS Status;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
> + UINT64 Timeout;
> + BOOLEAN InfiniteWait;
> +
> + Packet = Trb->Packet;
> + //
> + // Wait Command Complete Interrupt Status bit in Normal Interrupt Status
> + // Register
> + //
> + Timeout = Packet->Timeout;
> + if (Timeout == 0) {
> + InfiniteWait = TRUE;
> + } else {
> + InfiniteWait = FALSE;
> + }
> +
> + while (InfiniteWait || (Timeout > 0)) {
> + //
> + // Check Trb execution result by reading Normal Interrupt Status register.
> + //
> + Status = DwMmcCheckTrbResult (Private, Trb);
> + if (Status != EFI_NOT_READY) {
> + return Status;
> + }
> + //
> + // Stall for 1 microsecond.
> + //
> + gBS->Stall (1);
> +
> + Timeout--;
> + }
> +
> + return EFI_TIMEOUT;
> +}
> diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c b/EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
> new file mode 100644
> index 000000000000..b7a8688c4d2e
> --- /dev/null
> +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
> @@ -0,0 +1,1042 @@
> +/** @file
> + This file provides some helper functions which are specific for EMMC device.
> +
> + Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
> + Copyright (c) 2018, Linaro. 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 <IndustryStandard/Emmc.h>
> +
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +
> +#include "DwMmcHcDxe.h"
> +
> +#define EMMC_GET_STATE(x) (((x) >> 9) & 0xf)
> +#define EMMC_STATE_IDLE 0
> +#define EMMC_STATE_READY 1
> +#define EMMC_STATE_IDENT 2
> +#define EMMC_STATE_STBY 3
> +#define EMMC_STATE_TRAN 4
> +#define EMMC_STATE_DATA 5
> +#define EMMC_STATE_RCV 6
> +#define EMMC_STATE_PRG 7
> +#define EMMC_STATE_DIS 8
> +#define EMMC_STATE_BTST 9
> +#define EMMC_STATE_SLP 10
> +
> +#define EMMC_CMD1_CAPACITY_LESS_THAN_2GB 0x00FF8080 // Capacity <= 2GB, byte addressing used
> +#define EMMC_CMD1_CAPACITY_GREATER_THAN_2GB 0x40FF8080 // Capacity > 2GB, 512-byte sector addressing used
> +
> +/**
> + Send command GO_IDLE_STATE (CMD0 with argument of 0x00000000) to the device to
> + make it go to Idle State.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Slot The slot number of the SD card to send the command
> + to.
> +
> + @retval EFI_SUCCESS The EMMC device is reset correctly.
> + @retval Others The device reset fails.
> +
> +**/
> +EFI_STATUS
> +EmmcReset (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc;
> + SdMmcCmdBlk.ResponseType = 0;
> + SdMmcCmdBlk.CommandArgument = 0;
> +
> + gBS->Stall (1000);
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> +
> + return Status;
> +}
> +
> +/**
> + Send command SEND_OP_COND to the EMMC device to get the data of the OCR
> + register.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in, out] Argument On input, the argument of SEND_OP_COND is to send
> + to the device.
> + On output, the argument is the value of OCR
> + register.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +EmmcGetOcr (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN OUT UINT32 *Argument
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;
> + SdMmcCmdBlk.CommandArgument = *Argument;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> + if (!EFI_ERROR (Status)) {
> + //
> + // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
> + //
> + *Argument = SdMmcStatusBlk.Resp0;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Broadcast command ALL_SEND_CID to the bus to ask all the EMMC devices to send
> + the data of their CID registers.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +EmmcGetAllCid (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
> + SdMmcCmdBlk.CommandArgument = 0;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> +
> + return Status;
> +}
> +
> +/**
> + Send command SET_RELATIVE_ADDR to the EMMC device to assign a Relative device
> + Address (RCA).
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Rca The relative device address to be assigned.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +EmmcSetRca (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT16 Rca
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> +
> + return Status;
> +}
> +
> +/**
> + Send command SEND_CSD to the EMMC device to get the data of the CSD register.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Rca The relative device address of selected device.
> + @param[out] Csd The buffer to store the content of the CSD register.
> + Note the caller should ignore the lowest byte of
> + this buffer as the content of this byte is
> + meaningless even if the operation succeeds.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +EmmcGetCsd (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT16 Rca,
> + OUT EMMC_CSD *Csd
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
> + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> + if (!EFI_ERROR (Status)) {
> + //
> + // Copy 128bit data for CSD structure.
> + //
> + CopyMem ((VOID *)Csd + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Send command SELECT_DESELECT_CARD to the EMMC device to select/deselect it.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Rca The relative device address of selected device.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +EmmcSelect (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT16 Rca
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> +
> + return Status;
> +}
> +
> +/**
> + Send command SEND_EXT_CSD to the EMMC device to get the data of the EXT_CSD
> + register.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[out] ExtCsd The buffer to store the content of the EXT_CSD
> + register.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +EmmcGetExtCsd (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + OUT EMMC_EXT_CSD *ExtCsd
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> + SdMmcCmdBlk.CommandArgument = 0x00000000;
> +
> + Packet.InDataBuffer = ExtCsd;
> + Packet.InTransferLength = sizeof (EMMC_EXT_CSD);
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> + return Status;
> +}
> +
> +/**
> + Send command SWITCH to the EMMC device to switch the mode of operation of the
> + selected Device or modifies the EXT_CSD registers.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Access The access mode of SWTICH command.
> + @param[in] Index The offset of the field to be access.
> + @param[in] Value The value to be set to the specified field of
> + EXT_CSD register.
> + @param[in] CmdSet The value of CmdSet field of EXT_CSD register.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +EmmcSwitch (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT8 Access,
> + IN UINT8 Index,
> + IN UINT8 Value,
> + IN UINT8 CmdSet
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = EMMC_SWITCH;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
> + SdMmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | \
> + (Value << 8) | CmdSet;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> +
> + return Status;
> +}
> +
> +/**
> + Send command SEND_STATUS to the addressed EMMC device to get its status
> + register.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Rca The relative device address of addressed device.
> + @param[out] DevStatus The returned device status.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +EmmcSendStatus (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT16 Rca,
> + OUT UINT32 *DevStatus
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> + if (!EFI_ERROR (Status)) {
> + *DevStatus = SdMmcStatusBlk.Resp0;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Send command SEND_TUNING_BLOCK to the EMMC device for HS200 optimal sampling
> + point detection.
> +
> + It may be sent up to 40 times until the host finishes the tuning procedure.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] BusWidth The bus width to work.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +EmmcSendTuningBlk (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT8 BusWidth
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> + UINT8 TuningBlock[128];
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> + SdMmcCmdBlk.CommandArgument = 0;
> +
> + Packet.InDataBuffer = TuningBlock;
> + if (BusWidth == 8) {
> + Packet.InTransferLength = sizeof (TuningBlock);
> + } else {
> + Packet.InTransferLength = 64;
> + }
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> +
> + return Status;
> +}
> +
> +/**
> + Tunning the clock to get HS200 optimal sampling point.
> +
> + Command SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes
> + the tuning procedure.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8.
> +
> + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] BusWidth The bus width to work.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +EmmcTuningClkForHs200 (
> + IN UINTN DevBase,
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT8 BusWidth
> + )
> +{
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Switch the bus width to specified width.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9.
> +
> + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Rca The relative device address to be assigned.
> + @param[in] IsDdr If TRUE, use dual data rate data simpling method.
> + Otherwise use single data rate data simpling method.
> + @param[in] BusWidth The bus width to be set, it could be 4 or 8.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +EmmcSwitchBusWidth (
> + IN UINTN DevBase,
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT16 Rca,
> + IN BOOLEAN IsDdr,
> + IN UINT8 BusWidth
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 Access;
> + UINT8 Index;
> + UINT8 Value;
> + UINT8 CmdSet;
> + UINT32 DevStatus;
> +
> + //
> + // Write Byte, the Value field is written into the byte pointed by Index.
> + //
> + Access = 0x03;
> + Index = OFFSET_OF (EMMC_EXT_CSD, BusWidth);
> + if (BusWidth == 1) {
> + Value = 0;
> + } else {
> + if (BusWidth == 4) {
> + Value = 1;
> + } else if (BusWidth == 8) {
> + Value = 2;
> + } else {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (IsDdr) {
> + Value += 4;
> + }
> + }
> +
> + CmdSet = 0;
> + Status = EmmcSwitch (PassThru, Access, Index, Value, CmdSet);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "EmmcSwitchBusWidth: Switch to bus width %d fails with %r\n",
> + BusWidth,
> + Status
> + ));
> + return Status;
> + }
> +
> + do {
> + Status = EmmcSendStatus (PassThru, Rca, &DevStatus);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "EmmcSwitchBusWidth: Send status fails with %r\n",
> + Status
> + ));
> + return Status;
> + }
> + //
> + // Check the switch operation is really successful or not.
> + //
> + } while ((DevStatus & 0xf) == EMMC_STATE_PRG);
> +
> + Status = DwMmcHcSetBusWidth (DevBase, IsDdr, BusWidth);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Switch the clock frequency to the specified value.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.
> +
> + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Rca The relative device address to be assigned.
> + @param[in] HsTiming The value to be written to HS_TIMING field of
> + EXT_CSD register.
> + @param[in] ClockFreq The max clock frequency to be set, the unit is MHz.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +EmmcSwitchClockFreq (
> + IN UINTN DevBase,
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT16 Rca,
> + IN UINT8 HsTiming,
> + IN UINT32 ClockFreq
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 Access;
> + UINT8 Index;
> + UINT8 Value;
> + UINT8 CmdSet;
> + UINT32 DevStatus;
> + DW_MMC_HC_PRIVATE_DATA *Private;
> +
> + Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru);
> + //
> + // Write Byte, the Value field is written into the byte pointed by Index.
> + //
> + Access = 0x03;
> + Index = OFFSET_OF (EMMC_EXT_CSD, HsTiming);
> + Value = HsTiming;
> + CmdSet = 0;
> +
> + Status = EmmcSwitch (PassThru, Access, Index, Value, CmdSet);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "EmmcSwitchClockFreq: Switch to hstiming %d fails with %r\n",
> + HsTiming,
> + Status
> + ));
> + return Status;
> + }
> +
> + Status = EmmcSendStatus (PassThru, Rca, &DevStatus);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "EmmcSwitchClockFreq: Send status fails with %r\n",
> + Status
> + ));
> + return Status;
> + }
> + //
> + // Check the switch operation is really successful or not.
> + //
> + if ((DevStatus & BIT7) != 0) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "EmmcSwitchClockFreq: The switch operation fails as DevStatus 0x%08x\n",
> + DevStatus
> + ));
> + return EFI_DEVICE_ERROR;
> + }
> + //
> + // Convert the clock freq unit from MHz to KHz.
> + //
> + Status = DwMmcHcClockSupply (DevBase, ClockFreq * 1000, Private->Capability[0]);
> +
> + return Status;
> +}
> +
> +/**
> + Switch to the High Speed timing according to request.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8.
> +
> + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Rca The relative device address to be assigned.
> + @param[in] ClockFreq The max clock frequency to be set.
> + @param[in] IsDdr If TRUE, use dual data rate data simpling method.
> + Otherwise use single data rate data simpling method.
> + @param[in] BusWidth The bus width to be set, it could be 4 or 8.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +EmmcSwitchToHighSpeed (
> + IN UINTN DevBase,
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT16 Rca,
> + IN UINT32 ClockFreq,
> + IN BOOLEAN IsDdr,
> + IN UINT8 BusWidth
> + )
> +{
> + EFI_STATUS Status;
> + UINT8 HsTiming;
> +
> + HsTiming = 1;
> + Status = EmmcSwitchClockFreq (DevBase, PassThru, Rca, HsTiming, ClockFreq);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + Status = EmmcSwitchBusWidth (DevBase, PassThru, Rca, IsDdr, BusWidth);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Switch to the HS200 timing according to request.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8.
> +
> + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Rca The relative device address to be assigned.
> + @param[in] ClockFreq The max clock frequency to be set.
> + @param[in] BusWidth The bus width to be set, it could be 4 or 8.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +EmmcSwitchToHS200 (
> + IN UINTN DevBase,
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT16 Rca,
> + IN UINT32 ClockFreq,
> + IN UINT8 BusWidth
> + )
> +{
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Switch the high speed timing according to request.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8.
> +
> + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Rca The relative device address to be assigned.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +EmmcSetBusMode (
> + IN UINTN DevBase,
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT16 Rca
> + )
> +{
> + EFI_STATUS Status;
> + EMMC_CSD Csd;
> + EMMC_EXT_CSD ExtCsd;
> + UINT8 HsTiming;
> + BOOLEAN IsDdr;
> + UINT32 DevStatus;
> + UINT32 ClockFreq;
> + UINT8 BusWidth;
> + DW_MMC_HC_PRIVATE_DATA *Private;
> +
> + Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru);
> + ASSERT (Private->Capability[0].BaseClkFreq != 0);
> +
> + Status = EmmcGetCsd (PassThru, Rca, &Csd);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetCsd fails with %r\n", Status));
> + return Status;
> + }
> +
> + Status = EmmcSelect (PassThru, Rca);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: Select fails with %r\n", Status));
> + return Status;
> + }
> +
> + do {
> + Status = EmmcSendStatus (PassThru, Rca, &DevStatus);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "EmmcSetBusMode: Get Status fails with %r\n",
> + Status
> + ));
> + return Status;
> + }
> + } while (EMMC_GET_STATE (DevStatus) != EMMC_STATE_TRAN);
> +
> + BusWidth = 1;
> + Status = EmmcSwitchBusWidth (DevBase, PassThru, Rca, FALSE, BusWidth);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + BusWidth = Private->Capability[0].BusWidth;
> + //
> + // Get Deivce_Type from EXT_CSD register.
> + //
> + Status = EmmcGetExtCsd (PassThru, &ExtCsd);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetExtCsd fails with %r\n", Status));
> + return Status;
> + }
> +
> + //
> + // Calculate supported bus speed/bus width/clock frequency.
> + //
> + HsTiming = 0;
> + IsDdr = FALSE;
> + ClockFreq = 0;
> + if (((ExtCsd.DeviceType & (BIT4 | BIT5)) != 0) &&
> + (Private->Capability[0].Sdr104 != 0)) {
> + HsTiming = 2;
> + IsDdr = FALSE;
> + ClockFreq = 200;
> + } else if (((ExtCsd.DeviceType & (BIT2 | BIT3)) != 0) &&
> + (Private->Capability[0].Ddr50 != 0)) {
> + HsTiming = 1;
> + IsDdr = TRUE;
> + ClockFreq = 52;
> + } else if (((ExtCsd.DeviceType & BIT1) != 0) &&
> + (Private->Capability[0].HighSpeed != 0)) {
> + HsTiming = 1;
> + IsDdr = FALSE;
> + ClockFreq = 52;
> + } else if (((ExtCsd.DeviceType & BIT0) != 0) &&
> + (Private->Capability[0].HighSpeed != 0)) {
> + HsTiming = 1;
> + IsDdr = FALSE;
> + ClockFreq = 26;
> + }
> +
> + if ((ClockFreq == 0) || (HsTiming == 0)) {
> + //
> + // Continue using default setting.
> + //
> + return EFI_SUCCESS;
> + }
> +
> + DEBUG ((
> + DEBUG_INFO,
> + "EmmcSetBusMode: HsTiming %d ClockFreq %d BusWidth %d Ddr %a\n",
> + HsTiming,
> + ClockFreq,
> + BusWidth,
> + IsDdr ? "TRUE" : "FALSE"
> + ));
> +
> + if (HsTiming == 2) {
> + //
> + // Execute HS200 timing switch procedure
> + //
> + Status = EmmcSwitchToHS200 (DevBase, PassThru, Rca, ClockFreq, BusWidth);
> + } else {
> + //
> + // Execute High Speed timing switch procedure
> + //
> + Status = EmmcSwitchToHighSpeed (
> + DevBase,
> + PassThru,
> + Rca,
> + ClockFreq,
> + IsDdr,
> + BusWidth
> + );
> + }
> +
> + DEBUG ((
> + DEBUG_INFO,
> + "EmmcSetBusMode: Switch to %a %r\n",
> + (HsTiming == 3) ? "HS400" : ((HsTiming == 2) ? "HS200" : "HighSpeed"),
> + Status
> + ));
> +
> + return Status;
> +}
> +
> +/**
> + Execute EMMC device identification procedure.
> +
> + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
> +
> + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
> +
> + @retval EFI_SUCCESS There is a EMMC card.
> + @retval Others There is not a EMMC card.
> +
> +**/
> +EFI_STATUS
> +EmmcIdentification (
> + IN DW_MMC_HC_PRIVATE_DATA *Private
> + )
> +{
> + EFI_STATUS Status;
> + UINTN DevBase;
> + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
> + UINT32 Ocr;
> + UINT16 Rca;
> + UINT32 DevStatus;
> + UINT32 Timeout;
> +
> + DevBase = Private->DevBase;
> + PassThru = &Private->PassThru;
> +
> + Status = EmmcReset (PassThru);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_INFO,
> + "EmmcIdentification: Executing Cmd0 fails with %r\n",
> + Status
> + ));
> + return Status;
> + }
> +
> + Timeout = 100;
> + do {
> + Ocr = EMMC_CMD1_CAPACITY_GREATER_THAN_2GB;
> + Status = EmmcGetOcr (PassThru, &Ocr);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_INFO,
> + "EmmcIdentification: Executing Cmd1 fails with %r\n",
> + Status
> + ));
> + return Status;
> + }
> + if (--Timeout <= 0) {
> + return EFI_DEVICE_ERROR;
> + }
> + MicroSecondDelay (100);
> + } while ((Ocr & BIT31) == 0);
> +
> + Status = EmmcGetAllCid (PassThru);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_INFO,
> + "EmmcIdentification: Executing Cmd2 fails with %r\n",
> + Status
> + ));
> + return Status;
> + }
> + //
> + // valid RCA starts from 1.
> + // Here we takes a simple formula to calculate the RCA.
> + // Don't support multiple devices on the slot, that is
> + // shared bus slot feature.
> + //
> + Rca = 1;
> + Status = EmmcSetRca (PassThru, Rca);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_INFO,
> + "EmmcIdentification: Executing Cmd3 fails with %r\n",
> + Status
> + ));
> + return Status;
> + }
> + //
> + // Enter Data Tranfer Mode.
> + //
> + DEBUG ((
> + DEBUG_INFO,
> + "EmmcIdentification: Found a EMMC device at RCA [%d]\n",
> + Rca
> + ));
> + Private->Slot[0].CardType = EmmcCardType;
> +
> + Status = EmmcSetBusMode (DevBase, PassThru, Rca);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // Exit DATA Mode.
> + //
> + do {
> + Status = EmmcSendStatus (PassThru, Rca, &DevStatus);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_INFO,
> + "EmmcSwitchBusWidth: Send status fails with %r\n",
> + Status
> + ));
> + return Status;
> + }
> + } while ((DevStatus & 0xf) == EMMC_STATE_DATA);
> +
> + return Status;
> +}
> diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c b/EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
> new file mode 100644
> index 000000000000..63246637b6dd
> --- /dev/null
> +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
> @@ -0,0 +1,1105 @@
> +/** @file
> + This file provides some helper functions which are specific for SD card
> + device.
> +
> + Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
> + Copyright (c) 2018, Linaro. 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 <IndustryStandard/Sd.h>
> +
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +
> +#include "DwMmcHcDxe.h"
> +
> +/**
> + Send command GO_IDLE_STATE to the device to make it go to Idle State.
> +
> + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> +
> + @retval EFI_SUCCESS The SD device is reset correctly.
> + @retval Others The device reset fails.
> +
> +**/
> +EFI_STATUS
> +SdCardReset (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = SD_GO_IDLE_STATE;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> + //Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> +
> + return Status;
> +}
> +
> +/**
> + Send command SEND_IF_COND to the device to inquiry the SD Memory Card
> + interface condition.
> +
> + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] SupplyVoltage The supplied voltage by the host.
> + @param[in] CheckPattern The check pattern to be sent to the device.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +SdCardVoltageCheck (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT8 SupplyVoltage,
> + IN UINT8 CheckPattern
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = SD_SEND_IF_COND;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR7;
> + SdMmcCmdBlk.CommandArgument = (SupplyVoltage << 8) | CheckPattern;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> +
> + if (!EFI_ERROR (Status)) {
> + if (SdMmcStatusBlk.Resp0 != SdMmcCmdBlk.CommandArgument) {
> + return EFI_DEVICE_ERROR;
> + }
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Send command SDIO_SEND_OP_COND to the device to see whether it is SDIO device.
> +
> + Refer to SDIO Simplified Spec 3 Section 3.2 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] VoltageWindow The supply voltage window.
> + @param[in] S18R The boolean to show if it should switch to 1.8v.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +SdioSendOpCond (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT32 VoltageWindow,
> + IN BOOLEAN S18R
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> + UINT32 Switch;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = SDIO_SEND_OP_COND;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR4;
> +
> + Switch = S18R ? BIT24 : 0;
> +
> + SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> +
> + return Status;
> +}
> +
> +/**
> + Send command SD_SEND_OP_COND to the device to see whether it is SDIO device.
> +
> + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Rca The relative device address of addressed device.
> + @param[in] VoltageWindow The supply voltage window.
> + @param[in] S18R The boolean to show if it should switch to 1.8v.
> + @param[in] Xpc The boolean to show if it should provide 0.36w
> + power control.
> + @param[in] Hcs The boolean to show if it support host capacity
> + info.
> + @param[out] Ocr The buffer to store returned OCR register value.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +SdCardSendOpCond (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT16 Rca,
> + IN UINT32 VoltageWindow,
> + IN BOOLEAN S18R,
> + IN BOOLEAN Xpc,
> + IN BOOLEAN Hcs,
> + OUT UINT32 *Ocr
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> + UINT32 Switch;
> + UINT32 MaxPower;
> + UINT32 HostCapacity;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + SdMmcCmdBlk.CommandIndex = SD_SEND_OP_COND;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;
> +
> + Switch = S18R ? BIT24 : 0;
> + MaxPower = Xpc ? BIT28 : 0;
> + HostCapacity = Hcs ? BIT30 : 0;
> +
> + SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch | \
> + MaxPower | HostCapacity;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> + if (!EFI_ERROR (Status)) {
> + *Ocr = SdMmcStatusBlk.Resp0;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Broadcast command ALL_SEND_CID to the bus to ask all the SD devices to send
> + the data of their CID registers.
> +
> + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +SdCardAllSendCid (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = SD_ALL_SEND_CID;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> +
> + return Status;
> +}
> +
> +/**
> + Send command SET_RELATIVE_ADDR to the SD device to assign a Relative device
> + Address (RCA).
> +
> + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[out] Rca The relative device address to assign.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +SdCardSetRca (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + OUT UINT16 *Rca
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> + if (!EFI_ERROR (Status)) {
> + *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Send command SEND_CSD to the SD device to get the data of the CSD register.
> +
> + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Rca The relative device address of selected device.
> + @param[out] Csd The buffer to store the content of the CSD register.
> + Note the caller should ignore the lowest byte of
> + this buffer as the content of this byte is meaning-
> + less even if the operation succeeds.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +SdCardGetCsd (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT16 Rca,
> + OUT SD_CSD *Csd
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = SD_SEND_CSD;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
> + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> + if (!EFI_ERROR (Status)) {
> + CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1);
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Send command SEND_CSD to the SD device to get the data of the CSD register.
> +
> + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Rca The relative device address of selected device.
> + @param[out] Scr The buffer to store the content of the SCR register.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +SdCardGetScr (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT16 Rca,
> + OUT SD_SCR *Scr
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + SdMmcCmdBlk.CommandIndex = SD_SEND_SCR;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> +
> + Packet.InDataBuffer = Scr;
> + Packet.InTransferLength = sizeof (SD_SCR);
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> +
> + return Status;
> +}
> +
> +/**
> + Send command SELECT_DESELECT_CARD to the SD device to select/deselect it.
> +
> + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Rca The relative device address of selected device.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +SdCardSelect (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT16 Rca
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> + if (Rca != 0) {
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
> + }
> + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> +
> + return Status;
> +}
> +
> +/**
> + Send command VOLTAGE_SWITCH to the SD device to switch the voltage of the
> + device.
> +
> + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +SdCardVoltageSwitch (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = SD_VOLTAGE_SWITCH;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> + SdMmcCmdBlk.CommandArgument = 0;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> +
> + return Status;
> +}
> +
> +/**
> + Send command SET_BUS_WIDTH to the SD device to set the bus width.
> +
> + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Rca The relative device address of addressed device.
> + @param[in] BusWidth The bus width to be set, it could be 1 or 4.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +SdCardSetBusWidth (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT16 Rca,
> + IN UINT8 BusWidth
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> + UINT8 Value;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + SdMmcCmdBlk.CommandIndex = SD_SET_BUS_WIDTH;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> +
> + if (BusWidth == 1) {
> + Value = 0;
> + } else if (BusWidth == 4) {
> + Value = 2;
> + } else {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + SdMmcCmdBlk.CommandArgument = Value & 0x3;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> + return Status;
> +}
> +
> +/**
> + Send command SWITCH_FUNC to the SD device to check switchable function or
> + switch card function.
> +
> + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] AccessMode The value for access mode group.
> + @param[in] CommandSystem The value for command set group.
> + @param[in] DriveStrength The value for drive length group.
> + @param[in] PowerLimit The value for power limit group.
> + @param[in] Mode Switch or check function.
> + @param[out] SwitchResp The return switch function status.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +SdCardSwitch (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT8 AccessMode,
> + IN UINT8 CommandSystem,
> + IN UINT8 DriveStrength,
> + IN UINT8 PowerLimit,
> + IN BOOLEAN Mode,
> + OUT UINT8 *SwitchResp
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> + UINT32 ModeValue;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = SD_SWITCH_FUNC;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> +
> + ModeValue = Mode ? BIT31 : 0;
> + SdMmcCmdBlk.CommandArgument = (AccessMode & 0xF) | \
> + ((PowerLimit & 0xF) << 4) | \
> + ((DriveStrength & 0xF) << 8) | \
> + ((DriveStrength & 0xF) << 12) | \
> + ModeValue;
> +
> + Packet.InDataBuffer = SwitchResp;
> + Packet.InTransferLength = 64;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> +
> + return Status;
> +}
> +
> +/**
> + Send command SEND_STATUS to the addressed SD device to get its status
> + register.
> +
> + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Rca The relative device address of addressed device.
> + @param[out] DevStatus The returned device status.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +SdCardSendStatus (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT16 Rca,
> + OUT UINT32 *DevStatus
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> + if (!EFI_ERROR (Status)) {
> + *DevStatus = SdMmcStatusBlk.Resp0;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Send command SEND_TUNING_BLOCK to the SD device for HS200 optimal sampling
> + point detection.
> +
> + It may be sent up to 40 times until the host finishes the tuning procedure.
> +
> + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> +
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +SdCardSendTuningBlk (
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
> + )
> +{
> + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> + EFI_STATUS Status;
> + UINT8 TuningBlock[64];
> +
> + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> + ZeroMem (&Packet, sizeof (Packet));
> +
> + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> +
> + SdMmcCmdBlk.CommandIndex = SD_SEND_TUNING_BLOCK;
> + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
> + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> + SdMmcCmdBlk.CommandArgument = 0;
> +
> + Packet.InDataBuffer = TuningBlock;
> + Packet.InTransferLength = sizeof (TuningBlock);
> +
> + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> +
> + return Status;
> +}
> +
> +/**
> + Switch the bus width to specified width.
> +
> + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and
> + SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.
> +
> + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Rca The relative device address to be assigned.
> + @param[in] BusWidth The bus width to be set, it could be 4 or 8.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +SdCardSwitchBusWidth (
> + IN UINTN DevBase,
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT16 Rca,
> + IN BOOLEAN IsDdr,
> + IN UINT8 BusWidth
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 DevStatus;
> +
> + Status = SdCardSetBusWidth (PassThru, Rca, BusWidth);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "SdCardSwitchBusWidth: Switch to bus width %d fails with %r\n",
> + BusWidth,
> + Status
> + ));
> + return Status;
> + }
> +
> + Status = SdCardSendStatus (PassThru, Rca, &DevStatus);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "SdCardSwitchBusWidth: Send status fails with %r\n",
> + Status
> + ));
> + return Status;
> + }
> + //
> + // Check the switch operation is really successful or not.
> + //
> + if ((DevStatus >> 16) != 0) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "SdCardSwitchBusWidth: The switch operation fails as DevStatus 0x%08x\n",
> + DevStatus
> + ));
> + return EFI_DEVICE_ERROR;
> + }
> +
> + Status = DwMmcHcSetBusWidth (DevBase, IsDdr, BusWidth);
> +
> + return Status;
> +}
> +
> +/**
> + Switch the high speed timing according to request.
> +
> + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> +
> + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
> + @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
> + instance.
> + @param[in] Rca The relative device address to be assigned.
> + @param[in] S18A The boolean to show if it's a UHS-I SD card.
> + @param[in] BusWidths The bus width of the SD card.
> +
> + @retval EFI_SUCCESS The operation is done correctly.
> + @retval Others The operation fails.
> +
> +**/
> +EFI_STATUS
> +SdCardSetBusMode (
> + IN UINTN DevBase,
> + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> + IN UINT16 Rca,
> + IN BOOLEAN S18A,
> + IN UINT32 BusWidths
> + )
> +{
> + EFI_STATUS Status;
> + DW_MMC_HC_SLOT_CAP *Capability;
> + UINT32 ClockFreq;
> + UINT8 AccessMode;
> + UINT8 SwitchResp[64];
> + DW_MMC_HC_PRIVATE_DATA *Private;
> + BOOLEAN IsDdr;
> +
> + Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru);
> +
> + Capability = &Private->Capability[0];
> +
> + if ((Capability->BusWidth == 1) || (Capability->BusWidth == 4)) {
> + BusWidths &= Capability[0].BusWidth;
> + } else {
> + DEBUG ((
> + DEBUG_ERROR,
> + "SdCardSetBusMode: BusWidths (%d) in capability are wrong\n",
> + Capability->BusWidth
> + ));
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (BusWidths == 0) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "SdCardSetBusMode: Get wrong BusWidths:%d\n",
> + BusWidths
> + ));
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (Private->Capability[0].Ddr50) {
> + IsDdr = TRUE;
> + } else {
> + IsDdr = FALSE;
> + }
> +
> + Status = SdCardSwitchBusWidth (DevBase, PassThru, Rca, IsDdr, BusWidths);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "SdCardSetBusMode: Executing SdCardSwitchBusWidth fails with %r\n",
> + Status
> + ));
> + return Status;
> + }
> +
> + //
> + // Get the supported bus speed from SWITCH cmd return data group #1.
> + //
> + Status = SdCardSwitch (PassThru, 0xF, 0xF, 0xF, 0xF, FALSE, SwitchResp);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> + //
> + // Calculate supported bus speed/bus width/clock frequency by host and device
> + // capability.
> + //
> + ClockFreq = 0;
> + if (S18A && (Capability->Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) {
> + ClockFreq = 208;
> + AccessMode = 3;
> + } else if (S18A && (Capability->Sdr50 != 0) &&
> + ((SwitchResp[13] & BIT2) != 0)) {
> + ClockFreq = 100;
> + AccessMode = 2;
> + } else if (S18A && (Capability->Ddr50 != 0) &&
> + ((SwitchResp[13] & BIT4) != 0)) {
> + ClockFreq = 50;
> + AccessMode = 4;
> + } else if ((SwitchResp[13] & BIT1) != 0) {
> + ClockFreq = 50;
> + AccessMode = 1;
> + } else {
> + ClockFreq = 25;
> + AccessMode = 0;
> + }
> +
> + Status = SdCardSwitch (PassThru, AccessMode, 0xF, 0xF, 0xF, TRUE, SwitchResp);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + if ((SwitchResp[16] & 0xF) != AccessMode) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "SdCardSetBusMode: Switch to AccessMode %d ClockFreq %d fails! The Switch response is 0x%1x\n",
> + AccessMode,
> + ClockFreq,
> + SwitchResp[16] & 0xF
> + ));
> + return EFI_DEVICE_ERROR;
> + }
> +
> + DEBUG ((
> + DEBUG_INFO,
> + "SdCardSetBusMode: Switch to AccessMode %d ClockFreq %d \n",
> + AccessMode,
> + ClockFreq
> + ));
> +
> + Status = DwMmcHcClockSupply (DevBase, ClockFreq * 1000, *Capability);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + return Status;
> +}
> +
> +EFI_STATUS
> +SdCardIdentification (
> + IN DW_MMC_HC_PRIVATE_DATA *Private
> + )
> +{
> + EFI_STATUS Status;
> + UINTN DevBase;
> + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
> + UINT32 Ocr;
> + UINT16 Rca;
> + BOOLEAN Xpc;
> + BOOLEAN S18r;
> + UINT64 MaxCurrent;
> + SD_SCR Scr;
> + SD_CSD Csd;
> +
> + DevBase = Private->DevBase;
> + PassThru = &Private->PassThru;
> + //
> + // 1. Send Cmd0 to the device
> + //
> + Status = SdCardReset (PassThru);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_INFO,
> + "SdCardIdentification: Executing Cmd0 fails with %r\n",
> + Status
> + ));
> + return Status;
> + }
> + MicroSecondDelay (10000);
> + //
> + // 2. Send Cmd8 to the device
> + //
> + Status = SdCardVoltageCheck (PassThru, 0x1, 0xFF);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_INFO,
> + "SdCardIdentification: Executing Cmd8 fails with %r\n",
> + Status
> + ));
> + return Status;
> + }
> + //
> + // 3. Send Acmd41 with voltage window 0 to the device
> + //
> + Status = SdCardSendOpCond (PassThru, 0, 0, FALSE, FALSE, FALSE, &Ocr);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_INFO,
> + "SdCardIdentification: Executing SdCardSendOpCond fails with %r\n",
> + Status
> + ));
> + return EFI_DEVICE_ERROR;
> + }
> +
> + if (Private->Capability[0].Voltage33 != 0) {
> + //
> + // Support 3.3V
> + //
> + MaxCurrent = ((UINT32)Private->MaxCurrent[0] & 0xFF) * 4;
> + S18r = FALSE;
> + } else if (Private->Capability[0].Voltage30 != 0) {
> + //
> + // Support 3.0V
> + //
> + MaxCurrent = (((UINT32)Private->MaxCurrent[0] >> 8) & 0xFF) * 4;
> + S18r = FALSE;
> + } else if (Private->Capability[0].Voltage18 != 0) {
> + //
> + // Support 1.8V
> + //
> + MaxCurrent = (((UINT32)Private->MaxCurrent[0] >> 16) & 0xFF) * 4;
> + S18r = TRUE;
> + } else {
> + ASSERT (FALSE);
> + return EFI_DEVICE_ERROR;
> + }
> +
> + if (MaxCurrent >= 150) {
> + Xpc = TRUE;
> + } else {
> + Xpc = FALSE;
> + }
> +
> + //
> + // 4. Repeatly send Acmd41 with supply voltage window to the device.
> + // Note here we only support the cards complied with SD physical
> + // layer simplified spec version 2.0 and version 3.0 and above.
> + //
> + do {
> + Status = SdCardSendOpCond (PassThru, 0, Ocr, S18r, Xpc, TRUE, &Ocr);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "SdCardIdentification: SdCardSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n",
> + Status,
> + Ocr,
> + S18r,
> + Xpc
> + ));
> + return EFI_DEVICE_ERROR;
> + }
> + } while ((Ocr & BIT31) == 0);
> +
> + Status = SdCardAllSendCid (PassThru);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "SdCardIdentification: Executing SdCardAllSendCid fails with %r\n",
> + Status
> + ));
> + return Status;
> + }
> +
> + Status = SdCardSetRca (PassThru, &Rca);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "SdCardIdentification: Executing SdCardSetRca fails with %r\n",
> + Status
> + ));
> + return Status;
> + }
> +
> + Status = SdCardGetCsd (PassThru, Rca, &Csd);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "SdCardIdentification: Executing SdCardGetCsd fails with %r\n",
> + Status
> + ));
> + return Status;
> + }
> +
> + Status = SdCardSelect (PassThru, Rca);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "SdCardIdentification: Selecting card fails with %r\n",
> + Status
> + ));
> + return Status;
> + }
> +
> + Status = SdCardGetScr (PassThru, Rca, &Scr);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((
> + DEBUG_ERROR,
> + "SdCardIdentification: Executing SdCardGetScr fails with %r\n",
> + Status
> + ));
> + return Status;
> + }
> +
> + //
> + // Enter Data Tranfer Mode.
> + //
> + DEBUG ((DEBUG_INFO, "SdCardIdentification: Found a SD device\n"));
> + Private->Slot[0].CardType = SdCardType;
> +
> + Status = SdCardSetBusMode (DevBase, PassThru, Rca, S18r, Scr.SdBusWidths);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Private->Slot[0].Initialized = TRUE;
> +
> + return Status;
> +}
> --
> 2.12.3
>
>
>
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [edk2-devel] [PATCH V4 1/1] EmbeddedPkg: DwMmcHcDxe: Add support for Designware SDMMC driver
2021-03-19 15:33 ` [edk2-devel] " Michael D Kinney
@ 2021-03-22 3:32 ` Loh, Tien Hock
0 siblings, 0 replies; 4+ messages in thread
From: Loh, Tien Hock @ 2021-03-22 3:32 UTC (permalink / raw)
To: Kinney, Michael D, devel@edk2.groups.io
Cc: thloh85@gmail.com, Leif Lindholm, Ard Biesheuvel
Hi Mike,
I have created a V5 patch with the license and header updated.
Thanks
> -----Original Message-----
> From: Kinney, Michael D <michael.d.kinney@intel.com>
> Sent: Friday, March 19, 2021 11:33 PM
> To: devel@edk2.groups.io; Loh, Tien Hock <tien.hock.loh@intel.com>;
> Kinney, Michael D <michael.d.kinney@intel.com>
> Cc: thloh85@gmail.com; Leif Lindholm <leif@nuviainc.com>; Ard Biesheuvel
> <ardb+tianocore@kernel.org>
> Subject: RE: [edk2-devel] [PATCH V4 1/1] EmbeddedPkg: DwMmcHcDxe:
> Add support for Designware SDMMC driver
>
> Hello,
>
> The majority of the EDK II files use BSD 2-Clause Plus Patent license with
> SPDX identifiers in the source file headers:
>
> https://github.com/tianocore/edk2#license-details
> https://github.com/tianocore/edk2/blob/master/License.txt
> # SPDX-License-Identifier: BSD-2-Clause-Patent
>
> Can this content be updated to use that license and file header style?
>
> Thanks,
>
> Mike
>
> > -----Original Message-----
> > From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Loh,
> Tien Hock
> > Sent: Friday, March 19, 2021 1:22 AM
> > To: devel@edk2.groups.io
> > Cc: Loh, Tien Hock <tien.hock.loh@intel.com>; thloh85@gmail.com; Leif
> Lindholm <leif@nuviainc.com>; Ard Biesheuvel
> > <ardb+tianocore@kernel.org>
> > Subject: [edk2-devel] [PATCH V4 1/1] EmbeddedPkg: DwMmcHcDxe: Add
> support for Designware SDMMC driver
> >
> > From: "Tien Hock, Loh" <tien.hock.loh@intel.com>
> >
> > This adds support for Designware SDMMC driver. The SDMMC driver
> depends on
> > MdeModulePkg/Bus/Sd/, and produces
> EFI_SD_MMC_PASS_THRU_PROTOCOL. The
> > driver uses MMIO to read/write, and uses
> > gEdkiiNonDiscoverableDeviceProtocolGuid. Platform needs to register
> device
> > with gEdkiiNonDiscoverableDeviceProtocolGuid.
> >
> > Signed-off-by: Loh Tien Hock <tien.hock.loh@intel.com>
> > Cc: Leif Lindholm <leif@nuviainc.com>
> > Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> > ---
> > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec | 40 +
> > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf | 70 +
> > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h | 817
> ++++++++++
> > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h | 985
> ++++++++++++
> > EmbeddedPkg/Include/Protocol/PlatformDwMmc.h | 79 +
> > EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c | 214 +++
> > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c | 1296
> ++++++++++++++++
> > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c | 1602
> ++++++++++++++++++++
> > EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c | 1042
> +++++++++++++
> > EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c | 1105
> ++++++++++++++
> > 10 files changed, 7250 insertions(+)
> >
> > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
> b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
> > new file mode 100644
> > index 000000000000..cf85ccb1a030
> > --- /dev/null
> > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
> > @@ -0,0 +1,40 @@
> > +#/** @file
> > +# Framework Module Development Environment Industry Standards
> > +#
> > +# This Package provides headers and libraries that conform to EFI/PI
> Industry standards.
> > +# Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
> > +# Copyright (c) 2012-2014, ARM Ltd. All rights reserved.<BR>
> > +# Copyright (c) 2018, Linaro. 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]
> > + DEC_SPECIFICATION = 0x00010019
> > + PACKAGE_NAME = DwMmcHcDxePkg
> > + PACKAGE_GUID = e73097ce-1fe2-41a6-a930-3136bc6d23ef
> > + PACKAGE_VERSION = 0.1
> > +
> > +
> >
> +#########################################################
> #######################
> > +#
> > +# Include Section - list of Include Paths that are provided by this package.
> > +# Comments are used for Keywords and Module Types.
> > +#
> > +# Supported Module Types:
> > +# BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER
> DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER
> > UEFI_APPLICATION
> > +#
> >
> +#########################################################
> #######################
> > +
> > +[Guids.common]
> > + gDwMmcHcDxeTokenSpaceGuid = { 0x576c132e, 0x7d51, 0x4abb, {
> 0xbc, 0x60, 0x13, 0x08, 0x04, 0x0e, 0x90, 0x92 }}
> > +
> > +[Protocols.common]
> > + gPlatformDwMmcProtocolGuid = { 0x1d6dfde5, 0x76a7, 0x4404, { 0x85,
> 0x74, 0x7a, 0xdf, 0x1a, 0x8a, 0xa2, 0x0d }}
> > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
> b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
> > new file mode 100644
> > index 000000000000..4cd0960ef9c3
> > --- /dev/null
> > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
> > @@ -0,0 +1,70 @@
> > +## @file
> > +# DwSdMmcHcDxe driver is used to manage those host controllers which
> comply with
> > +# Designware SD Host Controller.
> > +#
> > +# It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending
> SD/MMC/eMMC cmds
> > +# to specified devices from upper layer.
> > +#
> > +# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
> > +# Copyright (C) 2016, Marvell International Ltd. All rights reserved.<BR>
> > +# Copyright (c) 2018, Linaro Ltd. 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 = 0x00010019
> > + BASE_NAME = DwMmcHcDxe
> > + MODULE_UNI_FILE = DwMmcHcDxe.uni
> > + FILE_GUID = 9be4d260-208c-4efe-a524-0b5d3bf77f9d
> > + MODULE_TYPE = UEFI_DRIVER
> > + VERSION_STRING = 1.0
> > + ENTRY_POINT = InitializeDwMmcHcDxe
> > +
> > +[Sources]
> > + ComponentName.c
> > + DwMmcHcDxe.c
> > + DwMmcHcDxe.h
> > + DwMmcHci.c
> > + DwMmcHci.h
> > + EmmcDevice.c
> > + SdDevice.c
> > +
> > +[Packages]
> > + ArmPkg/ArmPkg.dec
> > + EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
> > + EmbeddedPkg/EmbeddedPkg.dec
> > + MdeModulePkg/MdeModulePkg.dec
> > + MdePkg/MdePkg.dec
> > +
> > +[LibraryClasses]
> > + ArmLib
> > + BaseLib
> > + BaseMemoryLib
> > + CacheMaintenanceLib
> > + DebugLib
> > + DevicePathLib
> > + DmaLib
> > + MemoryAllocationLib
> > + TimerLib
> > + UefiBootServicesTableLib
> > + UefiDriverEntryPoint
> > + UefiLib
> > + UefiRuntimeServicesTableLib
> > +
> > +[Protocols]
> > + gEdkiiNonDiscoverableDeviceProtocolGuid
> > + gEfiDevicePathProtocolGuid ## TO_START
> > + gEfiPciIoProtocolGuid ## TO_START
> > + gEfiSdMmcPassThruProtocolGuid ## BY_START
> > + gPlatformDwMmcProtocolGuid
> > +
> > +[UserExtensions.TianoCore."ExtraFiles"]
> > + DwMmcHcDxeExtra.uni
> > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
> b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
> > new file mode 100644
> > index 000000000000..b783d9830325
> > --- /dev/null
> > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
> > @@ -0,0 +1,817 @@
> > +/** @file
> > +
> > + Provides some data structure definitions used by the Designware
> SD/MMC
> > + host controller driver.
> > +
> > + Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
> > + Copyright (C) 2018, Linaro Ltd. All rigths 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 _DW_MMC_HC_DXE_H_
> > +#define _DW_MMC_HC_DXE_H_
> > +
> > +#include <Uefi.h>
> > +
> > +#include <Library/UefiLib.h>
> > +
> > +#include <Protocol/ComponentName.h>
> > +#include <Protocol/ComponentName2.h>
> > +#include <Protocol/DeviceIo.h>
> > +#include <Protocol/DriverBinding.h>
> > +#include <Protocol/SdMmcPassThru.h>
> > +
> > +#include "DwMmcHci.h"
> > +
> > +extern EFI_COMPONENT_NAME_PROTOCOL
> gDwMmcHcComponentName;
> > +extern EFI_COMPONENT_NAME2_PROTOCOL
> gDwMmcHcComponentName2;
> > +extern EFI_DRIVER_BINDING_PROTOCOL gDwMmcHcDriverBinding;
> > +
> > +#define DW_MMC_HC_PRIVATE_SIGNATURE SIGNATURE_32 ('d', 'w', 's',
> 'd')
> > +
> > +#define DW_MMC_HC_PRIVATE_FROM_THIS(a) \
> > + CR(a, DW_MMC_HC_PRIVATE_DATA, PassThru,
> DW_MMC_HC_PRIVATE_SIGNATURE)
> > +
> > +//
> > +// Generic time out value, 1 microsecond as unit.
> > +//
> > +#define DW_MMC_HC_GENERIC_TIMEOUT (1 * 1000 * 1000)
> > +
> > +//
> > +// SD/MMC async transfer timer interval, set by experience.
> > +// The unit is 100us, takes 1ms as interval.
> > +//
> > +#define DW_MMC_HC_ASYNC_TIMER
> EFI_TIMER_PERIOD_MILLISECONDS(1)
> > +//
> > +// SD/MMC removable device enumeration timer interval, set by
> experience.
> > +// The unit is 100us, takes 100ms as interval.
> > +//
> > +#define DW_MMC_HC_ENUM_TIMER
> EFI_TIMER_PERIOD_MILLISECONDS(100)
> > +
> > +typedef struct {
> > + BOOLEAN Enable;
> > + EFI_SD_MMC_SLOT_TYPE SlotType;
> > + BOOLEAN MediaPresent;
> > + BOOLEAN Initialized;
> > + SD_MMC_CARD_TYPE CardType;
> > +} DW_MMC_HC_SLOT;
> > +
> > +typedef struct {
> > + UINTN Signature;
> > +
> > + EFI_HANDLE ControllerHandle;
> > +
> > + // Mmio base address
> > + UINTN DevBase;
> > +
> > + EFI_SD_MMC_PASS_THRU_PROTOCOL PassThru;
> > +
> > + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc;
> > + //
> > + // The field is used to record the previous slot in GetNextSlot().
> > + //
> > + UINT8 PreviousSlot;
> > + //
> > + // For Non-blocking operation.
> > + //
> > + EFI_EVENT TimerEvent;
> > + //
> > + // For Sd removable device enumeration.
> > + //
> > + EFI_EVENT ConnectEvent;
> > + LIST_ENTRY Queue;
> > +
> > + DW_MMC_HC_SLOT Slot[DW_MMC_HC_MAX_SLOT];
> > + DW_MMC_HC_SLOT_CAP
> Capability[DW_MMC_HC_MAX_SLOT];
> > + UINT64 MaxCurrent[DW_MMC_HC_MAX_SLOT];
> > +
> > + UINT32 ControllerVersion;
> > +} DW_MMC_HC_PRIVATE_DATA;
> > +
> > +#define DW_MMC_HC_TRB_SIG SIGNATURE_32 ('D', 'T', 'R', 'B')
> > +
> > +//
> > +// TRB (Transfer Request Block) contains information for the cmd request.
> > +//
> > +typedef struct {
> > + UINT32 Signature;
> > + LIST_ENTRY TrbList;
> > +
> > + UINT8 Slot;
> > + UINT16 BlockSize;
> > +
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
> > + VOID *Data;
> > + UINT32 DataLen;
> > + BOOLEAN Read;
> > + EFI_PHYSICAL_ADDRESS DataPhy;
> > + VOID *DataMap;
> > + DW_MMC_HC_TRANSFER_MODE Mode;
> > +
> > + EFI_EVENT Event;
> > + BOOLEAN Started;
> > + UINT64 Timeout;
> > +
> > + DW_MMC_HC_DMA_DESC_LINE *DmaDesc;
> > + EFI_PHYSICAL_ADDRESS DmaDescPhy;
> > + UINT32 DmaDescPages;
> > + VOID *DmaMap;
> > +
> > + BOOLEAN UseFifo;
> > + BOOLEAN UseBE; // Big-endian
> > +
> > + DW_MMC_HC_PRIVATE_DATA *Private;
> > +} DW_MMC_HC_TRB;
> > +
> > +#define DW_MMC_HC_TRB_FROM_THIS(a) \
> > + CR(a, DW_MMC_HC_TRB, TrbList, DW_MMC_HC_TRB_SIG)
> > +
> > +//
> > +// Task for Non-blocking mode.
> > +//
> > +typedef struct {
> > + UINT32 Signature;
> > + LIST_ENTRY Link;
> > +
> > + UINT8 Slot;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
> > + BOOLEAN IsStart;
> > + EFI_EVENT Event;
> > + UINT64 RetryTimes;
> > + BOOLEAN InfiniteWait;
> > + VOID *Map;
> > + VOID *MapAddress;
> > +} DW_MMC_HC_QUEUE;
> > +
> > +//
> > +// Prototypes
> > +//
> > +/**
> > + Execute card identification procedure.
> > +
> > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA
> instance.
> > +
> > + @retval EFI_SUCCESS The card is identified correctly.
> > + @retval Others The card can't be identified.
> > +
> > +**/
> > +typedef
> > +EFI_STATUS
> > +(*DWMMC_CARD_TYPE_DETECT_ROUTINE) (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private
> > + );
> > +
> > +/**
> > + Sends SD command to an SD card that is attached to the SD controller.
> > +
> > + The PassThru() function sends the SD command specified by Packet to
> the SD
> > + card specified by Slot.
> > +
> > + If Packet is successfully sent to the SD card, then EFI_SUCCESS is
> returned.
> > +
> > + If a device error occurs while sending the Packet, then
> EFI_DEVICE_ERROR is
> > + returned.
> > +
> > + If Slot is not in a valid range for the SD controller, then
> > + EFI_INVALID_PARAMETER is returned.
> > +
> > + If Packet defines a data command but both InDataBuffer and
> OutDataBuffer are
> > + NULL, EFI_INVALID_PARAMETER is returned.
> > +
> > + @param[in] This A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Slot The slot number of the SD card to send the
> > + command to.
> > + @param[in,out] Packet A pointer to the SD command data structure.
> > + @param[in] Event If Event is NULL, blocking I/O is performed. If
> > + Event is not NULL, then nonblocking I/O is
> > + performed, and Event will be signaled when the
> > + Packet completes.
> > +
> > + @retval EFI_SUCCESS The SD Command Packet was sent by the
> host.
> > + @retval EFI_DEVICE_ERROR A device error occurred while attempting
> to send
> > + the SD command Packet.
> > + @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the
> Packet is
> > + invalid.
> > + @retval EFI_INVALID_PARAMETER Packet defines a data command but
> both
> > + InDataBuffer and OutDataBuffer are NULL.
> > + @retval EFI_NO_MEDIA SD Device not present in the Slot.
> > + @retval EFI_UNSUPPORTED The command described by the SD
> Command Packet
> > + is not supported by the host controller.
> > + @retval EFI_BAD_BUFFER_SIZE The InTransferLength or
> OutTransferLength
> > + exceeds the limit supported by SD card ( i.e. if
> > + the number of bytes exceed the Last LBA).
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcPassThruPassThru (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> > + IN UINT8 Slot,
> > + IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
> > + IN EFI_EVENT Event OPTIONAL
> > + );
> > +
> > +/**
> > + Used to retrieve next slot numbers supported by the SD controller. The
> > + function returns information about all available slots (populated or
> > + not-populated).
> > +
> > + The GetNextSlot() function retrieves the next slot number on an SD
> controller.
> > + If on input Slot is 0xFF, then the slot number of the first slot on the SD
> > + controller is returned.
> > +
> > + If Slot is a slot number that was returned on a previous call to
> > + GetNextSlot(), then the slot number of the next slot on the SD controller
> is
> > + returned.
> > +
> > + If Slot is not 0xFF and Slot was not returned on a previous call to
> > + GetNextSlot(), EFI_INVALID_PARAMETER is returned.
> > +
> > + If Slot is the slot number of the last slot on the SD controller, then
> > + EFI_NOT_FOUND is returned.
> > +
> > + @param[in] This A pointer to the
> EFI_SD_MMMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in,out] Slot On input, a pointer to a slot number on the SD
> > + controller.
> > + On output, a pointer to the next slot number on
> > + the SD controller.
> > + An input value of 0xFF retrieves the first slot
> > + number on the SD controller.
> > +
> > + @retval EFI_SUCCESS The next slot number on the SD controller
> was
> > + returned in Slot.
> > + @retval EFI_NOT_FOUND There are no more slots on this SD
> controller.
> > + @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not
> returned on a
> > + previous call to GetNextSlot().
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcPassThruGetNextSlot (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> > + IN OUT UINT8 *Slot
> > + );
> > +
> > +/**
> > + Used to allocate and build a device path node for an SD card on the SD
> > + controller.
> > +
> > + The BuildDevicePath() function allocates and builds a single device node
> > + for the SD
> > + card specified by Slot.
> > +
> > + If the SD card specified by Slot is not present on the SD controller, then
> > + EFI_NOT_FOUND is returned.
> > +
> > + If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.
> > +
> > + If there are not enough resources to allocate the device path node, then
> > + EFI_OUT_OF_RESOURCES is returned.
> > +
> > + Otherwise, DevicePath is allocated with the boot service AllocatePool(),
> the
> > + contents of DevicePath are initialized to describe the SD card specified by
> > + Slot, and EFI_SUCCESS is returned.
> > +
> > + @param[in] This A pointer to the
> EFI_SD_MMMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Slot Specifies the slot number of the SD card for
> > + which a device path node is to be allocated and
> > + built.
> > + @param[in,out] DevicePath A pointer to a single device path node that
> > + describes the SD card specified by Slot. This
> > + function is responsible for allocating the
> > + buffer DevicePath with the boot service
> > + AllocatePool(). It is the caller's responsibi-
> > + lity to free DevicePath when the caller is
> > + finished with DevicePath.
> > +
> > + @retval EFI_SUCCESS The device path node that describes the SD
> card
> > + specified by Slot was allocated and returned in
> > + DevicePath.
> > + @retval EFI_NOT_FOUND The SD card specified by Slot does not
> exist on
> > + the SD controller.
> > + @retval EFI_INVALID_PARAMETER DevicePath is NULL.
> > + @retval EFI_OUT_OF_RESOURCES There are not enough resources to
> allocate
> > + DevicePath.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcPassThruBuildDevicePath (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> > + IN UINT8 Slot,
> > + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
> > + );
> > +
> > +/**
> > + This function retrieves an SD card slot number based on the input device
> path.
> > +
> > + The GetSlotNumber() function retrieves slot number for the SD card
> specified
> > + by the DevicePath node. If DevicePath is NULL,
> EFI_INVALID_PARAMETER is
> > + returned.
> > +
> > + If DevicePath is not a device path node type that the SD Pass Thru driver
> > + supports, EFI_UNSUPPORTED is returned.
> > +
> > + @param[in] This A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] DevicePath A pointer to the device path node that
> describes
> > + a SD card on the SD controller.
> > + @param[out] Slot On return, points to the slot number of an SD
> > + card on the SD controller.
> > +
> > + @retval EFI_SUCCESS SD card slot number is returned in Slot.
> > + @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.
> > + @retval EFI_UNSUPPORTED DevicePath is not a device path node
> type that
> > + the SD Pass Thru driver supports.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcPassThruGetSlotNumber (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> > + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
> > + OUT UINT8 *Slot
> > + );
> > +
> > +/**
> > + Resets an SD card that is connected to the SD controller.
> > +
> > + The ResetDevice() function resets the SD card specified by Slot.
> > +
> > + If this SD controller does not support a device reset operation,
> > + EFI_UNSUPPORTED is returned.
> > +
> > + If Slot is not in a valid slot number for this SD controller,
> > + EFI_INVALID_PARAMETER is returned.
> > +
> > + If the device reset operation is completed, EFI_SUCCESS is returned.
> > +
> > + @param[in] This A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Slot Specifies the slot number of the SD card to be
> > + reset.
> > +
> > + @retval EFI_SUCCESS The SD card specified by Slot was reset.
> > + @retval EFI_UNSUPPORTED The SD controller does not support a
> device
> > + reset operation.
> > + @retval EFI_INVALID_PARAMETER Slot number is invalid.
> > + @retval EFI_NO_MEDIA SD Device not present in the Slot.
> > + @retval EFI_DEVICE_ERROR The reset command failed due to a device
> error
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcPassThruResetDevice (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> > + IN UINT8 Slot
> > + );
> > +
> > +//
> > +// Driver model protocol interfaces
> > +//
> > +/**
> > + Tests to see if this driver supports a given controller. If a child device is
> > + provided, it further tests to see if this driver supports creating a handle
> > + for the specified child device.
> > +
> > + This function checks to see if the driver specified by This supports the
> > + device specified by ControllerHandle. Drivers will typically use the device
> > + path attached to ControllerHandle and/or the services from the bus I/O
> > + abstraction attached to ControllerHandle to determine if the driver
> supports
> > + ControllerHandle. This function may be called many times during
> platform
> > + initialization. In order to reduce boot times, the tests performed by this
> > + function must be very small, and take as little time as possible to
> execute.
> > + This function must not change the state of any hardware devices, and
> this
> > + function must be aware that the device specified by ControllerHandle
> may
> > + already be managed by the same driver or a different driver. This
> function
> > + must match its calls to AllocatePages() with FreePages(), AllocatePool()
> with
> > + FreePool(), and OpenProtocol() with CloseProtocol().
> > + Since ControllerHandle may have been previously started by the same
> driver, if
> > + a protocol is already in the opened state, then it must not be closed with
> > + CloseProtocol(). This is required to guarantee the state of
> ControllerHandle
> > + is not modified by this function.
> > +
> > + @param[in] This A pointer to the
> EFI_DRIVER_BINDING_PROTOCOL
> > + instance.
> > + @param[in] ControllerHandle The handle of the controller to test. This
> > + handle must support a protocol interface that
> > + supplies an I/O abstraction to the driver.
> > + @param[in] RemainingDevicePath A pointer to the remaining portion of
> a
> > + device path. This parameter is ignored by
> > + device drivers, and is optional for bus
> > + drivers. For bus drivers, if this parameter
> > + is not NULL, then the bus driver must deter-
> > + mine if the bus controller specified by
> > + ControllerHandle and the child controller
> > + specified by RemainingDevicePath are both
> > + supported by this bus driver.
> > +
> > + @retval EFI_SUCCESS The device specified by ControllerHandle
> and
> > + RemainingDevicePath is supported by the
> > + driver specified by This.
> > + @retval EFI_ALREADY_STARTED The device specified by
> ControllerHandle and
> > + RemainingDevicePath is already being managed
> > + by the driver specified by This.
> > + @retval EFI_ACCESS_DENIED The device specified by
> ControllerHandle and
> > + RemainingDevicePath is already being managed
> > + by a different driver or an application that
> > + requires exclusive access.
> > + Currently not implemented.
> > + @retval EFI_UNSUPPORTED The device specified by
> ControllerHandle and
> > + RemainingDevicePath is not supported by the
> > + driver specified by This.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcHcDriverBindingSupported (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE Controller,
> > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> > + );
> > +
> > +/**
> > + Starts a device controller or a bus controller.
> > +
> > + The Start() function is designed to be invoked from the EFI boot service
> > + ConnectController().
> > + As a result, much of the error checking on the parameters to Start() has
> been
> > + moved into this common boot service. It is legal to call Start() from other
> > + locations,
> > + but the following calling restrictions must be followed or the system
> behavior
> > + will not be deterministic.
> > + 1. ControllerHandle must be a valid EFI_HANDLE.
> > + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a
> natural-
> > + ly aligned EFI_DEVICE_PATH_PROTOCOL.
> > + 3. Prior to calling Start(), the Supported() function for the driver specified
> > + by This must have been called with the same calling parameters, and
> > + Supported() must have returned EFI_SUCCESS.
> > +
> > + @param[in] This A pointer to the
> EFI_DRIVER_BINDING_PROTOCOL
> > + instance.
> > + @param[in] ControllerHandle The handle of the controller to start.
> This
> > + handle must support a protocol interface that
> > + supplies an I/O abstraction to the driver.
> > + @param[in] RemainingDevicePath A pointer to the remaining portion of
> a
> > + device path. This parameter is ignored by
> > + device drivers, and is optional for bus dri-
> > + vers. For a bus driver, if this parameter is
> > + NULL, then handles for all the children of
> > + Controller are created by this driver.
> > + If this parameter is not NULL and the first
> > + Device Path Node is not the End of Device
> > + Path Node, then only the handle for the
> > + child device specified by the first Device
> > + Path Node of RemainingDevicePath is created
> > + by this driver.
> > + If the first Device Path Node of
> > + RemainingDevicePath is the End of Device Path
> > + Node, no child handle is created by this
> > + driver.
> > +
> > + @retval EFI_SUCCESS The device was started.
> > + @retval EFI_DEVICE_ERROR The device could not be started due to a
> > + device error. Currently not implemented.
> > + @retval EFI_OUT_OF_RESOURCES The request could not be
> completed due to a
> > + lack of resources.
> > + @retval Others The driver failded to start the device.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcHcDriverBindingStart (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE Controller,
> > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> > + );
> > +
> > +/**
> > + Stops a device controller or a bus controller.
> > +
> > + The Stop() function is designed to be invoked from the EFI boot service
> > + DisconnectController().
> > + As a result, much of the error checking on the parameters to Stop() has
> been
> > + moved into this common boot service. It is legal to call Stop() from other
> > + locations, but the following calling restrictions must be followed or the
> > + system behavior will not be deterministic.
> > + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a
> previous
> > + call to this same driver's Start() function.
> > + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a
> valid
> > + EFI_HANDLE. In addition, all of these handles must have been created
> in
> > + this driver's Start() function, and the Start() function must have called
> > + OpenProtocol() on ControllerHandle with an Attribute of
> > + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
> > +
> > + @param[in] This A pointer to the
> EFI_DRIVER_BINDING_PROTOCOL
> > + instance.
> > + @param[in] ControllerHandle A handle to the device being stopped.
> The handle
> > + must support a bus specific I/O protocol for the
> > + driver to use to stop the device.
> > + @param[in] NumberOfChildren The number of child device handles in
> > + ChildHandleBuffer.
> > + @param[in] ChildHandleBuffer An array of child handles to be freed.
> May be
> > + NULL if NumberOfChildren is 0.
> > +
> > + @retval EFI_SUCCESS The device was stopped.
> > + @retval EFI_DEVICE_ERROR The device could not be stopped due to a
> device
> > + error.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcHcDriverBindingStop (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE Controller,
> > + IN UINTN NumberOfChildren,
> > + IN EFI_HANDLE *ChildHandleBuffer
> > + );
> > +
> > +//
> > +// EFI Component Name Functions
> > +//
> > +/**
> > + Retrieves a Unicode string that is the user readable name of the driver.
> > +
> > + This function retrieves the user readable name of a driver in the form of
> a
> > + Unicode string. If the driver specified by This has a user readable name in
> > + the language specified by Language, then a pointer to the driver name is
> > + returned in DriverName, and EFI_SUCCESS is returned. If the driver
> specified
> > + by This does not support the language specified by Language,
> > + then EFI_UNSUPPORTED is returned.
> > +
> > + @param This[in] A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> > + EFI_COMPONENT_NAME_PROTOCOL instance.
> > +
> > + @param Language[in] A pointer to a Null-terminated ASCII string
> > + array indicating the language. This is the
> > + language of the driver name 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. Language is specified
> > + in RFC 4646 or ISO 639-2 language code format.
> > +
> > + @param DriverName[out] 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
> > +DwMmcHcComponentNameGetDriverName (
> > + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> > + IN CHAR8 *Language,
> > + OUT CHAR16 **DriverName
> > + );
> > +
> > +/**
> > + Retrieves a Unicode string that is the user readable name of the
> controller
> > + that is being managed by a driver.
> > +
> > + This function retrieves the user readable name of the controller specified
> by
> > + ControllerHandle and ChildHandle in the form of a Unicode string. If the
> > + driver specified by This has a user readable name in the language
> specified by
> > + Language, then a pointer to the controller name is returned in
> ControllerName,
> > + and EFI_SUCCESS is returned. If the driver specified by This is not
> currently
> > + managing the controller specified by ControllerHandle and ChildHandle,
> > + then EFI_UNSUPPORTED is returned. If the driver specified by This does
> not
> > + support the language specified by Language, then EFI_UNSUPPORTED is
> returned.
> > +
> > + @param This[in] A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> > + EFI_COMPONENT_NAME_PROTOCOL instance.
> > +
> > + @param ControllerHandle[in] 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 ChildHandle[in] 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 Language[in] A pointer to a Null-terminated ASCII string
> > + array indicating the language. This is the
> > + language of the driver name 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. Language is specified in
> > + RFC 4646 or ISO 639-2 language code format.
> > +
> > + @param ControllerName[out] 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
> > +DwMmcHcComponentNameGetControllerName (
> > + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> > + IN EFI_HANDLE ControllerHandle,
> > + IN EFI_HANDLE ChildHandle, OPTIONAL
> > + IN CHAR8 *Language,
> > + OUT CHAR16 **ControllerName
> > + );
> > +
> > +/**
> > + Create a new TRB for the SD/MMC cmd request.
> > +
> > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA
> instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command
> > + to.
> > + @param[in] Packet A pointer to the SD command data structure.
> > + @param[in] Event If Event is NULL, blocking I/O is performed.
> > + If Event is not NULL, then nonblocking I/O is
> > + performed, and Event will be signaled when the
> > + Packet completes.
> > +
> > + @return Created Trb or NULL.
> > +
> > +**/
> > +DW_MMC_HC_TRB *
> > +DwMmcCreateTrb (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private,
> > + IN UINT8 Slot,
> > + IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
> > + IN EFI_EVENT Event
> > + );
> > +
> > +/**
> > + Free the resource used by the TRB.
> > +
> > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> > +
> > +**/
> > +VOID
> > +DwMmcFreeTrb (
> > + IN DW_MMC_HC_TRB *Trb
> > + );
> > +
> > +/**
> > + Check if the env is ready for execute specified TRB.
> > +
> > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA
> instance.
> > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> > +
> > + @retval EFI_SUCCESS The env is ready for TRB execution.
> > + @retval EFI_NOT_READY The env is not ready for TRB execution.
> > + @retval Others Some erros happen.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcCheckTrbEnv (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private,
> > + IN DW_MMC_HC_TRB *Trb
> > + );
> > +
> > +/**
> > + Wait for the env to be ready for execute specified TRB.
> > +
> > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA
> instance.
> > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> > +
> > + @retval EFI_SUCCESS The env is ready for TRB execution.
> > + @retval EFI_TIMEOUT The env is not ready for TRB execution in time.
> > + @retval Others Some erros happen.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcWaitTrbEnv (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private,
> > + IN DW_MMC_HC_TRB *Trb
> > + );
> > +
> > +/**
> > + Execute the specified TRB.
> > +
> > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA
> instance.
> > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> > +
> > + @retval EFI_SUCCESS The TRB is sent to host controller successfully.
> > + @retval Others Some erros happen when sending this request to
> the
> > + host controller.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcExecTrb (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private,
> > + IN DW_MMC_HC_TRB *Trb
> > + );
> > +
> > +/**
> > + Check the TRB execution result.
> > +
> > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA
> instance.
> > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> > +
> > + @retval EFI_SUCCESS The TRB is executed successfully.
> > + @retval EFI_NOT_READY The TRB is not completed for execution.
> > + @retval Others Some erros happen when executing this request.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcCheckTrbResult (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private,
> > + IN DW_MMC_HC_TRB *Trb
> > + );
> > +
> > +/**
> > + Wait for the TRB execution result.
> > +
> > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA
> instance.
> > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> > +
> > + @retval EFI_SUCCESS The TRB is executed successfully.
> > + @retval Others Some erros happen when executing this request.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcWaitTrbResult (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private,
> > + IN DW_MMC_HC_TRB *Trb
> > + );
> > +
> > +/**
> > + Execute EMMC device identification procedure.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
> > +
> > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA
> instance.
> > +
> > + @retval EFI_SUCCESS There is a EMMC card.
> > + @retval Others There is not a EMMC card.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcIdentification (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private
> > + );
> > +
> > +/**
> > + Execute EMMC device identification procedure.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
> > +
> > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA
> instance.
> > +
> > + @retval EFI_SUCCESS There is a EMMC card.
> > + @retval Others There is not a EMMC card.
> > +
> > +**/
> > +EFI_STATUS
> > +SdCardIdentification (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private
> > + );
> > +
> > +#endif /* _DW_MMC_HC_DXE_H_ */
> > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
> b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
> > new file mode 100644
> > index 000000000000..12ef58a37368
> > --- /dev/null
> > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
> > @@ -0,0 +1,985 @@
> > +/** @file
> > +
> > + Provides some data structure definitions used by the SD/MMC host
> controller
> > + driver.
> > +
> > + Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
> > + Copyright (c) 2018, Linaro Ltd. 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 _DW_MMC_HCI_H_
> > +#define _DW_MMC_HCI_H_
> > +
> > +#include <Library/CacheMaintenanceLib.h>
> > +#include <Library/TimerLib.h>
> > +
> > +#include <Protocol/PlatformDwMmc.h>
> > +
> > +//
> > +// SD Host Controller SlotInfo Register Offset
> > +//
> > +#define DW_MMC_HC_SLOT_OFFSET 0x40
> > +
> > +#define DW_MMC_HC_MAX_SLOT 1
> > +
> > +//
> > +// SD Host Controller MMIO Register Offset
> > +//
> > +#define DW_MMC_CTRL 0x000
> > +#define DW_MMC_PWREN 0x004
> > +#define DW_MMC_CLKDIV 0x008
> > +#define DW_MMC_CLKSRC 0x00c
> > +#define DW_MMC_CLKENA 0x010
> > +#define DW_MMC_TMOUT 0x014
> > +#define DW_MMC_CTYPE 0x018
> > +#define DW_MMC_BLKSIZ 0x01c
> > +#define DW_MMC_BYTCNT 0x020
> > +#define DW_MMC_INTMASK 0x024
> > +#define DW_MMC_CMDARG 0x028
> > +#define DW_MMC_CMD 0x02c
> > +#define DW_MMC_RESP0 0x030
> > +#define DW_MMC_RESP1 0x034
> > +#define DW_MMC_RESP2 0x038
> > +#define DW_MMC_RESP3 0x03c
> > +#define DW_MMC_RINTSTS 0x044
> > +#define DW_MMC_STATUS 0x048
> > +#define DW_MMC_FIFOTH 0x04c
> > +#define DW_MMC_GPIO 0x058
> > +#define DW_MMC_DEBNCE 0x064
> > +#define DW_MMC_USRID 0x068
> > +#define DW_MMC_VERID 0x06c
> > +#define DW_MMC_HCON 0x070
> > +#define DW_MMC_UHSREG 0x074
> > +#define DW_MMC_BMOD 0x080
> > +#define DW_MMC_DBADDR 0x088
> > +#define DW_MMC_IDSTS 0x08c
> > +#define DW_MMC_IDINTEN 0x090
> > +#define DW_MMC_DSCADDR 0x094
> > +#define DW_MMC_BUFADDR 0x098
> > +#define DW_MMC_CARDTHRCTL 0x100
> > +#define DW_MMC_UHSREG_EXT 0x108
> > +#define DW_MMC_ENABLE_SHIFT 0x110
> > +#define DW_MMC_FIFO_START 0x200
> > +
> > +#define GET_IDSTS_DMAC_FSM(x) (((x) >> 13) & 0xf)
> > +#define IDSTS_FSM_DMA_IDLE 0
> > +#define IDSTS_FSM_DMA_SUSPEND 1
> > +#define IDSTS_FSM_DESC_RD 2
> > +#define IDSTS_FSM_DESC_CHK 3
> > +#define IDSTS_FSM_DMA_RD_REQ_WAIT 4
> > +#define IDSTS_FSM_DMA_WR_REQ_WAIT 5
> > +#define IDSTS_FSM_DMA_RD 6
> > +#define IDSTS_FSM_DMA_WR 7
> > +#define IDSTS_FSM_DESC_CLOSE 8
> > +#define IDSTS_FSM_MASK 0xf
> > +
> > +#define CMD_UPDATE_CLK 0x80202000
> > +#define CMD_START_BIT (1 << 31)
> > +
> > +#define MMC_8BIT_MODE (1 << 16)
> > +#define MMC_4BIT_MODE (1 << 0)
> > +#define MMC_1BIT_MODE 0
> > +
> > +#define DW_MMC_BLOCK_SIZE 512
> > +
> > +#define CMD_INDEX_MASK 0x3F
> > +#define BIT_CMD_RESPONSE_EXPECT (1 << 6)
> > +#define BIT_CMD_LONG_RESPONSE (1 << 7)
> > +#define BIT_CMD_CHECK_RESPONSE_CRC (1 << 8)
> > +#define BIT_CMD_DATA_EXPECTED (1 << 9)
> > +#define BIT_CMD_READ (0 << 10)
> > +#define BIT_CMD_WRITE (1 << 10)
> > +#define BIT_CMD_BLOCK_TRANSFER (0 << 11)
> > +#define BIT_CMD_STREAM_TRANSFER (1 << 11)
> > +#define BIT_CMD_SEND_AUTO_STOP (1 << 12)
> > +#define BIT_CMD_WAIT_PRVDATA_COMPLETE (1 << 13)
> > +#define BIT_CMD_STOP_ABORT_CMD (1 << 14)
> > +#define BIT_CMD_SEND_INIT (1 << 15)
> > +#define BIT_CMD_UPDATE_CLOCK_ONLY (1 << 21)
> > +#define BIT_CMD_READ_CEATA_DEVICE (1 << 22)
> > +#define BIT_CMD_CCS_EXPECTED (1 << 23)
> > +#define BIT_CMD_ENABLE_BOOT (1 << 24)
> > +#define BIT_CMD_EXPECT_BOOT_ACK (1 << 25)
> > +#define BIT_CMD_DISABLE_BOOT (1 << 26)
> > +#define BIT_CMD_MANDATORY_BOOT (0 << 27)
> > +#define BIT_CMD_ALTERNATE_BOOT (1 << 27)
> > +#define BIT_CMD_VOLT_SWITCH (1 << 28)
> > +#define BIT_CMD_USE_HOLD_REG (1 << 29)
> > +#define BIT_CMD_START (1 << 31)
> > +
> > +#define CMD_INDEX(x) ((x) & CMD_INDEX_MASK)
> > +
> > +#define DW_MMC_INT_EBE (1 << 15) /* End-bit Err */
> > +#define DW_MMC_INT_SBE (1 << 13) /* Start-bit Err */
> > +#define DW_MMC_INT_HLE (1 << 12) /* Hardware-lock
> Err */
> > +#define DW_MMC_INT_FRUN (1 << 11) /* FIFO UN/OV
> RUN */
> > +#define DW_MMC_INT_DRT (1 << 9) /* Data timeout */
> > +#define DW_MMC_INT_RTO (1 << 8) /* Response
> timeout */
> > +#define DW_MMC_INT_DCRC (1 << 7) /* Data CRC err */
> > +#define DW_MMC_INT_RCRC (1 << 6) /* Response CRC
> err */
> > +#define DW_MMC_INT_RXDR (1 << 5) /* Receive FIFO
> data request */
> > +#define DW_MMC_INT_TXDR (1 << 4) /* Transmit FIFO
> data request */
> > +#define DW_MMC_INT_DTO (1 << 3) /* Data trans over
> */
> > +#define DW_MMC_INT_CMD_DONE (1 << 2) /* Command
> done */
> > +#define DW_MMC_INT_RE (1 << 1) /* Response error */
> > +
> > +#define DW_MMC_IDMAC_DES0_DIC (1 << 1)
> > +#define DW_MMC_IDMAC_DES0_LD (1 << 2)
> > +#define DW_MMC_IDMAC_DES0_FS (1 << 3)
> > +#define DW_MMC_IDMAC_DES0_CH (1 << 4)
> > +#define DW_MMC_IDMAC_DES0_ER (1 << 5)
> > +#define DW_MMC_IDMAC_DES0_CES (1 << 30)
> > +#define DW_MMC_IDMAC_DES0_OWN (1 << 31)
> > +#define DW_MMC_IDMAC_DES1_BS1(x) ((x) & 0x1fff)
> > +#define DW_MMC_IDMAC_DES2_BS2(x) (((x) & 0x1fff) << 13)
> > +#define DW_MMC_IDMAC_SWRESET (1 << 0)
> > +#define DW_MMC_IDMAC_FB (1 << 1)
> > +#define DW_MMC_IDMAC_ENABLE (1 << 7)
> > +
> > +#define DW_MMC_CTRL_RESET (1 << 0)
> > +#define DW_MMC_CTRL_FIFO_RESET (1 << 1)
> > +#define DW_MMC_CTRL_DMA_RESET (1 << 2)
> > +#define DW_MMC_CTRL_INT_EN (1 << 4)
> > +#define DW_MMC_CTRL_DMA_EN (1 << 5)
> > +#define DW_MMC_CTRL_IDMAC_EN (1 << 25)
> > +#define DW_MMC_CTRL_RESET_ALL (DW_MMC_CTRL_RESET |
> DW_MMC_CTRL_FIFO_RESET | DW_MMC_CTRL_DMA_RESET)
> > +
> > +#define DW_MMC_STS_DATA_BUSY (1 << 9)
> > +#define DW_MMC_STS_FIFO_COUNT(x) (((x) & 0x1fff) << 17) /*
> Number of filled locations in FIFO */
> > +#define GET_STS_FIFO_COUNT(x) (((x) >> 17) & 0x1fff)
> > +#define DW_MMC_STS_FIFO_FULL(x) (((x) >> 3) & 1)
> > +
> > +#define DW_MMC_BMOD_SWR (1 << 0) /* Software
> Reset */
> > +#define DW_MMC_BMOD_FB (1 << 1) /* Fix Burst */
> > +#define DW_MMC_BMOD_DE (1 << 7) /* IDMAC Enable
> */
> > +
> > +#define DW_MMC_IDSTS_TI (1 << 0) /* Transmit
> Interrupt */
> > +#define DW_MMC_IDSTS_RI (1 << 1) /* Receive Interrupt
> */
> > +
> > +#define DW_MMC_FIFO_TWMARK(x) ((x) & 0xfff)
> > +#define DW_MMC_FIFO_RWMARK(x) (((x) & 0x1ff) << 16)
> > +#define DW_MMC_DMA_BURST_SIZE(x) (((x) & 0x7) << 28)
> > +
> > +#define DW_MMC_CARD_RD_THR(x) (((x) & 0xfff) << 16)
> > +#define DW_MMC_CARD_RD_THR_EN (1 << 0)
> > +
> > +#define UHS_DDR_MODE (1 << 16)
> > +
> > +#define GENCLK_DIV 7
> > +
> > +#define DW_MMC_GPIO_CLK_DIV(x) (((x) & 0xf) << 8)
> > +#define DW_MMC_GPIO_USE_SAMPLE_DLY(x) (((x) & 1) << 13)
> > +#define DW_MMC_GPIO_CLK_ENABLE BIT16
> > +
> > +#define UHSEXT_SAMPLE_PHASE(x) (((x) & 0x1f) << 16)
> > +#define UHSEXT_SAMPLE_DRVPHASE(x) (((x) & 0x1f) << 21)
> > +#define UHSEXT_SAMPLE_DLY(x) (((x) & 0x1f) << 26)
> > +
> > +#define DWMMC_DMA_BUF_SIZE (512 * 8)
> > +#define DWMMC_FIFO_THRESHOLD 16
> > +
> > +#define DWMMC_INIT_CLOCK_FREQ 400 /* KHz */
> > +
> > +//
> > +// The transfer modes supported by SD Host Controller
> > +// Simplified Spec 3.0 Table 1-2
> > +//
> > +typedef enum {
> > + SdMmcNoData,
> > + SdMmcPioMode,
> > + SdMmcSdmaMode,
> > + SdMmcAdmaMode
> > +} DW_MMC_HC_TRANSFER_MODE;
> > +
> > +//
> > +// The maximum data length of each descriptor line
> > +//
> > +#define ADMA_MAX_DATA_PER_LINE 0x10000
> > +
> > +typedef struct {
> > + UINT32 Des0;
> > + UINT32 Des1;
> > + UINT32 Des2;
> > + UINT32 Des3;
> > +} DW_MMC_HC_DMA_DESC_LINE;
> > +
> > +#define SD_MMC_SDMA_BOUNDARY 512 * 1024
> > +#define SD_MMC_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1))
> > +
> > +typedef struct {
> > + UINT8 FirstBar:3; // bit 0:2
> > + UINT8 Reserved:1; // bit 3
> > + UINT8 SlotNum:3; // bit 4:6
> > + UINT8 Reserved1:1; // bit 7
> > +} DW_MMC_HC_SLOT_INFO;
> > +
> > +/**
> > + Dump the content of SD/MMC host controller's Capability Register.
> > +
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > + @param[in] Capability The buffer to store the capability data.
> > +
> > +**/
> > +VOID
> > +DumpCapabilityReg (
> > + IN UINT8 Slot,
> > + IN DW_MMC_HC_SLOT_CAP *Capability
> > + );
> > +
> > +#if 0
> > +/**
> > + Read SlotInfo register from SD/MMC host controller pci config space.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[out] FirstBar The buffer to store the first BAR value.
> > + @param[out] SlotNum The buffer to store the supported slot number.
> > +
> > + @retval EFI_SUCCESS The operation succeeds.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcHcGetSlotInfo (
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + OUT UINT8 *FirstBar,
> > + OUT UINT8 *SlotNum
> > + );
> > +#endif
> > +
> > +#ifdef DWMMC_PCI
> > +/**
> > + Read/Write specified SD/MMC host controller mmio register.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[in] BarIndex The BAR index of the standard PCI
> Configuration
> > + header to use as the base address for the memory
> > + operation to perform.
> > + @param[in] Offset The offset within the selected BAR to start the
> > + memory operation.
> > + @param[in] Read A boolean to indicate it's read or write
> operation.
> > + @param[in] Count The width of the mmio register in bytes.
> > + Must be 1, 2 , 4 or 8 bytes.
> > + @param[in, out] Data For read operations, the destination buffer to
> store
> > + the results. For write operations, the source buffer
> > + to write data from. The caller is responsible for
> > + having ownership of the data buffer and ensuring its
> > + size not less than Count bytes.
> > +
> > + @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count
> is not valid.
> > + @retval EFI_SUCCESS The read/write operation succeeds.
> > + @retval Others The read/write operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcHcRwMmio (
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + IN UINT8 BarIndex,
> > + IN UINT32 Offset,
> > + IN BOOLEAN Read,
> > + IN UINT8 Count,
> > + IN OUT VOID *Data
> > + );
> > +#else
> > +/**
> > + Read/Write specified SD/MMC host controller mmio register.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] Offset The offset within the selected BAR to start the
> > + memory operation.
> > + @param[in] Read A boolean to indicate it's read or write
> operation.
> > + @param[in] Count The width of the mmio register in bytes.
> > + Must be 1, 2 , 4 or 8 bytes.
> > + @param[in, out] Data For read operations, the destination buffer to
> store
> > + the results. For write operations, the source buffer
> > + to write data from. The caller is responsible for
> > + having ownership of the data buffer and ensuring its
> > + size not less than Count bytes.
> > +
> > + @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count
> is not valid.
> > + @retval EFI_SUCCESS The read/write operation succeeds.
> > + @retval Others The read/write operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcHcRwMmio (
> > + IN UINTN DevBase,
> > + IN UINT32 Offset,
> > + IN BOOLEAN Read,
> > + IN UINT8 Count,
> > + IN OUT VOID *Data
> > + );
> > +#endif
> > +
> > +#ifdef DWMMC_PCI
> > +/**
> > + Do OR operation with the value of the specified SD/MMC host controller
> mmio register.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[in] BarIndex The BAR index of the standard PCI
> Configuration
> > + header to use as the base address for the memory
> > + operation to perform.
> > + @param[in] Offset The offset within the selected BAR to start the
> > + memory operation.
> > + @param[in] Count The width of the mmio register in bytes.
> > + Must be 1, 2 , 4 or 8 bytes.
> > + @param[in] OrData The pointer to the data used to do OR
> operation.
> > + The caller is responsible for having ownership of
> > + the data buffer and ensuring its size not less than
> > + Count bytes.
> > +
> > + @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the
> Count is not valid.
> > + @retval EFI_SUCCESS The OR operation succeeds.
> > + @retval Others The OR operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcHcOrMmio (
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + IN UINT8 BarIndex,
> > + IN UINT32 Offset,
> > + IN UINT8 Count,
> > + IN VOID *OrData
> > + );
> > +#else
> > +/**
> > + Do OR operation with the value of the specified SD/MMC host controller
> mmio register.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] BarIndex The BAR index of the standard PCI
> Configuration
> > + header to use as the base address for the memory
> > + operation to perform.
> > + @param[in] Offset The offset within the selected BAR to start the
> > + memory operation.
> > + @param[in] Count The width of the mmio register in bytes.
> > + Must be 1, 2 , 4 or 8 bytes.
> > + @param[in] OrData The pointer to the data used to do OR
> operation.
> > + The caller is responsible for having ownership of
> > + the data buffer and ensuring its size not less than
> > + Count bytes.
> > +
> > + @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the
> Count is not valid.
> > + @retval EFI_SUCCESS The OR operation succeeds.
> > + @retval Others The OR operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcHcOrMmio (
> > + IN UINTN DevBase,
> > + IN UINT32 Offset,
> > + IN UINT8 Count,
> > + IN VOID *OrData
> > + );
> > +#endif
> > +
> > +#ifdef DWMMC_PCI
> > +/**
> > + Do AND operation with the value of the specified SD/MMC host
> controller mmio register.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[in] BarIndex The BAR index of the standard PCI
> Configuration
> > + header to use as the base address for the memory
> > + operation to perform.
> > + @param[in] Offset The offset within the selected BAR to start the
> > + memory operation.
> > + @param[in] Count The width of the mmio register in bytes.
> > + Must be 1, 2 , 4 or 8 bytes.
> > + @param[in] AndData The pointer to the data used to do AND
> operation.
> > + The caller is responsible for having ownership of
> > + the data buffer and ensuring its size not less than
> > + Count bytes.
> > +
> > + @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the
> Count is not valid.
> > + @retval EFI_SUCCESS The AND operation succeeds.
> > + @retval Others The AND operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcHcAndMmio (
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + IN UINT8 BarIndex,
> > + IN UINT32 Offset,
> > + IN UINT8 Count,
> > + IN VOID *AndData
> > + );
> > +#else
> > +/**
> > + Do AND operation with the value of the specified SD/MMC host
> controller mmio register.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] Offset The offset within the selected BAR to start the
> > + memory operation.
> > + @param[in] Count The width of the mmio register in bytes.
> > + Must be 1, 2 , 4 or 8 bytes.
> > + @param[in] AndData The pointer to the data used to do AND
> operation.
> > + The caller is responsible for having ownership of
> > + the data buffer and ensuring its size not less than
> > + Count bytes.
> > +
> > + @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the
> Count is not valid.
> > + @retval EFI_SUCCESS The AND operation succeeds.
> > + @retval Others The AND operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcHcAndMmio (
> > + IN UINTN DevBase,
> > + IN UINT32 Offset,
> > + IN UINT8 Count,
> > + IN VOID *AndData
> > + );
> > +#endif
> > +
> > +#ifdef DWMMC_PCI
> > +/**
> > + Wait for the value of the specified MMIO register set to the test value.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[in] BarIndex The BAR index of the standard PCI
> Configuration
> > + header to use as the base address for the memory
> > + operation to perform.
> > + @param[in] Offset The offset within the selected BAR to start the
> > + memory operation.
> > + @param[in] Count The width of the mmio register in bytes.
> > + Must be 1, 2, 4 or 8 bytes.
> > + @param[in] MaskValue The mask value of memory.
> > + @param[in] TestValue The test value of memory.
> > + @param[in] Timeout The time out value for wait memory set, uses 1
> > + microsecond as a unit.
> > +
> > + @retval EFI_TIMEOUT The MMIO register hasn't expected value in
> timeout
> > + range.
> > + @retval EFI_SUCCESS The MMIO register has expected value.
> > + @retval Others The MMIO operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcHcWaitMmioSet (
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + IN UINT8 BarIndex,
> > + IN UINT32 Offset,
> > + IN UINT8 Count,
> > + IN UINT64 MaskValue,
> > + IN UINT64 TestValue,
> > + IN UINT64 Timeout
> > + );
> > +#else
> > +/**
> > + Wait for the value of the specified MMIO register set to the test value.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] Offset The offset within the selected BAR to start the
> > + memory operation.
> > + @param[in] Count The width of the mmio register in bytes.
> > + Must be 1, 2, 4 or 8 bytes.
> > + @param[in] MaskValue The mask value of memory.
> > + @param[in] TestValue The test value of memory.
> > + @param[in] Timeout The time out value for wait memory set, uses 1
> > + microsecond as a unit.
> > +
> > + @retval EFI_TIMEOUT The MMIO register hasn't expected value in
> timeout
> > + range.
> > + @retval EFI_SUCCESS The MMIO register has expected value.
> > + @retval Others The MMIO operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcHcWaitMmioSet (
> > + IN UINTN DevBase,
> > + IN UINT32 Offset,
> > + IN UINT8 Count,
> > + IN UINT64 MaskValue,
> > + IN UINT64 TestValue,
> > + IN UINT64 Timeout
> > + );
> > +#endif
> > +
> > +#ifdef DWMMC_PCI
> > +/**
> > + Software reset the specified SD/MMC host controller.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > +
> > + @retval EFI_SUCCESS The software reset executes successfully.
> > + @retval Others The software reset fails.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcReset (
> > +fark
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + IN UINT8 Slot,
> > + IN DW_MMC_HC_SLOT_CAP Capability
> > + );
> > +#else
> > +/**
> > + Software reset the specified SD/MMC host controller.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > +
> > + @retval EFI_SUCCESS The software reset executes successfully.
> > + @retval Others The software reset fails.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcReset (
> > + IN UINTN DevBase,
> > + IN DW_MMC_HC_SLOT_CAP Capability
> > + );
> > +#endif
> > +
> > +#ifdef DWMMC_PCI
> > +/**
> > + Set all interrupt status bits in Normal and Error Interrupt Status Enable
> > + register.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > +
> > + @retval EFI_SUCCESS The operation executes successfully.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcEnableInterrupt (
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + IN UINT8 Slot
> > + );
> > +#else
> > +/**
> > + Set all interrupt status bits in Normal and Error Interrupt Status Enable
> > + register.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > +
> > + @retval EFI_SUCCESS The operation executes successfully.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcEnableInterrupt (
> > + IN UINTN DevBase
> > + );
> > +#endif
> > +
> > +#ifdef DWMMC_PCI
> > +/**
> > + Get the capability data from the specified slot.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > + @param[out] Capability The buffer to store the capability data.
> > +
> > + @retval EFI_SUCCESS The operation executes successfully.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcGetCapability (
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + IN EFI_HANDLE Controller,
> > + IN UINT8 Slot,
> > + OUT DW_MMC_HC_SLOT_CAP *Capability
> > + );
> > +#else
> > +/**
> > + Get the capability data from the specified slot.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > + @param[out] Capability The buffer to store the capability data.
> > +
> > + @retval EFI_SUCCESS The operation executes successfully.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcGetCapability (
> > + IN UINTN DevBase,
> > + IN EFI_HANDLE Controller,
> > + IN UINT8 Slot,
> > + OUT DW_MMC_HC_SLOT_CAP *Capability
> > + );
> > +#endif
> > +
> > +#if 0
> > +/**
> > + Get the maximum current capability data from the specified slot.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > + @param[out] MaxCurrent The buffer to store the maximum current
> capability data.
> > +
> > + @retval EFI_SUCCESS The operation executes successfully.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcGetMaxCurrent (
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + IN UINT8 Slot,
> > + OUT UINT64 *MaxCurrent
> > + );
> > +#endif
> > +
> > +#ifdef DWMMC_PCI
> > +/**
> > + Detect whether there is a SD/MMC card attached at the specified
> SD/MMC host controller
> > + slot.
> > +
> > + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > + @param[out] MediaPresent The pointer to the media present boolean
> value.
> > +
> > + @retval EFI_SUCCESS There is no media change happened.
> > + @retval EFI_MEDIA_CHANGED There is media change happened.
> > + @retval Others The detection fails.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcCardDetect (
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + IN EFI_HANDLE Controller,
> > + IN UINT8 Slot,
> > + OUT BOOLEAN *MediaPresent
> > + );
> > +#else
> > +/**
> > + Detect whether there is a SD/MMC card attached at the specified
> SD/MMC host controller
> > + slot.
> > +
> > + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > + @param[out] MediaPresent The pointer to the media present boolean
> value.
> > +
> > + @retval EFI_SUCCESS There is no media change happened.
> > + @retval EFI_MEDIA_CHANGED There is media change happened.
> > + @retval Others The detection fails.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcCardDetect (
> > + IN UINTN DevBase,
> > + IN EFI_HANDLE Controller,
> > + IN UINT8 Slot,
> > + OUT BOOLEAN *MediaPresent
> > + );
> > +#endif
> > +
> > +#ifdef DWMMC_PCI
> > +/**
> > + Stop SD/MMC card clock.
> > +
> > + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > +
> > + @retval EFI_SUCCESS Succeed to stop SD/MMC clock.
> > + @retval Others Fail to stop SD/MMC clock.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcStopClock (
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + IN UINT8 Slot
> > + );
> > +
> > +/**
> > + SD/MMC card clock supply.
> > +
> > + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > + @param[in] ClockFreq The max clock frequency to be set. The unit is
> KHz.
> > + @param[in] Capability The capability of the slot.
> > +
> > + @retval EFI_SUCCESS The clock is supplied successfully.
> > + @retval Others The clock isn't supplied successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcClockSupply (
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + IN UINT8 Slot,
> > + IN UINT64 ClockFreq,
> > + IN DW_MMC_HC_SLOT_CAP Capability
> > + );
> > +#else
> > +/**
> > + Stop SD/MMC card clock.
> > +
> > + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > +
> > + @retval EFI_SUCCESS Succeed to stop SD/MMC clock.
> > + @retval Others Fail to stop SD/MMC clock.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcStopClock (
> > + IN UINTN DevBase
> > + );
> > +
> > +/**
> > + SD/MMC card clock supply.
> > +
> > + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] ClockFreq The max clock frequency to be set. The unit is
> KHz.
> > + @param[in] Capability The capability of the slot.
> > +
> > + @retval EFI_SUCCESS The clock is supplied successfully.
> > + @retval Others The clock isn't supplied successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcClockSupply (
> > + IN UINTN DevBase,
> > + IN UINT64 ClockFreq,
> > + IN DW_MMC_HC_SLOT_CAP Capability
> > + );
> > +#endif
> > +
> > +#if 0
> > +/**
> > + SD/MMC bus power control.
> > +
> > + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > + @param[in] PowerCtrl The value setting to the power control register.
> > +
> > + @retval TRUE There is a SD/MMC card attached.
> > + @retval FALSE There is no a SD/MMC card attached.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcPowerControl (
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + IN UINT8 Slot,
> > + IN UINT8 PowerCtrl
> > + );
> > +#endif
> > +
> > +#ifdef DWMMC_PCI
> > +/**
> > + Set the SD/MMC bus width.
> > +
> > + Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > + @param[in] BusWidth The bus width used by the SD/MMC device, it
> must be 1, 4 or 8.
> > +
> > + @retval EFI_SUCCESS The bus width is set successfully.
> > + @retval Others The bus width isn't set successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcSetBusWidth (
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + IN UINT8 Slot,
> > + IN BOOLEAN IsDdr,
> > + IN UINT16 BusWidth
> > + );
> > +#else
> > +/**
> > + Set the SD/MMC bus width.
> > +
> > + Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] BusWidth The bus width used by the SD/MMC device, it
> must be 1, 4 or 8.
> > +
> > + @retval EFI_SUCCESS The bus width is set successfully.
> > + @retval Others The bus width isn't set successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcSetBusWidth (
> > + IN UINTN DevBase,
> > + IN BOOLEAN IsDdr,
> > + IN UINT16 BusWidth
> > + );
> > +#endif
> > +
> > +#ifdef DWMMC_PCI
> > +/**
> > + Supply SD/MMC card with lowest clock frequency at initialization.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > + @param[in] Capability The capability of the slot.
> > +
> > + @retval EFI_SUCCESS The clock is supplied successfully.
> > + @retval Others The clock isn't supplied successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcInitClockFreq (
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + IN UINT8 Slot,
> > + IN DW_MMC_HC_SLOT_CAP Capability
> > + );
> > +#else
> > +/**
> > + Supply SD/MMC card with lowest clock frequency at initialization.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] Capability The capability of the slot.
> > +
> > + @retval EFI_SUCCESS The clock is supplied successfully.
> > + @retval Others The clock isn't supplied successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcInitClockFreq (
> > + IN UINTN DevBase,
> > + IN DW_MMC_HC_SLOT_CAP Capability
> > + );
> > +#endif
> > +
> > +#ifdef DWMMC_PCI
> > +/**
> > + Supply SD/MMC card with maximum voltage at initialization.
> > +
> > + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > + @param[in] Capability The capability of the slot.
> > +
> > + @retval EFI_SUCCESS The voltage is supplied successfully.
> > + @retval Others The voltage isn't supplied successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcInitPowerVoltage (
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + IN UINT8 Slot,
> > + IN DW_MMC_HC_SLOT_CAP Capability
> > + );
> > +#else
> > +/**
> > + Supply SD/MMC card with maximum voltage at initialization.
> > +
> > + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] Capability The capability of the slot.
> > +
> > + @retval EFI_SUCCESS The voltage is supplied successfully.
> > + @retval Others The voltage isn't supplied successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcInitPowerVoltage (
> > + IN UINTN DevBase,
> > + IN DW_MMC_HC_SLOT_CAP Capability
> > + );
> > +#endif
> > +
> > +#ifdef DWMMC_PCI
> > +/**
> > + Initialize the Timeout Control register with most conservative value at
> initialization.
> > +
> > + Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > +
> > + @retval EFI_SUCCESS The timeout control register is configured
> successfully.
> > + @retval Others The timeout control register isn't configured
> successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcInitTimeoutCtrl (
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + IN UINT8 Slot
> > + );
> > +#else
> > +/**
> > + Initialize the Timeout Control register with most conservative value at
> initialization.
> > +
> > + Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > +
> > + @retval EFI_SUCCESS The timeout control register is configured
> successfully.
> > + @retval Others The timeout control register isn't configured
> successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcInitTimeoutCtrl (
> > + IN UINTN DevBase
> > + );
> > +#endif
> > +
> > +#ifdef DWMMC_PCI
> > +/**
> > + Initial SD/MMC host controller with lowest clock frequency, max power
> and max timeout value
> > + at initialization.
> > +
> > + @param[in] PciIo The PCI IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command to.
> > + @param[in] Capability The capability of the slot.
> > +
> > + @retval EFI_SUCCESS The host controller is initialized successfully.
> > + @retval Others The host controller isn't initialized successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcInitHost (
> > + IN EFI_PCI_IO_PROTOCOL *PciIo,
> > + IN UINT8 Slot,
> > + IN DW_MMC_HC_SLOT_CAP Capability
> > + );
> > +#else
> > +/**
> > + Initial SD/MMC host controller with lowest clock frequency, max power
> and
> > + max timeout value at initialization.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] Capability The capability of the slot.
> > +
> > + @retval EFI_SUCCESS The host controller is initialized successfully.
> > + @retval Others The host controller isn't initialized successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcInitHost (
> > + IN UINTN DevBase,
> > + IN DW_MMC_HC_SLOT_CAP Capability
> > + );
> > +#endif
> > +
> > +#endif /* _DW_MMC_HCI_H_ */
> > diff --git a/EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
> b/EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
> > new file mode 100644
> > index 000000000000..acbc3e153dac
> > --- /dev/null
> > +++ b/EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
> > @@ -0,0 +1,79 @@
> > +/** @file
> > +
> > + Copyright (c) 2018, Linaro. All rights reserved.
> > +
> > + This program and the accompanying materials are licensed and made
> available
> > + under the terms and conditions of the BSD License which accompanies
> this
> > + distribution. The full text of the license may be found at
> > + http://opensource.org/licenses/bsd-license.php
> > +
> > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> > +
> > +**/
> > +
> > +#ifndef __PLATFORM_DW_MMC_H__
> > +#define __PLATFORM_DW_MMC_H__
> > +
> > +typedef enum {
> > + RemovableSlot,
> > + EmbeddedSlot,
> > + SharedBusSlot,
> > + UnknownSlot
> > +} EFI_SD_MMC_SLOT_TYPE;
> > +
> > +typedef enum {
> > + UnknownCardType,
> > + SdCardType,
> > + SdioCardType,
> > + MmcCardType,
> > + EmmcCardType
> > +} SD_MMC_CARD_TYPE;
> > +
> > +typedef struct {
> > + UINT32 DefaultSpeed:1; // bit 0
> > + UINT32 HighSpeed:1; // bit 1
> > + UINT32 Sdr12:1; // bit 2
> > + UINT32 Sdr25:1; // bit 3
> > + UINT32 Sdr50:1; // bit 4
> > + UINT32 Sdr104:1; // bit 5
> > + UINT32 Ddr50:1; // bit 6
> > + UINT32 SysBus64:1; // bit 7
> > + UINT32 BusWidth:4; // bit 11:8
> > + UINT32 SlotType:2; // bit 13:12
> > + UINT32 CardType:3; // bit 16:14
> > + UINT32 Voltage18:1; // bit 17
> > + UINT32 Voltage30:1; // bit 18
> > + UINT32 Voltage33:1; // bit 19
> > + UINT32 BaseClkFreq;
> > + EFI_HANDLE Controller;
> > +} DW_MMC_HC_SLOT_CAP;
> > +
> > +//
> > +// Protocol interface structure
> > +//
> > +typedef struct _PLATFORM_DW_MMC_PROTOCOL
> PLATFORM_DW_MMC_PROTOCOL;
> > +
> > +typedef
> > +EFI_STATUS
> > +(EFIAPI *PLATFORM_DW_MMC_GET_CAPABILITY) (
> > + IN EFI_HANDLE Controller,
> > + IN UINT8 Slot,
> > + OUT DW_MMC_HC_SLOT_CAP *Capability
> > + );
> > +
> > +typedef
> > +BOOLEAN
> > +(EFIAPI *PLATFORM_DW_MMC_CARD_DETECT) (
> > + IN EFI_HANDLE Controller,
> > + IN UINT8 Slot
> > + );
> > +
> > +struct _PLATFORM_DW_MMC_PROTOCOL {
> > + PLATFORM_DW_MMC_GET_CAPABILITY GetCapability;
> > + PLATFORM_DW_MMC_CARD_DETECT CardDetect;
> > +};
> > +
> > +extern EFI_GUID gPlatformDwMmcProtocolGuid;
> > +
> > +#endif /* __PLATFORM_DW_MMC_H__ */
> > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
> b/EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
> > new file mode 100644
> > index 000000000000..1edade69d091
> > --- /dev/null
> > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
> > @@ -0,0 +1,214 @@
> > +/** @file
> > + UEFI Component Name(2) protocol implementation for Designware
> SD/MMC host
> > + controller driver.
> > +
> > + Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
> > + Copyright (c) 2018, Linaro Ltd. 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 "DwMmcHcDxe.h"
> > +
> > +//
> > +// EFI Component Name Protocol
> > +//
> > +GLOBAL_REMOVE_IF_UNREFERENCED
> EFI_COMPONENT_NAME_PROTOCOL gDwMmcHcComponentName = {
> > + DwMmcHcComponentNameGetDriverName,
> > + DwMmcHcComponentNameGetControllerName,
> > + "eng"
> > +};
> > +
> > +//
> > +// EFI Component Name 2 Protocol
> > +//
> > +GLOBAL_REMOVE_IF_UNREFERENCED
> EFI_COMPONENT_NAME2_PROTOCOL gDwMmcHcComponentName2 = {
> > + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)
> DwMmcHcComponentNameGetDriverName,
> > + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)
> DwMmcHcComponentNameGetControllerName,
> > + "en"
> > +};
> > +
> > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
> mDwMmcHcDriverNameTable[] = {
> > + { "eng;en", L"Designware Sd/Mmc Host Controller Driver" },
> > + { NULL , NULL }
> > +};
> > +
> > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
> mDwMmcHcControllerNameTable[] = {
> > + { "eng;en", L"Designware Sd/Mmc Host Controller" },
> > + { NULL , NULL }
> > +};
> > +
> > +/**
> > + Retrieves a Unicode string that is the user readable name of the driver.
> > +
> > + This function retrieves the user readable name of a driver in the form of
> a
> > + Unicode string. If the driver specified by This has a user readable name in
> > + the language specified by Language, then a pointer to the driver name is
> > + returned in DriverName, and EFI_SUCCESS is returned. If the driver
> specified
> > + by This does not support the language specified by Language,
> > + then EFI_UNSUPPORTED is returned.
> > +
> > + @param This[in] A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> > + EFI_COMPONENT_NAME_PROTOCOL instance.
> > +
> > + @param Language[in] A pointer to a Null-terminated ASCII string
> > + array indicating the language. This is the
> > + language of the driver name 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. Language is specified
> > + in RFC 4646 or ISO 639-2 language code format.
> > +
> > + @param DriverName[out] 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
> > +DwMmcHcComponentNameGetDriverName (
> > + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> > + IN CHAR8 *Language,
> > + OUT CHAR16 **DriverName
> > + )
> > +{
> > + return LookupUnicodeString2 (
> > + Language,
> > + This->SupportedLanguages,
> > + mDwMmcHcDriverNameTable,
> > + DriverName,
> > + (BOOLEAN)(This == &gDwMmcHcComponentName)
> > + );
> > +}
> > +
> > +/**
> > + Retrieves a Unicode string that is the user readable name of the
> controller
> > + that is being managed by a driver.
> > +
> > + This function retrieves the user readable name of the controller specified
> by
> > + ControllerHandle and ChildHandle in the form of a Unicode string. If the
> > + driver specified by This has a user readable name in the language
> specified by
> > + Language, then a pointer to the controller name is returned in
> ControllerName,
> > + and EFI_SUCCESS is returned. If the driver specified by This is not
> currently
> > + managing the controller specified by ControllerHandle and ChildHandle,
> > + then EFI_UNSUPPORTED is returned. If the driver specified by This does
> not
> > + support the language specified by Language, then EFI_UNSUPPORTED is
> returned.
> > +
> > + @param This[in] A pointer to the
> EFI_COMPONENT_NAME2_PROTOCOL or
> > + EFI_COMPONENT_NAME_PROTOCOL instance.
> > +
> > + @param ControllerHandle[in] 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 ChildHandle[in] 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 Language[in] A pointer to a Null-terminated ASCII string
> > + array indicating the language. This is the
> > + language of the driver name 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. Language is specified in
> > + RFC 4646 or ISO 639-2 language code format.
> > +
> > + @param ControllerName[out] 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
> > +DwMmcHcComponentNameGetControllerName (
> > + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> > + IN EFI_HANDLE ControllerHandle,
> > + IN EFI_HANDLE ChildHandle, OPTIONAL
> > + IN CHAR8 *Language,
> > + OUT CHAR16 **ControllerName
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + if (Language == NULL || ControllerName == NULL) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + //
> > + // This is a device driver, so ChildHandle must be NULL.
> > + //
> > + if (ChildHandle != NULL) {
> > + return EFI_UNSUPPORTED;
> > + }
> > +
> > + //
> > + // Make sure this driver is currently managing ControllerHandle
> > + //
> > + Status = EfiTestManagedDevice (
> > + ControllerHandle,
> > + gDwMmcHcDriverBinding.DriverBindingHandle,
> > + &gEfiPciIoProtocolGuid
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + return LookupUnicodeString2 (
> > + Language,
> > + This->SupportedLanguages,
> > + mDwMmcHcControllerNameTable,
> > + ControllerName,
> > + (BOOLEAN)(This == &gDwMmcHcComponentName)
> > + );
> > +}
> > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
> b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
> > new file mode 100644
> > index 000000000000..aea12170d2cc
> > --- /dev/null
> > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
> > @@ -0,0 +1,1296 @@
> > +/** @file
> > + This driver is used to manage Designware SD/MMC host controller.
> > +
> > + It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer
> use.
> > +
> > + Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
> > + Copyright (C) 2016 Marvell International Ltd. All rigths reserved.<BR>
> > + Copyright (C) 2018, Linaro Ltd. All rigths 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 <Library/BaseMemoryLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/DevicePathLib.h>
> > +#include <Library/IoLib.h>
> > +#include <Library/MemoryAllocationLib.h>
> > +#include <Protocol/NonDiscoverableDevice.h>
> > +#include <Library/UefiBootServicesTableLib.h>
> > +#include <Library/UefiDriverEntryPoint.h>
> > +
> > +#include <Protocol/DevicePath.h>
> > +#include <Protocol/PlatformDwMmc.h>
> > +
> > +#include "DwMmcHcDxe.h"
> > +
> > +//
> > +// Driver Global Variables
> > +//
> > +EFI_DRIVER_BINDING_PROTOCOL gDwMmcHcDriverBinding = {
> > + DwMmcHcDriverBindingSupported,
> > + DwMmcHcDriverBindingStart,
> > + DwMmcHcDriverBindingStop,
> > + 0x10,
> > + NULL,
> > + NULL
> > +};
> > +
> > +//
> > +// Template for Designware SD/MMC host controller private data.
> > +//
> > +DW_MMC_HC_PRIVATE_DATA gDwMmcHcTemplate = {
> > + DW_MMC_HC_PRIVATE_SIGNATURE, // Signature
> > + NULL, // ControllerHandle
> > + 0x0, // Mmio base address
> > + { // PassThru
> > + sizeof (UINT32),
> > + DwMmcPassThruPassThru,
> > + DwMmcPassThruGetNextSlot,
> > + DwMmcPassThruBuildDevicePath,
> > + DwMmcPassThruGetSlotNumber,
> > + DwMmcPassThruResetDevice
> > + },
> > + NULL, // PlatformDwMmc
> > + 0, // PreviousSlot
> > + NULL, // TimerEvent
> > + NULL, // ConnectEvent
> > + // Queue
> > + INITIALIZE_LIST_HEAD_VARIABLE (gDwMmcHcTemplate.Queue),
> > + { // Slot
> > + {0, UnknownSlot, 0, 0, 0}
> > + },
> > + { // Capability
> > + {0}
> > + },
> > + { // MaxCurrent
> > + 0
> > + },
> > + 0 // ControllerVersion
> > +};
> > +
> > +SD_DEVICE_PATH mSdDpTemplate = {
> > + {
> > + MESSAGING_DEVICE_PATH,
> > + MSG_SD_DP,
> > + {
> > + (UINT8) (sizeof (SD_DEVICE_PATH)),
> > + (UINT8) ((sizeof (SD_DEVICE_PATH)) >> 8)
> > + }
> > + },
> > + 0
> > +};
> > +
> > +EMMC_DEVICE_PATH mEmmcDpTemplate = {
> > + {
> > + MESSAGING_DEVICE_PATH,
> > + MSG_EMMC_DP,
> > + {
> > + (UINT8) (sizeof (EMMC_DEVICE_PATH)),
> > + (UINT8) ((sizeof (EMMC_DEVICE_PATH)) >> 8)
> > + }
> > + },
> > + 0
> > +};
> > +
> > +//
> > +// Prioritized function list to detect card type.
> > +// User could add other card detection logic here.
> > +//
> > +DWMMC_CARD_TYPE_DETECT_ROUTINE
> mCardTypeDetectRoutineTable[] = {
> > + EmmcIdentification,
> > + SdCardIdentification,
> > + NULL
> > +};
> > +
> > +/**
> > + The entry point for SD host controller driver, used to install this driver on
> the ImageHandle.
> > +
> > + @param[in] ImageHandle The firmware allocated handle for this driver
> image.
> > + @param[in] SystemTable Pointer to the EFI system table.
> > +
> > + @retval EFI_SUCCESS Driver loaded.
> > + @retval other Driver not loaded.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +InitializeDwMmcHcDxe (
> > + IN EFI_HANDLE ImageHandle,
> > + IN EFI_SYSTEM_TABLE *SystemTable
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + Status = EfiLibInstallDriverBindingComponentName2 (
> > + ImageHandle,
> > + SystemTable,
> > + &gDwMmcHcDriverBinding,
> > + ImageHandle,
> > + &gDwMmcHcComponentName,
> > + &gDwMmcHcComponentName2
> > + );
> > + ASSERT_EFI_ERROR (Status);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Call back function when the timer event is signaled.
> > +
> > + @param[in] Event The Event this notify function registered to.
> > + @param[in] Context Pointer to the context data registered to the
> > + Event.
> > +
> > +**/
> > +VOID
> > +EFIAPI
> > +ProcessAsyncTaskList (
> > + IN EFI_EVENT Event,
> > + IN VOID* Context
> > + )
> > +{
> > + DW_MMC_HC_PRIVATE_DATA *Private;
> > + LIST_ENTRY *Link;
> > + DW_MMC_HC_TRB *Trb;
> > + EFI_STATUS Status;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
> > + BOOLEAN InfiniteWait;
> > + EFI_EVENT TrbEvent;
> > +
> > + Private = (DW_MMC_HC_PRIVATE_DATA *)Context;
> > +
> > + //
> > + // Check if the first entry in the async I/O queue is done or not.
> > + //
> > + Status = EFI_SUCCESS;
> > + Trb = NULL;
> > + Link = GetFirstNode (&Private->Queue);
> > + if (!IsNull (&Private->Queue, Link)) {
> > + Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
> > + if (!Private->Slot[Trb->Slot].MediaPresent) {
> > + Status = EFI_NO_MEDIA;
> > + goto Done;
> > + }
> > + if (!Trb->Started) {
> > + //
> > + // Check whether the cmd/data line is ready for transfer.
> > + //
> > + Status = DwMmcCheckTrbEnv (Private, Trb);
> > + if (!EFI_ERROR (Status)) {
> > + Trb->Started = TRUE;
> > + Status = DwMmcExecTrb (Private, Trb);
> > + if (EFI_ERROR (Status)) {
> > + goto Done;
> > + }
> > + } else {
> > + goto Done;
> > + }
> > + }
> > + Status = DwMmcCheckTrbResult (Private, Trb);
> > + }
> > +
> > +Done:
> > + if ((Trb != NULL) && (Status == EFI_NOT_READY)) {
> > + Packet = Trb->Packet;
> > + if (Packet->Timeout == 0) {
> > + InfiniteWait = TRUE;
> > + } else {
> > + InfiniteWait = FALSE;
> > + }
> > + if ((!InfiniteWait) && (Trb->Timeout-- == 0)) {
> > + RemoveEntryList (Link);
> > + Trb->Packet->TransactionStatus = EFI_TIMEOUT;
> > + TrbEvent = Trb->Event;
> > + DwMmcFreeTrb (Trb);
> > + DEBUG ((
> > + DEBUG_VERBOSE,
> > + "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT\n",
> > + TrbEvent
> > + ));
> > + gBS->SignalEvent (TrbEvent);
> > + return;
> > + }
> > + }
> > + if ((Trb != NULL) && (Status != EFI_NOT_READY)) {
> > + RemoveEntryList (Link);
> > + Trb->Packet->TransactionStatus = Status;
> > + TrbEvent = Trb->Event;
> > + DwMmcFreeTrb (Trb);
> > + DEBUG ((
> > + DEBUG_VERBOSE,
> > + "ProcessAsyncTaskList(): Signal Event %p with %r\n",
> > + TrbEvent,
> > + Status
> > + ));
> > + gBS->SignalEvent (TrbEvent);
> > + }
> > + return;
> > +}
> > +
> > +/**
> > + Sd removable device enumeration callback function when the timer
> event is signaled.
> > +
> > + @param[in] Event The Event this notify function registered to.
> > + @param[in] Context Pointer to the context data registered to the
> > + Event.
> > +
> > +**/
> > +VOID
> > +EFIAPI
> > +DwMmcHcEnumerateDevice (
> > + IN EFI_EVENT Event,
> > + IN VOID* Context
> > + )
> > +{
> > + DW_MMC_HC_PRIVATE_DATA *Private;
> > + EFI_STATUS Status;
> > + BOOLEAN MediaPresent;
> > + UINT32 RoutineNum;
> > + DWMMC_CARD_TYPE_DETECT_ROUTINE *Routine;
> > + UINTN Index;
> > + LIST_ENTRY *Link;
> > + LIST_ENTRY *NextLink;
> > + DW_MMC_HC_TRB *Trb;
> > + EFI_TPL OldTpl;
> > +
> > + Private = (DW_MMC_HC_PRIVATE_DATA *)Context;
> > +
> > + if ((Private->Slot[0].Enable) &&
> > + (Private->Slot[0].SlotType == RemovableSlot)) {
> > + Status = DwMmcHcCardDetect (
> > + Private->DevBase,
> > + Private->ControllerHandle,
> > + 0,
> > + &MediaPresent
> > + );
> > + if ((Status == EFI_MEDIA_CHANGED) && !MediaPresent) {
> > + DEBUG ((
> > + DEBUG_INFO,
> > + "DwMmcHcEnumerateDevice: device disconnected at %p\n",
> > + Private->DevBase
> > + ));
> > + Private->Slot[0].MediaPresent = FALSE;
> > + //
> > + // Signal all async task events at the slot with EFI_NO_MEDIA status.
> > + //
> > + OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> > + for (Link = GetFirstNode (&Private->Queue);
> > + !IsNull (&Private->Queue, Link);
> > + Link = NextLink) {
> > + NextLink = GetNextNode (&Private->Queue, Link);
> > + Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
> > + if (Trb->Slot == 0) {
> > + RemoveEntryList (Link);
> > + Trb->Packet->TransactionStatus = EFI_NO_MEDIA;
> > + gBS->SignalEvent (Trb->Event);
> > + DwMmcFreeTrb (Trb);
> > + }
> > + }
> > + gBS->RestoreTPL (OldTpl);
> > + //
> > + // Notify the upper layer the connect state change through
> > + // ReinstallProtocolInterface.
> > + //
> > + gBS->ReinstallProtocolInterface (
> > + Private->ControllerHandle,
> > + &gEfiSdMmcPassThruProtocolGuid,
> > + &Private->PassThru,
> > + &Private->PassThru
> > + );
> > + }
> > + if ((Status == EFI_MEDIA_CHANGED) && MediaPresent) {
> > + DEBUG ((
> > + DEBUG_INFO,
> > + "DwMmcHcEnumerateDevice: device connected at %p\n",
> > + Private->DevBase
> > + ));
> > + //
> > + // Initialize slot and start identification process for the new
> > + // attached device
> > + //
> > + Status = DwMmcHcInitHost (Private->DevBase, Private->Capability[0]);
> > + if (EFI_ERROR (Status)) {
> > + return;
> > + }
> > + //
> > + // Reset the specified slot of the SD/MMC Pci Host Controller
> > + //
> > + Status = DwMmcHcReset (Private->DevBase, Private->Capability[0]);
> > + if (EFI_ERROR (Status)) {
> > + return;
> > + }
> > +
> > + Private->Slot[0].MediaPresent = TRUE;
> > + RoutineNum = sizeof (mCardTypeDetectRoutineTable) /
> > + sizeof (DWMMC_CARD_TYPE_DETECT_ROUTINE);
> > + for (Index = 0; Index < RoutineNum; Index++) {
> > + Routine = &mCardTypeDetectRoutineTable[Index];
> > + if (*Routine != NULL) {
> > + Status = (*Routine) (Private);
> > + if (!EFI_ERROR (Status)) {
> > + break;
> > + }
> > + }
> > + }
> > + //
> > + // This card doesn't get initialized correctly.
> > + //
> > + if (Index == RoutineNum) {
> > + return;
> > + }
> > +
> > + //
> > + // Notify the upper layer the connect state change through
> > + // ReinstallProtocolInterface.
> > + //
> > + gBS->ReinstallProtocolInterface (
> > + Private->ControllerHandle,
> > + &gEfiSdMmcPassThruProtocolGuid,
> > + &Private->PassThru,
> > + &Private->PassThru
> > + );
> > + }
> > + }
> > +
> > + return;
> > +}
> > +
> > +/**
> > + Reset the specified SD/MMC host controller and enable all interrupts.
> > +
> > + @param[in] DevBase The Mmio Device Base Address.
> > +
> > + @retval EFI_SUCCESS The software reset executes successfully.
> > + @retval Others The software reset fails.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcReset (
> > + IN UINTN DevBase,
> > + IN DW_MMC_HC_SLOT_CAP Capability
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT32 BlkSize;
> > +
> > + //
> > + // Enable all interrupt after reset all.
> > + //
> > + Status = DwMmcHcEnableInterrupt (DevBase);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "DwMmcHcReset: enable interrupts fail:
> %r\n", Status));
> > + return Status;
> > + }
> > + Status = DwMmcHcInitTimeoutCtrl (DevBase);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + BlkSize = DW_MMC_BLOCK_SIZE;
> > + MmioWrite32 (DevBase + DW_MMC_BLKSIZ, BlkSize);
> > +
> > + Status = DwMmcHcInitClockFreq (DevBase, Capability);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + Status = DwMmcHcSetBusWidth (DevBase, FALSE, 1);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Tests to see if this driver supports a given controller. If a child device
> > + is provided, it further tests to see if this driver supports creating a
> > + handle for the specified child device.
> > +
> > + This function checks to see if the driver specified by This supports the
> > + device specified by ControllerHandle. Drivers will typically use the device
> > + path attached to ControllerHandle and/or the services from the bus I/O
> > + abstraction attached to ControllerHandle to determine if the driver
> supports
> > + ControllerHandle. This function may be called many times during
> platform
> > + initialization. In order to reduce boot times, the tests performed by this
> > + function must be very small, and take as little time as possible to
> execute.
> > + This function must not change the state of any hardware devices, and
> this
> > + function must be aware that the device specified by ControllerHandle
> may
> > + already be managed by the same driver or a different driver. This
> function
> > + must match its calls to AllocatePages() with FreePages(), AllocatePool()
> with
> > + FreePool(), and OpenProtocol() with CloseProtocol(). Since
> ControllerHandle
> > + may have been previously started by the same driver, if a protocol is
> already
> > + in the opened state, then it must not be closed with CloseProtocol(). This
> is
> > + required to guarantee the state of ControllerHandle is not modified by
> this
> > + function.
> > +
> > + @param[in] This A pointer to the
> EFI_DRIVER_BINDING_PROTOCOL
> > + instance.
> > + @param[in] ControllerHandle The handle of the controller to test. This
> > + handle must support a protocol interface that
> > + supplies an I/O abstraction to the driver.
> > + @param[in] RemainingDevicePath A pointer to the remaining portion of
> a
> > + device path. This parameter is ignored by
> > + device drivers, and is optional for bus
> > + drivers. For bus drivers, if this parameter
> > + is not NULL, then the bus driver must deter-
> > + mine if the bus controller specified by
> > + ControllerHandle and the child controller
> > + specified by RemainingDevicePath are both
> > + supported by this bus driver.
> > +
> > + @retval EFI_SUCCESS The device specified by ControllerHandle
> and
> > + RemainingDevicePath is supported by the
> > + driver specified by This.
> > + @retval EFI_ALREADY_STARTED The device specified by
> ControllerHandle and
> > + RemainingDevicePath is already being managed
> > + by the driver specified by This.
> > + @retval EFI_ACCESS_DENIED The device specified by
> ControllerHandle and
> > + RemainingDevicePath is already being managed
> > + by a different driver or an application that
> > + requires exclusive access.
> > + Currently not implemented.
> > + @retval EFI_UNSUPPORTED The device specified by
> ControllerHandle and
> > + RemainingDevicePath is not supported by the
> > + driver specified by This.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcHcDriverBindingSupported (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE Controller,
> > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
> > + NON_DISCOVERABLE_DEVICE *Dev;
> > + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc;
> > +
> > + ParentDevicePath = NULL;
> > +
> > + Status = gBS->LocateProtocol (
> > + &gPlatformDwMmcProtocolGuid,
> > + NULL,
> > + (VOID **) &PlatformDwMmc
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + Status = gBS->OpenProtocol (
> > + Controller,
> > + &gEfiDevicePathProtocolGuid,
> > + (VOID *) &ParentDevicePath,
> > + This->DriverBindingHandle,
> > + Controller,
> > + EFI_OPEN_PROTOCOL_BY_DRIVER
> > + );
> > + if (EFI_ERROR (Status)) {
> > + //
> > + // EFI_ALREADY_STARTED is also an error.
> > + //
> > + return Status;
> > + }
> > + //
> > + // Close the protocol because we don't use it here.
> > + //
> > + gBS->CloseProtocol (
> > + Controller,
> > + &gEfiDevicePathProtocolGuid,
> > + This->DriverBindingHandle,
> > + Controller
> > + );
> > +
> > + //
> > + // Now test the EmbeddedNonDiscoverableIoProtocol.
> > + //
> > + Status = gBS->OpenProtocol (
> > + Controller,
> > + &gEdkiiNonDiscoverableDeviceProtocolGuid,
> > + (VOID **) &Dev,
> > + This->DriverBindingHandle,
> > + Controller,
> > + EFI_OPEN_PROTOCOL_BY_DRIVER
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > + gBS->CloseProtocol (
> > + Controller,
> > + &gEdkiiNonDiscoverableDeviceProtocolGuid,
> > + This->DriverBindingHandle,
> > + Controller
> > + );
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Starts a device controller or a bus controller.
> > +
> > + The Start() function is designed to be invoked from the EFI boot service
> > + ConnectController().
> > + As a result, much of the error checking on the parameters to Start() has
> > + been moved into this
> > + common boot service. It is legal to call Start() from other locations,
> > + but the following calling restrictions must be followed or the system
> > + behavior will not be deterministic.
> > + 1. ControllerHandle must be a valid EFI_HANDLE.
> > + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a
> > + naturally aligned EFI_DEVICE_PATH_PROTOCOL.
> > + 3. Prior to calling Start(), the Supported() function for the driver
> > + specified by This must have been called with the same calling
> parameters,
> > + and Supported() must have returned EFI_SUCCESS.
> > +
> > + @param[in] This A pointer to the
> EFI_DRIVER_BINDING_PROTOCOL
> > + instance.
> > + @param[in] ControllerHandle The handle of the controller to start.
> This
> > + handle must support a protocol interface
> > + that supplies an I/O abstraction to the
> > + driver.
> > + @param[in] RemainingDevicePath A pointer to the remaining portion of
> a
> > + device path. This parameter is ignored by
> > + device drivers, and is optional for bus
> > + drivers.
> > + For a bus driver, if this parameter is NULL,
> > + then handles for all the children of
> > + Controller are created by this driver.
> > + If this parameter is not NULL and the first
> > + Device Path Node is not the End of Device
> > + Path Node, then only the handle for the
> > + child device specified by the first Device
> > + Path Node of RemainingDevicePath is created
> > + by this driver.
> > + If the first Device Path Node of
> > + RemainingDevicePath is the End of Device Path
> > + Node, no child handle is created by this
> > + driver.
> > +
> > + @retval EFI_SUCCESS The device was started.
> > + @retval EFI_DEVICE_ERROR The device could not be started due to a
> > + device error. Currently not implemented.
> > + @retval EFI_OUT_OF_RESOURCES The request could not be
> completed due to a
> > + lack of resources.
> > + @retval Others The driver failded to start the device.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcHcDriverBindingStart (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE Controller,
> > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> > + )
> > +{
> > + EFI_STATUS Status;
> > + DW_MMC_HC_PRIVATE_DATA *Private;
> > +
> > + NON_DISCOVERABLE_DEVICE *Dev;
> > +
> > + BOOLEAN MediaPresent;
> > + DWMMC_CARD_TYPE_DETECT_ROUTINE *Routine;
> > + UINT8 Index;
> > + UINT32 RoutineNum;
> > + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc;
> > +
> > + Status = gBS->LocateProtocol (
> > + &gPlatformDwMmcProtocolGuid,
> > + NULL,
> > + (VOID **) &PlatformDwMmc
> > + );
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "err %d", __LINE__));
> > + return Status;
> > + }
> > +
> > + Status = gBS->OpenProtocol (
> > + Controller,
> > + &gEdkiiNonDiscoverableDeviceProtocolGuid,
> > + (VOID **) &Dev,
> > + This->DriverBindingHandle,
> > + Controller,
> > + EFI_OPEN_PROTOCOL_BY_DRIVER
> > + );
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "err %d", __LINE__));
> > + return Status;
> > + }
> > +
> > + Private = AllocateCopyPool (sizeof (DW_MMC_HC_PRIVATE_DATA),
> &gDwMmcHcTemplate);
> > + if (Private == NULL) {
> > + DEBUG ((DEBUG_ERROR, "err %d", __LINE__));
> > + Status = EFI_OUT_OF_RESOURCES;
> > + goto Done;
> > + }
> > +
> > + Private->ControllerHandle = Controller;
> > + Private->DevBase = Dev->Resources[0].AddrRangeMin;
> > + Private->PlatformDwMmc = PlatformDwMmc;
> > + InitializeListHead (&Private->Queue);
> > +
> > + Status = Private->PlatformDwMmc->GetCapability (Controller, 0,
> &Private->Capability[0]);
> > +
> > + if (EFI_ERROR (Status)) {
> > + goto Done;
> > + }
> > +
> > + if (Private->Capability[0].BaseClkFreq == 0) {
> > + goto Done;
> > + }
> > +
> > + DumpCapabilityReg (0, &Private->Capability[0]);
> > +
> > + MediaPresent = FALSE;
> > +
> > + Status = Private->PlatformDwMmc->CardDetect (Controller, 0);
> > + Status = DwMmcHcCardDetect (Private->DevBase, Controller, 0,
> &MediaPresent);
> > + if (MediaPresent == FALSE) {
> > + goto Done;
> > + }
> > +
> > + //
> > + // Initialize slot and start identification process for the new attached
> device
> > + //
> > + Status = DwMmcHcInitHost (Private->DevBase, Private->Capability[0]);
> > + if (EFI_ERROR (Status)) {
> > + goto Done;
> > + }
> > +
> > + //
> > + // Reset HC
> > + //
> > + Status = DwMmcHcReset (Private->DevBase, Private->Capability[0]);
> > + if (EFI_ERROR (Status)) {
> > + goto Done;
> > + }
> > +
> > + Private->Slot[0].CardType = Private->Capability[0].CardType;
> > + Private->Slot[0].Enable = TRUE;
> > + Private->Slot[0].MediaPresent = TRUE;
> > +
> > + RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof
> (DWMMC_CARD_TYPE_DETECT_ROUTINE);
> > + for (Index = 0; Index < RoutineNum; Index++) {
> > + Routine = &mCardTypeDetectRoutineTable[Index];
> > + if (*Routine != NULL) {
> > + Status = (*Routine) (Private);
> > + if (!EFI_ERROR (Status)) {
> > + break;
> > + }
> > + }
> > + }
> > +
> > + //
> > + // Start the asynchronous I/O monitor
> > + //
> > + Status = gBS->CreateEvent (
> > + EVT_TIMER | EVT_NOTIFY_SIGNAL,
> > + TPL_NOTIFY,
> > + ProcessAsyncTaskList,
> > + Private,
> > + &Private->TimerEvent
> > + );
> > + if (EFI_ERROR (Status)) {
> > + goto Done;
> > + }
> > +
> > + Status = gBS->SetTimer (Private->TimerEvent, TimerPeriodic,
> DW_MMC_HC_ASYNC_TIMER);
> > + if (EFI_ERROR (Status)) {
> > + goto Done;
> > + }
> > +
> > + //
> > + // Start the Sd removable device connection enumeration
> > + //
> > + Status = gBS->CreateEvent (
> > + EVT_TIMER | EVT_NOTIFY_SIGNAL,
> > + TPL_CALLBACK,
> > + DwMmcHcEnumerateDevice,
> > + Private,
> > + &Private->ConnectEvent
> > + );
> > + if (EFI_ERROR (Status)) {
> > + goto Done;
> > + }
> > +
> > + Status = gBS->SetTimer (Private->ConnectEvent, TimerPeriodic,
> DW_MMC_HC_ENUM_TIMER);
> > + if (EFI_ERROR (Status)) {
> > + goto Done;
> > + }
> > +
> > + Status = gBS->InstallMultipleProtocolInterfaces (
> > + &Controller,
> > + &gEfiSdMmcPassThruProtocolGuid,
> > + &(Private->PassThru),
> > + NULL
> > + );
> > +
> > + DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStart: %r End on %x\n",
> Status, Controller));
> > +
> > +Done:
> > + if (EFI_ERROR (Status)) {
> > + if ((Private != NULL) && (Private->TimerEvent != NULL)) {
> > + gBS->CloseEvent (Private->TimerEvent);
> > + }
> > +
> > + if ((Private != NULL) && (Private->ConnectEvent != NULL)) {
> > + gBS->CloseEvent (Private->ConnectEvent);
> > + }
> > +
> > + if (Private != NULL) {
> > + FreePool (Private);
> > + }
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Stops a device controller or a bus controller.
> > +
> > + The Stop() function is designed to be invoked from the EFI boot service
> > + DisconnectController().
> > + As a result, much of the error checking on the parameters to Stop() has
> been
> > + moved into this common boot service. It is legal to call Stop() from other
> > + locations, but the following calling restrictions must be followed or the
> > + system behavior will not be deterministic.
> > + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a
> previous
> > + call to this same driver's Start() function.
> > + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a
> valid
> > + EFI_HANDLE. In addition, all of these handles must have been created
> in
> > + this driver's Start() function, and the Start() function must have called
> > + OpenProtocol() on ControllerHandle with an Attribute of
> > + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
> > +
> > + @param[in] This A pointer to the
> EFI_DRIVER_BINDING_PROTOCOL
> > + instance.
> > + @param[in] ControllerHandle A handle to the device being stopped.
> The handle
> > + must support a bus specific I/O protocol for the
> > + driver to use to stop the device.
> > + @param[in] NumberOfChildren The number of child device handles in
> > + ChildHandleBuffer.
> > + @param[in] ChildHandleBuffer An array of child handles to be freed.
> May be
> > + NULL if NumberOfChildren is 0.
> > +
> > + @retval EFI_SUCCESS The device was stopped.
> > + @retval EFI_DEVICE_ERROR The device could not be stopped due to a
> device
> > + error.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcHcDriverBindingStop (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE Controller,
> > + IN UINTN NumberOfChildren,
> > + IN EFI_HANDLE *ChildHandleBuffer
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
> > + DW_MMC_HC_PRIVATE_DATA *Private;
> > + LIST_ENTRY *Link;
> > + LIST_ENTRY *NextLink;
> > + DW_MMC_HC_TRB *Trb;
> > +
> > + DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStop: Start\n"));
> > +
> > + Status = gBS->OpenProtocol (
> > + Controller,
> > + &gEfiSdMmcPassThruProtocolGuid,
> > + (VOID**) &PassThru,
> > + This->DriverBindingHandle,
> > + Controller,
> > + EFI_OPEN_PROTOCOL_GET_PROTOCOL
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru);
> > + //
> > + // Close Non-Blocking timer and free Task list.
> > + //
> > + if (Private->TimerEvent != NULL) {
> > + gBS->CloseEvent (Private->TimerEvent);
> > + Private->TimerEvent = NULL;
> > + }
> > + if (Private->ConnectEvent != NULL) {
> > + gBS->CloseEvent (Private->ConnectEvent);
> > + Private->ConnectEvent = NULL;
> > + }
> > + //
> > + // As the timer is closed, there is no needs to use TPL lock to
> > + // protect the critical region "queue".
> > + //
> > + for (Link = GetFirstNode (&Private->Queue);
> > + !IsNull (&Private->Queue, Link);
> > + Link = NextLink) {
> > + NextLink = GetNextNode (&Private->Queue, Link);
> > + RemoveEntryList (Link);
> > + Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
> > + Trb->Packet->TransactionStatus = EFI_ABORTED;
> > + gBS->SignalEvent (Trb->Event);
> > + DwMmcFreeTrb (Trb);
> > + }
> > +
> > + //
> > + // Uninstall Block I/O protocol from the device handle
> > + //
> > + Status = gBS->UninstallProtocolInterface (
> > + Controller,
> > + &gEfiSdMmcPassThruProtocolGuid,
> > + &(Private->PassThru)
> > + );
> > +
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + gBS->CloseProtocol (
> > + Controller,
> > + &gEfiPciIoProtocolGuid,
> > + This->DriverBindingHandle,
> > + Controller
> > + );
> > +
> > + FreePool (Private);
> > +
> > + DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStop: End with %r\n",
> Status));
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Sends SD command to an SD card that is attached to the SD controller.
> > +
> > + The PassThru() function sends the SD command specified by Packet to
> the SD
> > + card specified by Slot.
> > +
> > + If Packet is successfully sent to the SD card, then EFI_SUCCESS is
> returned.
> > +
> > + If a device error occurs while sending the Packet, then
> EFI_DEVICE_ERROR is
> > + returned.
> > +
> > + If Slot is not in a valid range for the SD controller, then
> > + EFI_INVALID_PARAMETER is returned.
> > +
> > + If Packet defines a data command but both InDataBuffer and
> OutDataBuffer are
> > + NULL, EFI_INVALID_PARAMETER is returned.
> > +
> > + @param[in] This A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Slot The slot number of the SD card to send the
> > + command to.
> > + @param[in,out] Packet A pointer to the SD command data structure.
> > + @param[in] Event If Event is NULL, blocking I/O is performed. If
> > + Event is not NULL, then nonblocking I/O is
> > + performed, and Event will be signaled when the
> > + Packet completes.
> > +
> > + @retval EFI_SUCCESS The SD Command Packet was sent by the
> host.
> > + @retval EFI_DEVICE_ERROR A device error occurred while attempting
> to send
> > + the SD command Packet.
> > + @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the
> Packet is
> > + invalid.
> > + @retval EFI_INVALID_PARAMETER Packet defines a data command but
> both
> > + InDataBuffer and OutDataBuffer are NULL.
> > + @retval EFI_NO_MEDIA SD Device not present in the Slot.
> > + @retval EFI_UNSUPPORTED The command described by the SD
> Command Packet
> > + is not supported by the host controller.
> > + @retval EFI_BAD_BUFFER_SIZE The InTransferLength or
> OutTransferLength
> > + exceeds the limit supported by SD card
> > + ( i.e. if the number of bytes exceed the Last
> > + LBA).
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcPassThruPassThru (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> > + IN UINT8 Slot,
> > + IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
> > + IN EFI_EVENT Event OPTIONAL
> > + )
> > +{
> > + EFI_STATUS Status;
> > + DW_MMC_HC_PRIVATE_DATA *Private;
> > + DW_MMC_HC_TRB *Trb;
> > + EFI_TPL OldTpl;
> > +
> > + if ((This == NULL) || (Packet == NULL)) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if ((Packet->SdMmcCmdBlk == NULL) || (Packet->SdMmcStatusBlk ==
> NULL)) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength !=
> 0)) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0))
> {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
> > +
> > + if (!Private->Slot[Slot].Enable) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if (!Private->Slot[Slot].MediaPresent) {
> > + return EFI_NO_MEDIA;
> > + }
> > +
> > + Trb = DwMmcCreateTrb (Private, Slot, Packet, Event);
> > + if (Trb == NULL) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > + //
> > + // Immediately return for async I/O.
> > + //
> > + if (Event != NULL) {
> > + return EFI_SUCCESS;
> > + }
> > +
> > + //
> > + // Wait async I/O list is empty before execute sync I/O operation.
> > + //
> > + while (TRUE) {
> > + OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> > + if (IsListEmpty (&Private->Queue)) {
> > + gBS->RestoreTPL (OldTpl);
> > + break;
> > + }
> > + gBS->RestoreTPL (OldTpl);
> > + }
> > +
> > + Status = DwMmcWaitTrbEnv (Private, Trb);
> > + if (EFI_ERROR (Status)) {
> > + goto Done;
> > + }
> > +
> > + Status = DwMmcExecTrb (Private, Trb);
> > + if (EFI_ERROR (Status)) {
> > + goto Done;
> > + }
> > +
> > + Status = DwMmcWaitTrbResult (Private, Trb);
> > + if (EFI_ERROR (Status)) {
> > + goto Done;
> > + }
> > +
> > +Done:
> > + if (Trb != NULL) {
> > + DwMmcFreeTrb (Trb);
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Used to retrieve next slot numbers supported by the SD controller. The
> > + function returns information about all available slots (populated or
> > + not-populated).
> > +
> > + The GetNextSlot() function retrieves the next slot number on an SD
> controller.
> > + If on input Slot is 0xFF, then the slot number of the first slot on the SD
> > + controller is returned.
> > +
> > + If Slot is a slot number that was returned on a previous call to
> > + GetNextSlot(), then the slot number of the next slot on the SD controller
> is
> > + returned.
> > +
> > + If Slot is not 0xFF and Slot was not returned on a previous call to
> > + GetNextSlot(), EFI_INVALID_PARAMETER is returned.
> > +
> > + If Slot is the slot number of the last slot on the SD controller, then
> > + EFI_NOT_FOUND is returned.
> > +
> > + @param[in] This A pointer to the
> EFI_SD_MMMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in,out] Slot On input, a pointer to a slot number on the SD
> > + controller.
> > + On output, a pointer to the next slot number on
> > + the SD controller.
> > + An input value of 0xFF retrieves the first slot
> > + number on the SD controller.
> > +
> > + @retval EFI_SUCCESS The next slot number on the SD controller
> was
> > + returned in Slot.
> > + @retval EFI_NOT_FOUND There are no more slots on this SD
> controller.
> > + @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not
> returned on a
> > + previous call to GetNextSlot().
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcPassThruGetNextSlot (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> > + IN OUT UINT8 *Slot
> > + )
> > +{
> > + DW_MMC_HC_PRIVATE_DATA *Private;
> > +
> > + if ((This == NULL) || (Slot == NULL)) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
> > +
> > + if (*Slot == 0xFF) {
> > + if (Private->Slot[0].Enable) {
> > + *Slot = 0;
> > + Private->PreviousSlot = 0;
> > + return EFI_SUCCESS;
> > + }
> > + return EFI_NOT_FOUND;
> > + } else if (*Slot == Private->PreviousSlot) {
> > + return EFI_NOT_FOUND;
> > + } else {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +}
> > +
> > +/**
> > + Used to allocate and build a device path node for an SD card on the SD
> > + controller.
> > +
> > + The BuildDevicePath() function allocates and builds a single device node
> > + for the SD card specified by Slot.
> > +
> > + If the SD card specified by Slot is not present on the SD controller, then
> > + EFI_NOT_FOUND is returned.
> > +
> > + If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.
> > +
> > + If there are not enough resources to allocate the device path node, then
> > + EFI_OUT_OF_RESOURCES is returned.
> > +
> > + Otherwise, DevicePath is allocated with the boot service AllocatePool(),
> > + the contents of DevicePath are initialized to describe the SD card
> specified
> > + by Slot, and EFI_SUCCESS is returned.
> > +
> > + @param[in] This A pointer to the
> EFI_SD_MMMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Slot Specifies the slot number of the SD card for
> > + which a device path node is to be allocated and
> > + built.
> > + @param[in,out] DevicePath A pointer to a single device path node that
> > + describes the SD card specified by Slot. This
> > + function is responsible for allocating the
> > + buffer DevicePath with the boot service
> > + AllocatePool(). It is the caller's responsi-
> > + bility to free DevicePath when the caller is
> > + finished with DevicePath.
> > +
> > + @retval EFI_SUCCESS The device path node that describes the SD
> card
> > + specified by Slot was allocated and returned in
> > + DevicePath.
> > + @retval EFI_NOT_FOUND The SD card specified by Slot does not
> exist on
> > + the SD controller.
> > + @retval EFI_INVALID_PARAMETER DevicePath is NULL.
> > + @retval EFI_OUT_OF_RESOURCES There are not enough resources to
> allocate
> > + DevicePath.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcPassThruBuildDevicePath (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> > + IN UINT8 Slot,
> > + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
> > + )
> > +{
> > + DW_MMC_HC_PRIVATE_DATA *Private;
> > + SD_DEVICE_PATH *SdNode;
> > + EMMC_DEVICE_PATH *EmmcNode;
> > +
> > + if ((This == NULL) || (DevicePath == NULL) || (Slot >=
> DW_MMC_HC_MAX_SLOT)) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
> > +
> > + if ((!Private->Slot[Slot].Enable) || (!Private->Slot[Slot].MediaPresent)) {
> > + return EFI_NOT_FOUND;
> > + }
> > +
> > + if (Private->Slot[Slot].CardType == SdCardType) {
> > + SdNode = AllocateCopyPool (sizeof (SD_DEVICE_PATH),
> &mSdDpTemplate);
> > + if (SdNode == NULL) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > + SdNode->SlotNumber = Slot;
> > +
> > + *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) SdNode;
> > + } else if (Private->Slot[Slot].CardType == EmmcCardType) {
> > + EmmcNode = AllocateCopyPool (sizeof (EMMC_DEVICE_PATH),
> &mEmmcDpTemplate);
> > + if (EmmcNode == NULL) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > + EmmcNode->SlotNumber = Slot;
> > +
> > + *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) EmmcNode;
> > + } else {
> > + //
> > + // Currently we only support SD and EMMC two device nodes.
> > + //
> > + return EFI_NOT_FOUND;
> > + }
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + This function retrieves an SD card slot number based on the input device
> path.
> > +
> > + The GetSlotNumber() function retrieves slot number for the SD card
> specified
> > + by the DevicePath node. If DevicePath is NULL,
> EFI_INVALID_PARAMETER is
> > + returned.
> > +
> > + If DevicePath is not a device path node type that the SD Pass Thru driver
> > + supports, EFI_UNSUPPORTED is returned.
> > +
> > + @param[in] This A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] DevicePath A pointer to the device path node that
> describes
> > + a SD card on the SD controller.
> > + @param[out] Slot On return, points to the slot number of an SD
> > + card on the SD controller.
> > +
> > + @retval EFI_SUCCESS SD card slot number is returned in Slot.
> > + @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.
> > + @retval EFI_UNSUPPORTED DevicePath is not a device path node
> type that
> > + the SD Pass Thru driver supports.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcPassThruGetSlotNumber (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> > + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
> > + OUT UINT8 *Slot
> > + )
> > +{
> > + DW_MMC_HC_PRIVATE_DATA *Private;
> > + SD_DEVICE_PATH *SdNode;
> > + EMMC_DEVICE_PATH *EmmcNode;
> > + UINT8 SlotNumber;
> > +
> > + if ((This == NULL) || (DevicePath == NULL) || (Slot == NULL)) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
> > +
> > + //
> > + // Check whether the DevicePath belongs to SD_DEVICE_PATH or
> EMMC_DEVICE_PATH
> > + //
> > + if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
> > + ((DevicePath->SubType != MSG_SD_DP) &&
> > + (DevicePath->SubType != MSG_EMMC_DP)) ||
> > + (DevicePathNodeLength(DevicePath) != sizeof(SD_DEVICE_PATH)) ||
> > + (DevicePathNodeLength(DevicePath) !=
> sizeof(EMMC_DEVICE_PATH))) {
> > + return EFI_UNSUPPORTED;
> > + }
> > +
> > + if (DevicePath->SubType == MSG_SD_DP) {
> > + SdNode = (SD_DEVICE_PATH *) DevicePath;
> > + SlotNumber = SdNode->SlotNumber;
> > + } else {
> > + EmmcNode = (EMMC_DEVICE_PATH *) DevicePath;
> > + SlotNumber = EmmcNode->SlotNumber;
> > + }
> > +
> > + if (SlotNumber >= DW_MMC_HC_MAX_SLOT) {
> > + return EFI_NOT_FOUND;
> > + }
> > +
> > + if (Private->Slot[SlotNumber].Enable) {
> > + *Slot = SlotNumber;
> > + return EFI_SUCCESS;
> > + } else {
> > + return EFI_NOT_FOUND;
> > + }
> > +}
> > +
> > +/**
> > + Resets an SD card that is connected to the SD controller.
> > +
> > + The ResetDevice() function resets the SD card specified by Slot.
> > +
> > + If this SD controller does not support a device reset operation,
> > + EFI_UNSUPPORTED is returned.
> > +
> > + If Slot is not in a valid slot number for this SD controller,
> > + EFI_INVALID_PARAMETER is returned.
> > +
> > + If the device reset operation is completed, EFI_SUCCESS is returned.
> > +
> > + @param[in] This A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Slot Specifies the slot number of the SD card to be
> > + reset.
> > +
> > + @retval EFI_SUCCESS The SD card specified by Slot was reset.
> > + @retval EFI_UNSUPPORTED The SD controller does not support a
> device
> > + reset operation.
> > + @retval EFI_INVALID_PARAMETER Slot number is invalid.
> > + @retval EFI_NO_MEDIA SD Device not present in the Slot.
> > + @retval EFI_DEVICE_ERROR The reset command failed due to a device
> error
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +DwMmcPassThruResetDevice (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
> > + IN UINT8 Slot
> > + )
> > +{
> > + DW_MMC_HC_PRIVATE_DATA *Private;
> > + LIST_ENTRY *Link;
> > + LIST_ENTRY *NextLink;
> > + DW_MMC_HC_TRB *Trb;
> > + EFI_TPL OldTpl;
> > +
> > + if (This == NULL) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
> > +
> > + if (!Private->Slot[Slot].Enable) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if (!Private->Slot[Slot].MediaPresent) {
> > + return EFI_NO_MEDIA;
> > + }
> > +
> > + //
> > + // Free all async I/O requests in the queue
> > + //
> > + OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> > +
> > + for (Link = GetFirstNode (&Private->Queue);
> > + !IsNull (&Private->Queue, Link);
> > + Link = NextLink) {
> > + NextLink = GetNextNode (&Private->Queue, Link);
> > + RemoveEntryList (Link);
> > + Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
> > + Trb->Packet->TransactionStatus = EFI_ABORTED;
> > + gBS->SignalEvent (Trb->Event);
> > + DwMmcFreeTrb (Trb);
> > + }
> > +
> > + gBS->RestoreTPL (OldTpl);
> > +
> > + return EFI_SUCCESS;
> > +}
> > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
> b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
> > new file mode 100644
> > index 000000000000..b091f9803b2e
> > --- /dev/null
> > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
> > @@ -0,0 +1,1602 @@
> > +/** @file
> > + This driver is used to manage Designware SD/MMC PCI host controllers.
> > +
> > + It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer
> use.
> > +
> > + Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR>
> > + Copyright (c) 2018, Linaro Ltd. 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 <IndustryStandard/Emmc.h>
> > +#include <IndustryStandard/Sd.h>
> > +
> > +#include <Library/ArmLib.h>
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/DmaLib.h>
> > +#include <Library/IoLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/MemoryAllocationLib.h>
> > +#include <Library/UefiBootServicesTableLib.h>
> > +
> > +#include "DwMmcHcDxe.h"
> > +
> > +/**
> > + Dump the content of SD/MMC host controller's Capability Register.
> > +
> > + @param[in] Slot The slot number of the SD card to send the
> > + command to.
> > + @param[in] Capability The buffer to store the capability data.
> > +
> > +**/
> > +VOID
> > +DumpCapabilityReg (
> > + IN UINT8 Slot,
> > + IN DW_MMC_HC_SLOT_CAP *Capability
> > + )
> > +{
> > + //
> > + // Dump Capability Data
> > + //
> > + DEBUG ((
> > + DEBUG_INFO,
> > + " == Slot [%d] Capability is 0x%x ==\n",
> > + Slot,
> > + Capability
> > + ));
> > + DEBUG ((
> > + DEBUG_INFO,
> > + " Base Clk Freq %dKHz\n",
> > + Capability->BaseClkFreq
> > + ));
> > + DEBUG ((
> > + DEBUG_INFO,
> > + " BusWidth %d\n",
> > + Capability->BusWidth
> > + ));
> > + DEBUG ((
> > + DEBUG_INFO,
> > + " HighSpeed Support %a\n",
> > + Capability->HighSpeed ? "TRUE" : "FALSE"
> > + ));
> > + DEBUG ((
> > + DEBUG_INFO,
> > + " Voltage 1.8 %a\n",
> > + Capability->Voltage18 ? "TRUE" : "FALSE"
> > + ));
> > + DEBUG ((
> > + DEBUG_INFO,
> > + " 64-bit Sys Bus %a\n",
> > + Capability->SysBus64 ? "TRUE" : "FALSE"
> > + ));
> > + DEBUG ((DEBUG_INFO, " SlotType "));
> > + if (Capability->SlotType == 0x00) {
> > + DEBUG ((DEBUG_INFO, "%a\n", "Removable Slot"));
> > + } else if (Capability->SlotType == 0x01) {
> > + DEBUG ((DEBUG_INFO, "%a\n", "Embedded Slot"));
> > + } else if (Capability->SlotType == 0x02) {
> > + DEBUG ((DEBUG_INFO, "%a\n", "Shared Bus Slot"));
> > + } else {
> > + DEBUG ((DEBUG_INFO, "%a\n", "Reserved"));
> > + }
> > + DEBUG ((
> > + DEBUG_INFO,
> > + " SDR50 Support %a\n",
> > + Capability->Sdr50 ? "TRUE" : "FALSE"
> > + ));
> > + DEBUG ((
> > + DEBUG_INFO,
> > + " SDR104 Support %a\n",
> > + Capability->Sdr104 ? "TRUE" : "FALSE"
> > + ));
> > + DEBUG ((
> > + DEBUG_INFO,
> > + " DDR50 Support %a\n",
> > + Capability->Ddr50 ? "TRUE" : "FALSE"
> > + ));
> > + return;
> > +}
> > +
> > +/**
> > + Set all interrupt status bits in Normal and Error Interrupt Status Enable
> > + register.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > +
> > + @retval EFI_SUCCESS The operation executes successfully.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcEnableInterrupt (
> > + UINTN DevBase
> > + )
> > +{
> > + UINT32 IntStatus;
> > + UINT32 IdIntEn;
> > + UINT32 IdSts;
> > +
> > + //
> > + // Enable all bits in Interrupt Mask Register
> > + //
> > + IntStatus = 0;
> > + MmioWrite32 (DevBase + DW_MMC_INTMASK, IntStatus);
> > +
> > + //
> > + // Clear status in Interrupt Status Register
> > + //
> > + IntStatus = ~0;
> > + MmioWrite32 (DevBase + DW_MMC_RINTSTS, IntStatus);
> > +
> > + IdIntEn = ~0;
> > + MmioWrite32 (DevBase + DW_MMC_IDINTEN, IdIntEn);
> > +
> > + IdSts = ~0;
> > + MmioWrite32 (DevBase + DW_MMC_IDSTS, IdSts);
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +EFI_STATUS
> > +DwMmcHcGetCapability (
> > + IN UINTN DevBase,
> > + IN EFI_HANDLE Controller,
> > + IN UINT8 Slot,
> > + OUT DW_MMC_HC_SLOT_CAP *Capacity
> > + )
> > +{
> > + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc;
> > + EFI_STATUS Status;
> > +
> > + if (Capacity == NULL) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > + Status = gBS->LocateProtocol (
> > + &gPlatformDwMmcProtocolGuid,
> > + NULL,
> > + (VOID **) &PlatformDwMmc
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > + Status = PlatformDwMmc->GetCapability (Controller, Slot, Capacity);
> > + return Status;
> > +}
> > +
> > +/**
> > + Detect whether there is a SD/MMC card attached at the specified
> SD/MMC host
> > + controller slot.
> > +
> > + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command
> > + to.
> > + @param[out] MediaPresent The pointer to the media present boolean
> value.
> > +
> > + @retval EFI_SUCCESS There is no media change happened.
> > + @retval EFI_MEDIA_CHANGED There is media change happened.
> > + @retval Others The detection fails.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcCardDetect (
> > + IN UINTN DevBase,
> > + IN EFI_HANDLE Controller,
> > + IN UINT8 Slot,
> > + OUT BOOLEAN *MediaPresent
> > + )
> > +{
> > + PLATFORM_DW_MMC_PROTOCOL *PlatformDwMmc;
> > + EFI_STATUS Status;
> > +
> > + if (MediaPresent == NULL) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > + Status = gBS->LocateProtocol (
> > + &gPlatformDwMmcProtocolGuid,
> > + NULL,
> > + (VOID **) &PlatformDwMmc
> > + );
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > + *MediaPresent = PlatformDwMmc->CardDetect (Controller, Slot);
> > + return EFI_SUCCESS;
> > +}
> > +
> > +STATIC
> > +EFI_STATUS
> > +DwMmcHcUpdateClock (
> > + IN UINTN DevBase
> > + )
> > +{
> > + UINT32 Cmd;
> > + UINT32 IntStatus;
> > +
> > + Cmd = BIT_CMD_WAIT_PRVDATA_COMPLETE |
> BIT_CMD_UPDATE_CLOCK_ONLY |
> > + BIT_CMD_START;
> > + MmioWrite32 (DevBase + DW_MMC_CMD, Cmd);
> > +
> > + while (1) {
> > + Cmd = MmioRead32 (DevBase + DW_MMC_CMD);
> > +
> > + if (!(Cmd & CMD_START_BIT)) {
> > + break;
> > + }
> > +
> > + IntStatus = MmioRead32 (DevBase + DW_MMC_RINTSTS);
> > +
> > + if (IntStatus & DW_MMC_INT_HLE) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "DwMmcHcUpdateClock: failed to update mmc clock frequency\n"
> > + ));
> > + return EFI_DEVICE_ERROR;
> > + }
> > + }
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Stop SD/MMC card clock.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > +
> > + @retval EFI_SUCCESS Succeed to stop SD/MMC clock.
> > + @retval Others Fail to stop SD/MMC clock.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcStopClock (
> > + IN UINTN DevBase
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT32 ClkEna;
> > +
> > + //
> > + // Disable MMC clock first
> > + //
> > + ClkEna = 0;
> > + MmioWrite32 (DevBase + DW_MMC_CLKENA, ClkEna);
> > +
> > + Status = DwMmcHcUpdateClock (DevBase);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > + return Status;
> > +}
> > +
> > +/**
> > + SD/MMC card clock supply.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] ClockFreq The max clock frequency to be set. The unit is
> KHz.
> > + @param[in] Capability The capability of the slot.
> > +
> > + @retval EFI_SUCCESS The clock is supplied successfully.
> > + @retval Others The clock isn't supplied successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcClockSupply (
> > + IN UINTN DevBase,
> > + IN UINT64 ClockFreq,
> > + IN DW_MMC_HC_SLOT_CAP Capability
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT32 BaseClkFreq;
> > + UINT32 SettingFreq;
> > + UINT32 Divisor;
> > + UINT32 Remainder;
> > + UINT32 MmcStatus;
> > + UINT32 ClkEna;
> > + UINT32 ClkSrc;
> > +
> > + //
> > + // Calculate a divisor for SD clock frequency
> > + //
> > + ASSERT (Capability.BaseClkFreq != 0);
> > +
> > + BaseClkFreq = Capability.BaseClkFreq;
> > + if (ClockFreq == 0) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if (ClockFreq > BaseClkFreq) {
> > + ClockFreq = BaseClkFreq;
> > + }
> > +
> > + //
> > + // Calculate the divisor of base frequency.
> > + //
> > + Divisor = 0;
> > + SettingFreq = BaseClkFreq;
> > + while (ClockFreq < SettingFreq) {
> > + Divisor++;
> > +
> > + SettingFreq = BaseClkFreq / (2 * Divisor);
> > + Remainder = BaseClkFreq % (2 * Divisor);
> > + if ((ClockFreq == SettingFreq) && (Remainder == 0)) {
> > + break;
> > + }
> > + if ((ClockFreq == SettingFreq) && (Remainder != 0)) {
> > + SettingFreq ++;
> > + }
> > + }
> > +
> > + DEBUG ((
> > + DEBUG_INFO,
> > + "BaseClkFreq %dKHz Divisor %d ClockFreq %dKhz\n",
> > + BaseClkFreq,
> > + Divisor,
> > + ClockFreq
> > + ));
> > +
> > + //
> > + // Wait until MMC is idle
> > + //
> > + do {
> > + MmcStatus = MmioRead32 (DevBase + DW_MMC_STATUS);
> > + } while (MmcStatus & DW_MMC_STS_DATA_BUSY);
> > +
> > + do {
> > + Status = DwMmcHcStopClock (DevBase);
> > + } while (EFI_ERROR (Status));
> > +
> > + do {
> > + ClkSrc = 0;
> > + MmioWrite32 (DevBase + DW_MMC_CLKSRC, ClkSrc);
> > + //
> > + // Set clock divisor
> > + //
> > + MmioWrite32 (DevBase + DW_MMC_CLKDIV, Divisor);
> > + //
> > + // Enable MMC clock
> > + //
> > + ClkEna = 1;
> > + MmioWrite32 (DevBase + DW_MMC_CLKENA, ClkEna);
> > +
> > + Status = DwMmcHcUpdateClock (DevBase);
> > + } while (EFI_ERROR (Status));
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Set the SD/MMC bus width.
> > +
> > + Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] IsDdr A boolean to indicate it's dual data rate or not.
> > + @param[in] BusWidth The bus width used by the SD/MMC device, it
> must be
> > + 1, 4 or 8.
> > +
> > + @retval EFI_SUCCESS The bus width is set successfully.
> > + @retval Others The bus width isn't set successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcSetBusWidth (
> > + IN UINTN DevBase,
> > + IN BOOLEAN IsDdr,
> > + IN UINT16 BusWidth
> > + )
> > +{
> > + UINT32 Ctype;
> > + UINT32 Uhs;
> > +
> > + switch (BusWidth) {
> > + case 1:
> > + Ctype = MMC_1BIT_MODE;
> > + break;
> > + case 4:
> > + Ctype = MMC_4BIT_MODE;
> > + break;
> > + case 8:
> > + Ctype = MMC_8BIT_MODE;
> > + break;
> > + default:
> > + return EFI_INVALID_PARAMETER;
> > + }
> > + MmioWrite32 (DevBase + DW_MMC_CTYPE, Ctype);
> > +
> > + Uhs = MmioRead32 (DevBase + DW_MMC_UHSREG);
> > +
> > + if (IsDdr) {
> > + Uhs |= UHS_DDR_MODE;
> > + } else {
> > + Uhs &= ~(UHS_DDR_MODE);
> > + }
> > +
> > + MmioWrite32 (DevBase + DW_MMC_UHSREG, Uhs);
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Supply SD/MMC card with lowest clock frequency at initialization.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] Capability The capability of the slot.
> > +
> > + @retval EFI_SUCCESS The clock is supplied successfully.
> > + @retval Others The clock isn't supplied successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcInitClockFreq (
> > + IN UINTN DevBase,
> > + IN DW_MMC_HC_SLOT_CAP Capability
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT32 InitFreq;
> > +
> > + //
> > + // Calculate a divisor for SD clock frequency
> > + //
> > + if (Capability.BaseClkFreq == 0) {
> > + //
> > + // Don't support get Base Clock Frequency information via another
> method
> > + //
> > + return EFI_UNSUPPORTED;
> > + }
> > + //
> > + // Supply 400KHz clock frequency at initialization phase.
> > + //
> > + InitFreq = DWMMC_INIT_CLOCK_FREQ;
> > + Status = DwMmcHcClockSupply (DevBase, InitFreq, Capability);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > + MicroSecondDelay (100);
> > + return Status;
> > +}
> > +
> > +/**
> > + Supply SD/MMC card with maximum voltage at initialization.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] Capability The capability of the slot.
> > +
> > + @retval EFI_SUCCESS The voltage is supplied successfully.
> > + @retval Others The voltage isn't supplied successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcInitPowerVoltage (
> > + IN UINTN DevBase,
> > + IN DW_MMC_HC_SLOT_CAP Capability
> > + )
> > +{
> > + UINT32 Data;
> > + UINT32 Timeout;
> > +
> > + Data = 0x1;
> > + MmioWrite32 (DevBase + DW_MMC_PWREN, Data);
> > +
> > + Data = DW_MMC_CTRL_RESET_ALL;
> > + MmioWrite32 (DevBase + DW_MMC_CTRL, Data);
> > +
> > + Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > + while (Timeout > 0) {
> > + Data = MmioRead32 (DevBase + DW_MMC_CTRL);
> > +
> > + if ((Data & DW_MMC_CTRL_RESET_ALL) == 0) {
> > + break;
> > + }
> > + gBS->Stall (1);
> > +
> > + Timeout--;
> > + }
> > +
> > + if (Timeout <= 0) {
> > + DEBUG ((DEBUG_INFO,
> > + "DwMmcHcInitPowerVoltage: reset failed due to timeout"));
> > +
> > + return EFI_TIMEOUT;
> > + }
> > +
> > + Data = DW_MMC_CTRL_INT_EN;
> > + MmioWrite32 (DevBase + DW_MMC_CTRL, Data);
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Initialize the Timeout Control register with most conservative value at
> > + initialization.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > +
> > + @retval EFI_SUCCESS The timeout control register is configured
> > + successfully.
> > + @retval Others The timeout control register isn't configured
> > + successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcInitTimeoutCtrl (
> > + IN UINTN DevBase
> > + )
> > +{
> > + UINT32 Data;
> > +
> > + Data = ~0;
> > + MmioWrite32 (DevBase + DW_MMC_TMOUT, Data);
> > +
> > + Data = 0x00FFFFFF;
> > + MmioWrite32 (DevBase + DW_MMC_DEBNCE, Data);
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Initial SD/MMC host controller with lowest clock frequency, max power
> and
> > + max timeout value at initialization.
> > +
> > + @param[in] DevIo The DEVICE IO protocol instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command
> > + to.
> > + @param[in] Capability The capability of the slot.
> > +
> > + @retval EFI_SUCCESS The host controller is initialized successfully.
> > + @retval Others The host controller isn't initialized successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcHcInitHost (
> > + IN UINTN DevBase,
> > + IN DW_MMC_HC_SLOT_CAP Capability
> > + )
> > +{
> > + EFI_STATUS Status;
> > +
> > + Status = DwMmcHcInitPowerVoltage (DevBase, Capability);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > + return Status;
> > +}
> > +
> > +EFI_STATUS
> > +DwMmcHcStartDma (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private,
> > + IN DW_MMC_HC_TRB *Trb
> > + )
> > +{
> > + UINTN DevBase;
> > + UINT32 Ctrl;
> > + UINT32 Bmod;
> > + UINT32 Timeout;
> > + UINT32 Data;
> > +
> > +// DevIo = Trb->Private->DevIo;
> > + DevBase = Trb->Private->DevBase;
> > +
> > + //
> > + // Reset DMA
> > + //
> > + Ctrl = DW_MMC_CTRL_DMA_RESET;
> > + MmioWrite32 (DevBase + DW_MMC_CTRL, Ctrl);
> > +
> > + Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > + while (Timeout > 0) {
> > + Data = MmioRead32 (DevBase + DW_MMC_CTRL);
> > +
> > + if ((Data & DW_MMC_CTRL_DMA_RESET) == 0) {
> > + break;
> > + }
> > + gBS->Stall (1);
> > +
> > + Timeout--;
> > + }
> > +
> > + if (Timeout <= 0) {
> > + DEBUG ((DEBUG_ERROR, "Timed out waiting for CTRL_DMA_RESET"));
> > +
> > + return EFI_TIMEOUT;
> > + }
> > +
> > + Bmod = DW_MMC_IDMAC_SWRESET | MmioRead32 (DevBase +
> DW_MMC_BMOD);
> > +
> > + MmioWrite32 (DevBase + DW_MMC_BMOD, Bmod);
> > +
> > + //
> > + // Select IDMAC
> > + //
> > + Ctrl = DW_MMC_CTRL_IDMAC_EN;
> > + Ctrl |= MmioRead32 (DevBase + DW_MMC_CTRL);
> > + MmioWrite32 (DevBase + DW_MMC_CTRL, Ctrl);
> > +
> > + //
> > + // Enable IDMAC
> > + //
> > + Bmod = DW_MMC_IDMAC_ENABLE | DW_MMC_IDMAC_FB;
> > + Bmod |= MmioRead32 (DevBase + DW_MMC_BMOD);
> > +
> > + MmioWrite32 (DevBase + DW_MMC_BMOD, Bmod);
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +EFI_STATUS
> > +DwMmcHcStopDma (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private,
> > + IN DW_MMC_HC_TRB *Trb
> > + )
> > +{
> > + UINTN DevBase;
> > + UINT32 Ctrl;
> > + UINT32 Bmod;
> > +
> > + DevBase = Trb->Private->DevBase;
> > +
> > + //
> > + // Disable and reset IDMAC
> > + //
> > + Ctrl = MmioRead32 (DevBase + DW_MMC_CTRL);
> > + Ctrl &= ~DW_MMC_CTRL_IDMAC_EN;
> > + Ctrl |= DW_MMC_CTRL_DMA_RESET;
> > + MmioWrite32 (DevBase + DW_MMC_CTRL, Ctrl);
> > +
> > + //
> > + // Stop IDMAC
> > + //
> > + Bmod = MmioRead32 (DevBase + DW_MMC_BMOD);
> > + Bmod &= ~(DW_MMC_BMOD_FB | DW_MMC_BMOD_DE);
> > + Bmod |= DW_MMC_BMOD_SWR;
> > + MmioWrite32 (DevBase + DW_MMC_BMOD, Bmod);
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Build DMA descriptor table for transfer.
> > +
> > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> > +
> > + @retval EFI_SUCCESS The DMA descriptor table is created
> successfully.
> > + @retval Others The DMA descriptor table isn't created successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +BuildDmaDescTable (
> > + IN DW_MMC_HC_TRB *Trb
> > + )
> > +{
> > + EFI_PHYSICAL_ADDRESS Data;
> > + UINT64 DataLen;
> > + UINT64 Entries;
> > + UINT32 Index;
> > + UINT64 Remaining;
> > + UINTN TableSize;
> > + UINTN DevBase;
> > + EFI_STATUS Status;
> > + UINTN Bytes;
> > + UINTN Blocks;
> > + DW_MMC_HC_DMA_DESC_LINE *DmaDesc;
> > + UINT32 DmaDescPhy;
> > + UINT32 Idsts;
> > + UINT32 BytCnt;
> > + UINT32 BlkSize;
> > +
> > + Data = Trb->DataPhy;
> > + DataLen = Trb->DataLen;
> > + DevBase = Trb->Private->DevBase;
> > + //
> > + // Only support 32bit DMA Descriptor Table
> > + //
> > + if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > + //
> > + // Address field shall be set on 32-bit boundary (Lower 2-bit is always set
> > + // to 0) for 32-bit address descriptor table.
> > + //
> > + if ((Data & (BIT0 | BIT1)) != 0) {
> > + DEBUG ((
> > + DEBUG_INFO,
> > + "The buffer [0x%x] to construct DMA desc is not aligned to 4 bytes!\n",
> > + Data
> > + ));
> > + }
> > +
> > + Entries = (DataLen + DWMMC_DMA_BUF_SIZE - 1) /
> DWMMC_DMA_BUF_SIZE;
> > + TableSize = Entries * sizeof (DW_MMC_HC_DMA_DESC_LINE);
> > + Blocks = (DataLen + DW_MMC_BLOCK_SIZE - 1) /
> DW_MMC_BLOCK_SIZE;
> > +
> > + Trb->DmaDescPages = (UINT32)EFI_SIZE_TO_PAGES (Entries *
> DWMMC_DMA_BUF_SIZE);
> > +/* Status = DevIo->AllocateBuffer (
> > + DevIo,
> > + AllocateAnyPages,
> > + EfiBootServicesData,
> > + EFI_SIZE_TO_PAGES (TableSize),
> > + (EFI_PHYSICAL_ADDRESS *)&Trb->DmaDesc
> > + );*/
> > + Status = DmaAllocateBuffer (EfiBootServicesData, EFI_SIZE_TO_PAGES
> (TableSize),
> > + (VOID *)&Trb->DmaDesc);
> > + if (EFI_ERROR (Status)) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + ZeroMem (Trb->DmaDesc, TableSize);
> > + Bytes = TableSize;
> > +
> > + Status = DmaMap (MapOperationBusMasterCommonBuffer,
> > + (EFI_PHYSICAL_ADDRESS *)Trb->DmaDesc,
> > + &Bytes, &Trb->DmaDescPhy, &Trb->DmaMap);
> > +/* Status = DevIo->Map (
> > + DevIo,
> > + EfiBusMasterCommonBuffer,
> > + (EFI_PHYSICAL_ADDRESS *)Trb->DmaDesc,
> > + &Bytes,
> > + &Trb->DmaDescPhy,
> > + &Trb->DmaMap
> > + );*/
> > +
> > + if (EFI_ERROR (Status) || (Bytes != TableSize)) {
> > + //
> > + // Map error or unable to map the whole RFis buffer into a contiguous
> > + // region.
> > + //
> > +/* DevIo->FreeBuffer (
> > + DevIo,
> > + EFI_SIZE_TO_PAGES (TableSize),
> > + (EFI_PHYSICAL_ADDRESS)Trb->DmaDesc
> > + );*/
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + if ((UINT64)(UINTN)Trb->DmaDescPhy > 0x100000000ul) {
> > + //
> > + // The DMA doesn't support 64bit addressing.
> > + //
> > + DmaUnmap (Trb->DmaMap);
> > +/* DevIo->Unmap (
> > + DevIo,
> > + Trb->DmaMap
> > + );*/
> > + return EFI_DEVICE_ERROR;
> > + }
> > +
> > + if (DataLen < DW_MMC_BLOCK_SIZE) {
> > + BlkSize = DataLen;
> > + BytCnt = DataLen;
> > + Remaining = DataLen;
> > + } else {
> > + BlkSize = DW_MMC_BLOCK_SIZE;
> > + BytCnt = DW_MMC_BLOCK_SIZE * Blocks;
> > + Remaining = DW_MMC_BLOCK_SIZE * Blocks;
> > + }
> > +
> > + MmioWrite32 (DevBase + DW_MMC_BLKSIZ, BlkSize);
> > + MmioWrite32 (DevBase + DW_MMC_BYTCNT, BytCnt);
> > + DmaDesc = Trb->DmaDesc;
> > + for (Index = 0; Index < Entries; Index++, DmaDesc++) {
> > + DmaDesc->Des0 = DW_MMC_IDMAC_DES0_OWN |
> DW_MMC_IDMAC_DES0_CH |
> > + DW_MMC_IDMAC_DES0_DIC;
> > + DmaDesc->Des1 = DW_MMC_IDMAC_DES1_BS1
> (DWMMC_DMA_BUF_SIZE);
> > + //
> > + // Buffer Address
> > + //
> > + DmaDesc->Des2 = (UINT32)((UINTN)Trb->DataPhy +
> > + (DWMMC_DMA_BUF_SIZE * Index));
> > + //
> > + // Next Descriptor Address
> > + //
> > + DmaDesc->Des3 = (UINT32)((UINTN)Trb->DmaDescPhy +
> > + sizeof (DW_MMC_HC_DMA_DESC_LINE) * (Index + 1));
> > + Remaining = Remaining - DWMMC_DMA_BUF_SIZE;
> > + }
> > + //
> > + // First Descriptor
> > + //
> > + Trb->DmaDesc[0].Des0 |= DW_MMC_IDMAC_DES0_FS;
> > + //
> > + // Last Descriptor
> > + //
> > + Trb->DmaDesc[Entries - 1].Des0 &= ~(DW_MMC_IDMAC_DES0_CH |
> > + DW_MMC_IDMAC_DES0_DIC);
> > + Trb->DmaDesc[Entries - 1].Des0 |= DW_MMC_IDMAC_DES0_OWN |
> > + DW_MMC_IDMAC_DES0_LD;
> > + Trb->DmaDesc[Entries - 1].Des1 = DW_MMC_IDMAC_DES1_BS1
> (Remaining +
> > + DWMMC_DMA_BUF_SIZE);
> > + //
> > + // Set the next field of the Last Descriptor
> > + //
> > + Trb->DmaDesc[Entries - 1].Des3 = 0;
> > + DmaDescPhy = (UINT32)Trb->DmaDescPhy;
> > +
> > + MmioWrite32 (DevBase + DW_MMC_DBADDR, DmaDescPhy);
> > +
> > + ArmDataSynchronizationBarrier ();
> > + ArmInstructionSynchronizationBarrier ();
> > + //
> > + // Clear interrupts
> > + //
> > + Idsts = ~0;
> > + MmioWrite32 (DevBase + DW_MMC_IDSTS, Idsts);
> > +
> > + return Status;
> > +}
> > +
> > +EFI_STATUS
> > +TransferFifo (
> > + IN DW_MMC_HC_TRB *Trb
> > + )
> > +{
> > + UINTN DevBase;
> > + UINT32 Data;
> > + UINT32 Received;
> > + UINT32 Count;
> > + UINT32 Intsts;
> > + UINT32 Sts;
> > + UINT32 FifoCount;
> > + UINT32 Index; /* count with bytes */
> > + UINT32 Ascending;
> > + UINT32 Descending;
> > +
> > + DevBase = Trb->Private->DevBase;
> > + Received = 0;
> > + Count = 0;
> > + Index = 0;
> > + Ascending = 0;
> > + Descending = ((Trb->DataLen + 3) & ~3) - 4;
> > + do {
> > + Intsts = MmioRead32 (DevBase + DW_MMC_RINTSTS);
> > +
> > + if (Trb->DataLen && (Intsts & DW_MMC_INT_TXDR) && !Trb->Read) {
> > + Sts = MmioRead32 (DevBase + DW_MMC_STATUS);
> > +
> > + while (!(DW_MMC_STS_FIFO_FULL(Sts))
> > + && (Received < Trb->DataLen)
> > + && (Intsts & DW_MMC_INT_TXDR)) {
> > + if (Trb->UseBE) {
> > + Data = SwapBytes32 (*(UINT32 *)((UINTN)Trb->Data + Descending));
> > + Descending = Descending - 4;
> > + } else {
> > + Data = *(UINT32 *)((UINTN)Trb->Data + Ascending);
> > + Ascending += 4;
> > + }
> > + Index += 4;
> > + Received += 4;
> > +
> > + MmioWrite32 (DevBase + DW_MMC_FIFO_START, Data);
> > +
> > + Intsts = DW_MMC_INT_TXDR;
> > + MmioWrite32 (DevBase + DW_MMC_RINTSTS, Intsts);
> > +
> > + Intsts = MmioRead32 (DevBase + DW_MMC_RINTSTS);
> > + Sts = MmioRead32 (DevBase + DW_MMC_STATUS);
> > + }
> > + continue;
> > + }
> > +
> > + if (Trb->DataLen && ((Intsts & DW_MMC_INT_RXDR) ||
> > + (Intsts & DW_MMC_INT_DTO)) && Trb->Read) {
> > + Sts = MmioRead32 (DevBase + DW_MMC_STATUS);
> > + //
> > + // Convert to bytes
> > + //
> > + FifoCount = GET_STS_FIFO_COUNT (Sts) << 2;
> > + if ((FifoCount == 0) && (Received < Trb->DataLen)) {
> > + continue;
> > + }
> > + Index = 0;
> > + Count = (MIN (FifoCount, Trb->DataLen) + 3) & ~3;
> > + while (Index < Count) {
> > + Data = MmioRead32 (DevBase + DW_MMC_FIFO_START);
> > +
> > + if (Trb->UseBE) {
> > + *(UINT32 *)((UINTN)Trb->Data + Descending) = SwapBytes32 (Data);
> > + Descending = Descending - 4;
> > + } else {
> > + *(UINT32 *)((UINTN)Trb->Data + Ascending) = Data;
> > + Ascending += 4;
> > + }
> > + Index += 4;
> > + Received += 4;
> > + } /* while */
> > + } /* if */
> > + } while (((Intsts & DW_MMC_INT_CMD_DONE) == 0) || (Received < Trb-
> >DataLen));
> > + //
> > + // Clear RINTSTS
> > + //
> > + Intsts = ~0;
> > + MmioWrite32 (DevBase + DW_MMC_RINTSTS, Intsts);
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Create a new TRB for the SD/MMC cmd request.
> > +
> > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA
> instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command
> > + to.
> > + @param[in] Packet A pointer to the SD command data structure.
> > + @param[in] Event If Event is NULL, blocking I/O is performed. If
> > + Event is not NULL, then nonblocking I/O is
> > + performed, and Event will be signaled when the
> > + Packet completes.
> > +
> > + @return Created Trb or NULL.
> > +
> > +**/
> > +DW_MMC_HC_TRB *
> > +DwMmcCreateTrb (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private,
> > + IN UINT8 Slot,
> > + IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
> > + IN EFI_EVENT Event
> > + )
> > +{
> > + DW_MMC_HC_TRB *Trb;
> > + EFI_STATUS Status;
> > + EFI_TPL OldTpl;
> > + EFI_IO_OPERATION_TYPE Flag;
> > + UINTN MapLength;
> > +
> > + Trb = AllocateZeroPool (sizeof (DW_MMC_HC_TRB));
> > + if (Trb == NULL) {
> > + return NULL;
> > + }
> > +
> > + Trb->Signature = DW_MMC_HC_TRB_SIG;
> > + Trb->Slot = Slot;
> > + Trb->BlockSize = 0x200;
> > + Trb->Packet = Packet;
> > + Trb->Event = Event;
> > + Trb->Started = FALSE;
> > + Trb->Timeout = Packet->Timeout;
> > + Trb->Private = Private;
> > +
> > + if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {
> > + Trb->Data = Packet->InDataBuffer;
> > + Trb->DataLen = Packet->InTransferLength;
> > + Trb->Read = TRUE;
> > + ZeroMem (Trb->Data, Trb->DataLen);
> > + } else if (Packet->OutTransferLength && (Packet->OutDataBuffer !=
> NULL)) {
> > + Trb->Data = Packet->OutDataBuffer;
> > + Trb->DataLen = Packet->OutTransferLength;
> > + Trb->Read = FALSE;
> > + } else if (!Packet->InTransferLength && !Packet->OutTransferLength) {
> > + Trb->Data = NULL;
> > + Trb->DataLen = 0;
> > + } else {
> > + goto Error;
> > + }
> > +
> > + if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) &&
> > + (Packet->SdMmcCmdBlk->CommandIndex ==
> EMMC_SEND_TUNING_BLOCK)) ||
> > + ((Private->Slot[Trb->Slot].CardType == SdCardType) &&
> > + (Packet->SdMmcCmdBlk->CommandIndex ==
> SD_SEND_TUNING_BLOCK))) {
> > + Trb->Mode = SdMmcPioMode;
> > + } else {
> > + if (Trb->Read) {
> > + Flag = EfiBusMasterWrite;
> > + } else {
> > + Flag = EfiBusMasterRead;
> > + }
> > +
> > + if (Private->Slot[Trb->Slot].CardType == SdCardType) {
> > + Trb->UseFifo = TRUE;
> > + } else {
> > + Trb->UseFifo = FALSE;
> > + if (Trb->DataLen) {
> > + MapLength = Trb->DataLen;
> > + Status = DmaMap (Flag, Trb->Data, &MapLength, &Trb->DataPhy,
> &Trb->DataMap);
> > +/* Status = DevIo->Map (
> > + DevIo,
> > + Flag,
> > + Trb->Data,
> > + &MapLength,
> > + &Trb->DataPhy,
> > + &Trb->DataMap
> > + );*/
> > + if (EFI_ERROR (Status) || (Trb->DataLen != MapLength)) {
> > + Status = EFI_BAD_BUFFER_SIZE;
> > + goto Error;
> > + }
> > +
> > + Status = BuildDmaDescTable (Trb);
> > + if (EFI_ERROR (Status)) {
> > + DmaUnmap(Trb->DataMap);
> > + goto Error;
> > + }
> > + Status = DwMmcHcStartDma (Private, Trb);
> > + if (EFI_ERROR (Status)) {
> > + DmaUnmap(Trb->DataMap);
> > + goto Error;
> > + }
> > + }
> > + }
> > + } /* TuningBlock */
> > +
> > + if (Event != NULL) {
> > + OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> > + InsertTailList (&Private->Queue, &Trb->TrbList);
> > + gBS->RestoreTPL (OldTpl);
> > + }
> > +
> > + return Trb;
> > +
> > +Error:
> > + return NULL;
> > +}
> > +
> > +/**
> > + Free the resource used by the TRB.
> > +
> > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> > +
> > +**/
> > +VOID
> > +DwMmcFreeTrb (
> > + IN DW_MMC_HC_TRB *Trb
> > + )
> > +{
> > + if (Trb->DmaMap != NULL) {
> > + DmaUnmap (Trb->DmaMap);
> > + }
> > + if (Trb->DataMap != NULL) {
> > + DmaUnmap (Trb->DataMap);
> > + }
> > + FreePool (Trb);
> > +}
> > +
> > +/**
> > + Check if the env is ready for execute specified TRB.
> > +
> > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA
> instance.
> > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> > +
> > + @retval EFI_SUCCESS The env is ready for TRB execution.
> > + @retval EFI_NOT_READY The env is not ready for TRB execution.
> > + @retval Others Some erros happen.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcCheckTrbEnv (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private,
> > + IN DW_MMC_HC_TRB *Trb
> > + )
> > +{
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Wait for the env to be ready for execute specified TRB.
> > +
> > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA
> instance.
> > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> > +
> > + @retval EFI_SUCCESS The env is ready for TRB execution.
> > + @retval EFI_TIMEOUT The env is not ready for TRB execution in time.
> > + @retval Others Some erros happen.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcWaitTrbEnv (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private,
> > + IN DW_MMC_HC_TRB *Trb
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
> > + UINT64 Timeout;
> > + BOOLEAN InfiniteWait;
> > +
> > + //
> > + // Wait Command Complete Interrupt Status bit in Normal Interrupt
> Status
> > + // Register
> > + //
> > + Packet = Trb->Packet;
> > + Timeout = Packet->Timeout;
> > + if (Timeout == 0) {
> > + InfiniteWait = TRUE;
> > + } else {
> > + InfiniteWait = FALSE;
> > + }
> > +
> > + while (InfiniteWait || (Timeout > 0)) {
> > + //
> > + // Check Trb execution result by reading Normal Interrupt Status
> register.
> > + //
> > + Status = DwMmcCheckTrbEnv (Private, Trb);
> > + if (Status != EFI_NOT_READY) {
> > + return Status;
> > + }
> > + //
> > + // Stall for 1 microsecond.
> > + //
> > + gBS->Stall (1);
> > +
> > + Timeout--;
> > + }
> > +
> > + return EFI_TIMEOUT;
> > +}
> > +
> > +EFI_STATUS
> > +DwEmmcExecTrb (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private,
> > + IN DW_MMC_HC_TRB *Trb
> > + )
> > +{
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
> > + UINTN DevBase;
> > + UINT32 Cmd;
> > + UINT32 MmcStatus;
> > + UINT32 IntStatus;
> > + UINT32 Argument;
> > + UINT32 ErrMask;
> > + UINT32 Timeout;
> > +
> > + Packet = Trb->Packet;
> > + DevBase = Trb->Private->DevBase;
> > +
> > + ArmDataSynchronizationBarrier ();
> > + ArmInstructionSynchronizationBarrier ();
> > + //
> > + // Wait until MMC is idle
> > + //
> > + do {
> > + MmcStatus = MmioRead32 (DevBase + DW_MMC_STATUS);
> > + } while (MmcStatus & DW_MMC_STS_DATA_BUSY);
> > +
> > + IntStatus = ~0;
> > + MmioWrite32 (DevBase + DW_MMC_RINTSTS, IntStatus);
> > + Cmd = CMD_INDEX (Packet->SdMmcCmdBlk->CommandIndex);
> > + if ((Packet->SdMmcCmdBlk->CommandType ==
> SdMmcCommandTypeAc) ||
> > + (Packet->SdMmcCmdBlk->CommandType ==
> SdMmcCommandTypeAdtc)) {
> > + switch (Packet->SdMmcCmdBlk->CommandIndex) {
> > + case EMMC_SET_RELATIVE_ADDR:
> > + Cmd |= BIT_CMD_SEND_INIT;
> > + break;
> > + case EMMC_SEND_STATUS:
> > + Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE;
> > + break;
> > + case EMMC_STOP_TRANSMISSION:
> > + Cmd |= BIT_CMD_STOP_ABORT_CMD;
> > + break;
> > + }
> > + if (Packet->InTransferLength) {
> > + Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE |
> BIT_CMD_DATA_EXPECTED |
> > + BIT_CMD_READ;
> > + } else if (Packet->OutTransferLength) {
> > + Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE |
> BIT_CMD_DATA_EXPECTED |
> > + BIT_CMD_WRITE;
> > + }
> > + Cmd |= BIT_CMD_RESPONSE_EXPECT |
> BIT_CMD_CHECK_RESPONSE_CRC;
> > + } else {
> > + switch (Packet->SdMmcCmdBlk->CommandIndex) {
> > + case EMMC_GO_IDLE_STATE:
> > + Cmd |= BIT_CMD_SEND_INIT;
> > + break;
> > + case EMMC_SEND_OP_COND:
> > + Cmd |= BIT_CMD_RESPONSE_EXPECT;
> > + break;
> > + case EMMC_ALL_SEND_CID:
> > + Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_LONG_RESPONSE |
> > + BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_SEND_INIT;
> > + break;
> > + }
> > + }
> > + switch (Packet->SdMmcCmdBlk->ResponseType) {
> > + case SdMmcResponseTypeR2:
> > + Cmd |= BIT_CMD_RESPONSE_EXPECT |
> BIT_CMD_CHECK_RESPONSE_CRC |
> > + BIT_CMD_LONG_RESPONSE;
> > + break;
> > + case SdMmcResponseTypeR3:
> > + Cmd |= BIT_CMD_RESPONSE_EXPECT;
> > + break;
> > + }
> > + Cmd |= BIT_CMD_USE_HOLD_REG | BIT_CMD_START;
> > +
> > + Argument = Packet->SdMmcCmdBlk->CommandArgument;
> > + MmioWrite32 (DevBase + DW_MMC_CMDARG, Argument);
> > +
> > + ArmDataSynchronizationBarrier ();
> > + ArmInstructionSynchronizationBarrier ();
> > +
> > + MmioWrite32 (DevBase + DW_MMC_CMD, Cmd);
> > + ArmDataSynchronizationBarrier ();
> > + ArmInstructionSynchronizationBarrier ();
> > +
> > + ErrMask = DW_MMC_INT_EBE | DW_MMC_INT_HLE |
> DW_MMC_INT_RTO |
> > + DW_MMC_INT_RCRC | DW_MMC_INT_RE;
> > + ErrMask |= DW_MMC_INT_DCRC | DW_MMC_INT_DRT |
> DW_MMC_INT_SBE;
> > + do {
> > + Timeout = 10000;
> > + if (--Timeout == 0) {
> > + break;
> > + }
> > + IntStatus = MmioRead32 (DevBase + DW_MMC_RINTSTS);
> > + if (IntStatus & ErrMask) {
> > + return EFI_DEVICE_ERROR;
> > + }
> > + if (Trb->DataLen && ((IntStatus & DW_MMC_INT_DTO) == 0)) {
> > + //
> > + // Transfer Not Done
> > + //
> > + MicroSecondDelay (10);
> > + continue;
> > + }
> > + MicroSecondDelay (10);
> > + } while (!(IntStatus & DW_MMC_INT_CMD_DONE));
> > + switch (Packet->SdMmcCmdBlk->ResponseType) {
> > + case SdMmcResponseTypeR1:
> > + case SdMmcResponseTypeR1b:
> > + case SdMmcResponseTypeR3:
> > + case SdMmcResponseTypeR4:
> > + case SdMmcResponseTypeR5:
> > + Packet->SdMmcStatusBlk->Resp0 = MmioRead32 (DevBase +
> DW_MMC_RESP0);
> > + break;
> > + case SdMmcResponseTypeR2:
> > + Packet->SdMmcStatusBlk->Resp0 = MmioRead32 (DevBase +
> DW_MMC_RESP0);
> > + Packet->SdMmcStatusBlk->Resp1 = MmioRead32 (DevBase +
> DW_MMC_RESP1);
> > + Packet->SdMmcStatusBlk->Resp2 = MmioRead32 (DevBase +
> DW_MMC_RESP2);
> > + Packet->SdMmcStatusBlk->Resp3 = MmioRead32 (DevBase +
> DW_MMC_RESP3);
> > + break;
> > + }
> > +
> > + //
> > + // The workaround on EMMC_SEND_CSD is used to be compatible with
> SDHC.
> > + //
> > + if (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_CSD) {
> > + {
> > + UINT32 Buf[4];
> > + ZeroMem (Buf, sizeof (Buf));
> > + CopyMem (
> > + (UINT8 *)Buf,
> > + (UINT8 *)&Packet->SdMmcStatusBlk->Resp0 + 1,
> > + sizeof (Buf) - 1
> > + );
> > + CopyMem (
> > + (UINT8 *)&Packet->SdMmcStatusBlk->Resp0,
> > + (UINT8 *)Buf,
> > + sizeof (Buf) - 1
> > + );
> > + }
> > + }
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +EFI_STATUS
> > +DwSdExecTrb (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private,
> > + IN DW_MMC_HC_TRB *Trb
> > + )
> > +{
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
> > + UINTN DevBase;
> > + UINT32 Cmd;
> > + UINT32 MmcStatus;
> > + UINT32 IntStatus;
> > + UINT32 Argument;
> > + UINT32 ErrMask;
> > + UINT32 Timeout;
> > + UINT32 Idsts;
> > + UINT32 BytCnt;
> > + UINT32 BlkSize;
> > + EFI_STATUS Status;
> > +
> > + Packet = Trb->Packet;
> > + DevBase = Trb->Private->DevBase;
> > +
> > + ArmDataSynchronizationBarrier ();
> > + ArmInstructionSynchronizationBarrier ();
> > + //
> > + // Wait until MMC is idle
> > + //
> > + do {
> > + MmcStatus = MmioRead32 (DevBase + DW_MMC_STATUS);
> > + } while (MmcStatus & DW_MMC_STS_DATA_BUSY);
> > +
> > + IntStatus = ~0;
> > + MmioWrite32 (DevBase + DW_MMC_RINTSTS, IntStatus);
> > + Cmd = CMD_INDEX (Packet->SdMmcCmdBlk->CommandIndex);
> > + if ((Packet->SdMmcCmdBlk->CommandType ==
> SdMmcCommandTypeAc) ||
> > + (Packet->SdMmcCmdBlk->CommandType ==
> SdMmcCommandTypeAdtc)) {
> > + switch (Packet->SdMmcCmdBlk->CommandIndex) {
> > + case SD_SET_RELATIVE_ADDR:
> > + Cmd |= BIT_CMD_SEND_INIT;
> > + break;
> > + case SD_STOP_TRANSMISSION:
> > + Cmd |= BIT_CMD_STOP_ABORT_CMD;
> > + break;
> > + case SD_SEND_SCR:
> > + Trb->UseBE = TRUE;
> > + break;
> > + }
> > + if (Packet->InTransferLength) {
> > + Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE |
> BIT_CMD_DATA_EXPECTED |
> > + BIT_CMD_READ;
> > + } else if (Packet->OutTransferLength) {
> > + Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE |
> BIT_CMD_DATA_EXPECTED |
> > + BIT_CMD_WRITE;
> > + }
> > + Cmd |= BIT_CMD_RESPONSE_EXPECT |
> BIT_CMD_CHECK_RESPONSE_CRC |
> > + BIT_CMD_SEND_AUTO_STOP;
> > + } else {
> > + switch (Packet->SdMmcCmdBlk->CommandIndex) {
> > + case SD_GO_IDLE_STATE:
> > + Cmd |= BIT_CMD_SEND_INIT;
> > + break;
> > + }
> > + }
> > + switch (Packet->SdMmcCmdBlk->ResponseType) {
> > + case SdMmcResponseTypeR2:
> > + Cmd |= BIT_CMD_RESPONSE_EXPECT |
> BIT_CMD_CHECK_RESPONSE_CRC |
> > + BIT_CMD_LONG_RESPONSE;
> > + break;
> > + case SdMmcResponseTypeR3:
> > + Cmd |= BIT_CMD_RESPONSE_EXPECT;
> > + break;
> > + case SdMmcResponseTypeR1b:
> > + case SdMmcResponseTypeR4:
> > + case SdMmcResponseTypeR6:
> > + case SdMmcResponseTypeR7:
> > + Cmd |= BIT_CMD_RESPONSE_EXPECT |
> BIT_CMD_CHECK_RESPONSE_CRC;
> > + break;
> > + }
> > + Cmd |= BIT_CMD_USE_HOLD_REG | BIT_CMD_START;
> > +
> > + if (Trb->UseFifo == TRUE) {
> > + BytCnt = Trb->Read ? Packet->InTransferLength : Packet-
> >OutTransferLength;
> > + MmioWrite32 (DevBase + DW_MMC_BYTCNT, BytCnt);
> > + if (Trb->Read) {
> > + if (Packet->InTransferLength > DW_MMC_BLOCK_SIZE) {
> > + BlkSize = DW_MMC_BLOCK_SIZE;
> > + } else {
> > + BlkSize = Packet->InTransferLength;
> > + }
> > + }
> > + else {
> > + if (Packet->OutTransferLength > DW_MMC_BLOCK_SIZE) {
> > + BlkSize = DW_MMC_BLOCK_SIZE;
> > + } else {
> > + BlkSize = Packet->OutTransferLength;
> > + }
> > + }
> > +
> > + MmioWrite32 (DevBase + DW_MMC_BLKSIZ, BlkSize);
> > + }
> > +
> > + Argument = Packet->SdMmcCmdBlk->CommandArgument;
> > + MmioWrite32 (DevBase + DW_MMC_CMDARG, Argument);
> > + ArmDataSynchronizationBarrier ();
> > + ArmInstructionSynchronizationBarrier ();
> > + MmioWrite32 (DevBase + DW_MMC_CMD, Cmd);
> > + ArmDataSynchronizationBarrier ();
> > + ArmInstructionSynchronizationBarrier ();
> > +
> > + ErrMask = DW_MMC_INT_EBE | DW_MMC_INT_HLE |
> DW_MMC_INT_RTO |
> > + DW_MMC_INT_RCRC | DW_MMC_INT_RE;
> > + ErrMask |= DW_MMC_INT_DRT | DW_MMC_INT_SBE;
> > + if (Packet->InTransferLength || Packet->OutTransferLength) {
> > + ErrMask |= DW_MMC_INT_DCRC;
> > + }
> > + if (Trb->UseFifo == TRUE) {
> > + Status = TransferFifo (Trb);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > + } else {
> > + Timeout = 10000;
> > + do {
> > + if (--Timeout == 0) {
> > + break;
> > + }
> > + IntStatus = MmioRead32 (DevBase + DW_MMC_RINTSTS);
> > + if (IntStatus & ErrMask) {
> > + return EFI_DEVICE_ERROR;
> > + }
> > + if (Trb->DataLen && ((IntStatus & DW_MMC_INT_DTO) == 0)) {
> > + //
> > + // Transfer not Done
> > + //
> > + MicroSecondDelay (10);
> > + continue;
> > + }
> > + MicroSecondDelay (10);
> > + } while (!(IntStatus & DW_MMC_INT_CMD_DONE));
> > + if (Packet->InTransferLength) {
> > + do {
> > + Idsts = MmioRead32 (DevBase + DW_MMC_IDSTS);
> > + } while ((Idsts & DW_MMC_IDSTS_RI) == 0);
> > + Status = DwMmcHcStopDma (Private, Trb);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > + } else if (Packet->OutTransferLength) {
> > + do {
> > + Idsts = MmioRead32 (DevBase + DW_MMC_IDSTS);
> > + } while ((Idsts & DW_MMC_IDSTS_TI) == 0);
> > + Status = DwMmcHcStopDma (Private, Trb);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > + } /* Packet->InTransferLength */
> > + } /* UseFifo */
> > + switch (Packet->SdMmcCmdBlk->ResponseType) {
> > + case SdMmcResponseTypeR1:
> > + case SdMmcResponseTypeR1b:
> > + case SdMmcResponseTypeR3:
> > + case SdMmcResponseTypeR4:
> > + case SdMmcResponseTypeR5:
> > + case SdMmcResponseTypeR6:
> > + case SdMmcResponseTypeR7:
> > + Packet->SdMmcStatusBlk->Resp0 = MmioRead32 (DevBase +
> DW_MMC_RESP0);
> > + break;
> > + case SdMmcResponseTypeR2:
> > + Packet->SdMmcStatusBlk->Resp0 = MmioRead32 (DevBase +
> DW_MMC_RESP0);
> > + Packet->SdMmcStatusBlk->Resp1 = MmioRead32 (DevBase +
> DW_MMC_RESP1);
> > + Packet->SdMmcStatusBlk->Resp2 = MmioRead32 (DevBase +
> DW_MMC_RESP2);
> > + Packet->SdMmcStatusBlk->Resp3 = MmioRead32 (DevBase +
> DW_MMC_RESP3);
> > + break;
> > + }
> > +
> > + //
> > + // The workaround on SD_SEND_CSD is used to be compatible with
> SDHC.
> > + //
> > + if (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_CSD) {
> > + {
> > + UINT32 Buf[4];
> > + ZeroMem (Buf, sizeof (Buf));
> > + CopyMem (
> > + (UINT8 *)Buf,
> > + (UINT8 *)&Packet->SdMmcStatusBlk->Resp0 + 1,
> > + sizeof (Buf) - 1
> > + );
> > + CopyMem (
> > + (UINT8 *)&Packet->SdMmcStatusBlk->Resp0,
> > + (UINT8 *)Buf,
> > + sizeof (Buf) - 1
> > + );
> > + }
> > + }
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Execute the specified TRB.
> > +
> > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA
> instance.
> > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> > +
> > + @retval EFI_SUCCESS The TRB is sent to host controller successfully.
> > + @retval Others Some erros happen when sending this request to
> the
> > + host controller.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcExecTrb (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private,
> > + IN DW_MMC_HC_TRB *Trb
> > + )
> > +{
> > + EFI_STATUS Status = EFI_SUCCESS;
> > + UINT32 Slot;
> > +
> > + Slot = Trb->Slot;
> > + if (Private->Slot[Slot].CardType == EmmcCardType) {
> > + Status = DwEmmcExecTrb (Private, Trb);
> > + } else if (Private->Slot[Slot].CardType == SdCardType) {
> > + Status = DwSdExecTrb (Private, Trb);
> > + } else {
> > + ASSERT (0);
> > + }
> > + return Status;
> > +}
> > +
> > +/**
> > + Check the TRB execution result.
> > +
> > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA
> instance.
> > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> > +
> > + @retval EFI_SUCCESS The TRB is executed successfully.
> > + @retval EFI_NOT_READY The TRB is not completed for execution.
> > + @retval Others Some erros happen when executing this request.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcCheckTrbResult (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private,
> > + IN DW_MMC_HC_TRB *Trb
> > + )
> > +{
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
> > + UINT32 Idsts;
> > + UINTN DevBase;
> > +
> > + DevBase = Private->DevBase;
> > + Packet = Trb->Packet;
> > + if (Trb->UseFifo == TRUE) {
> > + return EFI_SUCCESS;
> > + }
> > + if (Packet->InTransferLength) {
> > + do {
> > + Idsts = MmioRead32 (DevBase + DW_MMC_IDSTS);
> > + } while ((Idsts & BIT1) == 0);
> > + } else if (Packet->OutTransferLength) {
> > + do {
> > + Idsts = MmioRead32 (DevBase + DW_MMC_IDSTS);
> > + } while ((Idsts & BIT0) == 0);
> > + } else {
> > + return EFI_SUCCESS;
> > + }
> > + Idsts = ~0;
> > + MmioWrite32 (DevBase + DW_MMC_IDSTS, Idsts);
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Wait for the TRB execution result.
> > +
> > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA
> instance.
> > + @param[in] Trb The pointer to the DW_MMC_HC_TRB instance.
> > +
> > + @retval EFI_SUCCESS The TRB is executed successfully.
> > + @retval Others Some erros happen when executing this request.
> > +
> > +**/
> > +EFI_STATUS
> > +DwMmcWaitTrbResult (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private,
> > + IN DW_MMC_HC_TRB *Trb
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
> > + UINT64 Timeout;
> > + BOOLEAN InfiniteWait;
> > +
> > + Packet = Trb->Packet;
> > + //
> > + // Wait Command Complete Interrupt Status bit in Normal Interrupt
> Status
> > + // Register
> > + //
> > + Timeout = Packet->Timeout;
> > + if (Timeout == 0) {
> > + InfiniteWait = TRUE;
> > + } else {
> > + InfiniteWait = FALSE;
> > + }
> > +
> > + while (InfiniteWait || (Timeout > 0)) {
> > + //
> > + // Check Trb execution result by reading Normal Interrupt Status
> register.
> > + //
> > + Status = DwMmcCheckTrbResult (Private, Trb);
> > + if (Status != EFI_NOT_READY) {
> > + return Status;
> > + }
> > + //
> > + // Stall for 1 microsecond.
> > + //
> > + gBS->Stall (1);
> > +
> > + Timeout--;
> > + }
> > +
> > + return EFI_TIMEOUT;
> > +}
> > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
> b/EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
> > new file mode 100644
> > index 000000000000..b7a8688c4d2e
> > --- /dev/null
> > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
> > @@ -0,0 +1,1042 @@
> > +/** @file
> > + This file provides some helper functions which are specific for EMMC
> device.
> > +
> > + Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
> > + Copyright (c) 2018, Linaro. 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 <IndustryStandard/Emmc.h>
> > +
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/UefiBootServicesTableLib.h>
> > +
> > +#include "DwMmcHcDxe.h"
> > +
> > +#define EMMC_GET_STATE(x) (((x) >> 9) & 0xf)
> > +#define EMMC_STATE_IDLE 0
> > +#define EMMC_STATE_READY 1
> > +#define EMMC_STATE_IDENT 2
> > +#define EMMC_STATE_STBY 3
> > +#define EMMC_STATE_TRAN 4
> > +#define EMMC_STATE_DATA 5
> > +#define EMMC_STATE_RCV 6
> > +#define EMMC_STATE_PRG 7
> > +#define EMMC_STATE_DIS 8
> > +#define EMMC_STATE_BTST 9
> > +#define EMMC_STATE_SLP 10
> > +
> > +#define EMMC_CMD1_CAPACITY_LESS_THAN_2GB 0x00FF8080 //
> Capacity <= 2GB, byte addressing used
> > +#define EMMC_CMD1_CAPACITY_GREATER_THAN_2GB 0x40FF8080 //
> Capacity > 2GB, 512-byte sector addressing used
> > +
> > +/**
> > + Send command GO_IDLE_STATE (CMD0 with argument of 0x00000000) to
> the device to
> > + make it go to Idle State.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Slot The slot number of the SD card to send the
> command
> > + to.
> > +
> > + @retval EFI_SUCCESS The EMMC device is reset correctly.
> > + @retval Others The device reset fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcReset (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc;
> > + SdMmcCmdBlk.ResponseType = 0;
> > + SdMmcCmdBlk.CommandArgument = 0;
> > +
> > + gBS->Stall (1000);
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SEND_OP_COND to the EMMC device to get the data of
> the OCR
> > + register.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in, out] Argument On input, the argument of SEND_OP_COND
> is to send
> > + to the device.
> > + On output, the argument is the value of OCR
> > + register.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcGetOcr (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN OUT UINT32 *Argument
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;
> > + SdMmcCmdBlk.CommandArgument = *Argument;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > + if (!EFI_ERROR (Status)) {
> > + //
> > + // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
> > + //
> > + *Argument = SdMmcStatusBlk.Resp0;
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Broadcast command ALL_SEND_CID to the bus to ask all the EMMC
> devices to send
> > + the data of their CID registers.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcGetAllCid (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
> > + SdMmcCmdBlk.CommandArgument = 0;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SET_RELATIVE_ADDR to the EMMC device to assign a
> Relative device
> > + Address (RCA).
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Rca The relative device address to be assigned.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcSetRca (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT16 Rca
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> > + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SEND_CSD to the EMMC device to get the data of the
> CSD register.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Rca The relative device address of selected device.
> > + @param[out] Csd The buffer to store the content of the CSD
> register.
> > + Note the caller should ignore the lowest byte of
> > + this buffer as the content of this byte is
> > + meaningless even if the operation succeeds.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcGetCsd (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT16 Rca,
> > + OUT EMMC_CSD *Csd
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
> > + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > + if (!EFI_ERROR (Status)) {
> > + //
> > + // Copy 128bit data for CSD structure.
> > + //
> > + CopyMem ((VOID *)Csd + 1, &SdMmcStatusBlk.Resp0, sizeof
> (EMMC_CSD) - 1);
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SELECT_DESELECT_CARD to the EMMC device to
> select/deselect it.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Rca The relative device address of selected device.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcSelect (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT16 Rca
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> > + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SEND_EXT_CSD to the EMMC device to get the data of
> the EXT_CSD
> > + register.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[out] ExtCsd The buffer to store the content of the EXT_CSD
> > + register.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcGetExtCsd (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + OUT EMMC_EXT_CSD *ExtCsd
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> > + SdMmcCmdBlk.CommandArgument = 0x00000000;
> > +
> > + Packet.InDataBuffer = ExtCsd;
> > + Packet.InTransferLength = sizeof (EMMC_EXT_CSD);
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SWITCH to the EMMC device to switch the mode of
> operation of the
> > + selected Device or modifies the EXT_CSD registers.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Access The access mode of SWTICH command.
> > + @param[in] Index The offset of the field to be access.
> > + @param[in] Value The value to be set to the specified field of
> > + EXT_CSD register.
> > + @param[in] CmdSet The value of CmdSet field of EXT_CSD register.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcSwitch (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT8 Access,
> > + IN UINT8 Index,
> > + IN UINT8 Value,
> > + IN UINT8 CmdSet
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = EMMC_SWITCH;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
> > + SdMmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | \
> > + (Value << 8) | CmdSet;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SEND_STATUS to the addressed EMMC device to get its
> status
> > + register.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Rca The relative device address of addressed device.
> > + @param[out] DevStatus The returned device status.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcSendStatus (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT16 Rca,
> > + OUT UINT32 *DevStatus
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> > + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > + if (!EFI_ERROR (Status)) {
> > + *DevStatus = SdMmcStatusBlk.Resp0;
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SEND_TUNING_BLOCK to the EMMC device for HS200
> optimal sampling
> > + point detection.
> > +
> > + It may be sent up to 40 times until the host finishes the tuning
> procedure.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] BusWidth The bus width to work.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcSendTuningBlk (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT8 BusWidth
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > + UINT8 TuningBlock[128];
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> > + SdMmcCmdBlk.CommandArgument = 0;
> > +
> > + Packet.InDataBuffer = TuningBlock;
> > + if (BusWidth == 8) {
> > + Packet.InTransferLength = sizeof (TuningBlock);
> > + } else {
> > + Packet.InTransferLength = 64;
> > + }
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Tunning the clock to get HS200 optimal sampling point.
> > +
> > + Command SEND_TUNING_BLOCK may be sent up to 40 times until the
> host finishes
> > + the tuning procedure.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8.
> > +
> > + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL
> instance.
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] BusWidth The bus width to work.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcTuningClkForHs200 (
> > + IN UINTN DevBase,
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT8 BusWidth
> > + )
> > +{
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Switch the bus width to specified width.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9.
> > +
> > + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL
> instance.
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Rca The relative device address to be assigned.
> > + @param[in] IsDdr If TRUE, use dual data rate data simpling method.
> > + Otherwise use single data rate data simpling method.
> > + @param[in] BusWidth The bus width to be set, it could be 4 or 8.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcSwitchBusWidth (
> > + IN UINTN DevBase,
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT16 Rca,
> > + IN BOOLEAN IsDdr,
> > + IN UINT8 BusWidth
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT8 Access;
> > + UINT8 Index;
> > + UINT8 Value;
> > + UINT8 CmdSet;
> > + UINT32 DevStatus;
> > +
> > + //
> > + // Write Byte, the Value field is written into the byte pointed by Index.
> > + //
> > + Access = 0x03;
> > + Index = OFFSET_OF (EMMC_EXT_CSD, BusWidth);
> > + if (BusWidth == 1) {
> > + Value = 0;
> > + } else {
> > + if (BusWidth == 4) {
> > + Value = 1;
> > + } else if (BusWidth == 8) {
> > + Value = 2;
> > + } else {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if (IsDdr) {
> > + Value += 4;
> > + }
> > + }
> > +
> > + CmdSet = 0;
> > + Status = EmmcSwitch (PassThru, Access, Index, Value, CmdSet);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "EmmcSwitchBusWidth: Switch to bus width %d fails with %r\n",
> > + BusWidth,
> > + Status
> > + ));
> > + return Status;
> > + }
> > +
> > + do {
> > + Status = EmmcSendStatus (PassThru, Rca, &DevStatus);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "EmmcSwitchBusWidth: Send status fails with %r\n",
> > + Status
> > + ));
> > + return Status;
> > + }
> > + //
> > + // Check the switch operation is really successful or not.
> > + //
> > + } while ((DevStatus & 0xf) == EMMC_STATE_PRG);
> > +
> > + Status = DwMmcHcSetBusWidth (DevBase, IsDdr, BusWidth);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Switch the clock frequency to the specified value.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.
> > +
> > + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL
> instance.
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Rca The relative device address to be assigned.
> > + @param[in] HsTiming The value to be written to HS_TIMING field of
> > + EXT_CSD register.
> > + @param[in] ClockFreq The max clock frequency to be set, the unit is
> MHz.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcSwitchClockFreq (
> > + IN UINTN DevBase,
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT16 Rca,
> > + IN UINT8 HsTiming,
> > + IN UINT32 ClockFreq
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT8 Access;
> > + UINT8 Index;
> > + UINT8 Value;
> > + UINT8 CmdSet;
> > + UINT32 DevStatus;
> > + DW_MMC_HC_PRIVATE_DATA *Private;
> > +
> > + Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru);
> > + //
> > + // Write Byte, the Value field is written into the byte pointed by Index.
> > + //
> > + Access = 0x03;
> > + Index = OFFSET_OF (EMMC_EXT_CSD, HsTiming);
> > + Value = HsTiming;
> > + CmdSet = 0;
> > +
> > + Status = EmmcSwitch (PassThru, Access, Index, Value, CmdSet);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "EmmcSwitchClockFreq: Switch to hstiming %d fails with %r\n",
> > + HsTiming,
> > + Status
> > + ));
> > + return Status;
> > + }
> > +
> > + Status = EmmcSendStatus (PassThru, Rca, &DevStatus);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "EmmcSwitchClockFreq: Send status fails with %r\n",
> > + Status
> > + ));
> > + return Status;
> > + }
> > + //
> > + // Check the switch operation is really successful or not.
> > + //
> > + if ((DevStatus & BIT7) != 0) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "EmmcSwitchClockFreq: The switch operation fails as DevStatus
> 0x%08x\n",
> > + DevStatus
> > + ));
> > + return EFI_DEVICE_ERROR;
> > + }
> > + //
> > + // Convert the clock freq unit from MHz to KHz.
> > + //
> > + Status = DwMmcHcClockSupply (DevBase, ClockFreq * 1000, Private-
> >Capability[0]);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Switch to the High Speed timing according to request.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8.
> > +
> > + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL
> instance.
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Rca The relative device address to be assigned.
> > + @param[in] ClockFreq The max clock frequency to be set.
> > + @param[in] IsDdr If TRUE, use dual data rate data simpling method.
> > + Otherwise use single data rate data simpling method.
> > + @param[in] BusWidth The bus width to be set, it could be 4 or 8.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcSwitchToHighSpeed (
> > + IN UINTN DevBase,
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT16 Rca,
> > + IN UINT32 ClockFreq,
> > + IN BOOLEAN IsDdr,
> > + IN UINT8 BusWidth
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT8 HsTiming;
> > +
> > + HsTiming = 1;
> > + Status = EmmcSwitchClockFreq (DevBase, PassThru, Rca, HsTiming,
> ClockFreq);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > + Status = EmmcSwitchBusWidth (DevBase, PassThru, Rca, IsDdr,
> BusWidth);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Switch to the HS200 timing according to request.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8.
> > +
> > + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL
> instance.
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Rca The relative device address to be assigned.
> > + @param[in] ClockFreq The max clock frequency to be set.
> > + @param[in] BusWidth The bus width to be set, it could be 4 or 8.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcSwitchToHS200 (
> > + IN UINTN DevBase,
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT16 Rca,
> > + IN UINT32 ClockFreq,
> > + IN UINT8 BusWidth
> > + )
> > +{
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Switch the high speed timing according to request.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8.
> > +
> > + @param[in] DevIo A pointer to the EFI_DEVICE_IO_PROTOCOL
> instance.
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Rca The relative device address to be assigned.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcSetBusMode (
> > + IN UINTN DevBase,
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT16 Rca
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EMMC_CSD Csd;
> > + EMMC_EXT_CSD ExtCsd;
> > + UINT8 HsTiming;
> > + BOOLEAN IsDdr;
> > + UINT32 DevStatus;
> > + UINT32 ClockFreq;
> > + UINT8 BusWidth;
> > + DW_MMC_HC_PRIVATE_DATA *Private;
> > +
> > + Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru);
> > + ASSERT (Private->Capability[0].BaseClkFreq != 0);
> > +
> > + Status = EmmcGetCsd (PassThru, Rca, &Csd);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetCsd fails with %r\n",
> Status));
> > + return Status;
> > + }
> > +
> > + Status = EmmcSelect (PassThru, Rca);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: Select fails with %r\n",
> Status));
> > + return Status;
> > + }
> > +
> > + do {
> > + Status = EmmcSendStatus (PassThru, Rca, &DevStatus);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "EmmcSetBusMode: Get Status fails with %r\n",
> > + Status
> > + ));
> > + return Status;
> > + }
> > + } while (EMMC_GET_STATE (DevStatus) != EMMC_STATE_TRAN);
> > +
> > + BusWidth = 1;
> > + Status = EmmcSwitchBusWidth (DevBase, PassThru, Rca, FALSE,
> BusWidth);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + BusWidth = Private->Capability[0].BusWidth;
> > + //
> > + // Get Deivce_Type from EXT_CSD register.
> > + //
> > + Status = EmmcGetExtCsd (PassThru, &ExtCsd);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetExtCsd fails with
> %r\n", Status));
> > + return Status;
> > + }
> > +
> > + //
> > + // Calculate supported bus speed/bus width/clock frequency.
> > + //
> > + HsTiming = 0;
> > + IsDdr = FALSE;
> > + ClockFreq = 0;
> > + if (((ExtCsd.DeviceType & (BIT4 | BIT5)) != 0) &&
> > + (Private->Capability[0].Sdr104 != 0)) {
> > + HsTiming = 2;
> > + IsDdr = FALSE;
> > + ClockFreq = 200;
> > + } else if (((ExtCsd.DeviceType & (BIT2 | BIT3)) != 0) &&
> > + (Private->Capability[0].Ddr50 != 0)) {
> > + HsTiming = 1;
> > + IsDdr = TRUE;
> > + ClockFreq = 52;
> > + } else if (((ExtCsd.DeviceType & BIT1) != 0) &&
> > + (Private->Capability[0].HighSpeed != 0)) {
> > + HsTiming = 1;
> > + IsDdr = FALSE;
> > + ClockFreq = 52;
> > + } else if (((ExtCsd.DeviceType & BIT0) != 0) &&
> > + (Private->Capability[0].HighSpeed != 0)) {
> > + HsTiming = 1;
> > + IsDdr = FALSE;
> > + ClockFreq = 26;
> > + }
> > +
> > + if ((ClockFreq == 0) || (HsTiming == 0)) {
> > + //
> > + // Continue using default setting.
> > + //
> > + return EFI_SUCCESS;
> > + }
> > +
> > + DEBUG ((
> > + DEBUG_INFO,
> > + "EmmcSetBusMode: HsTiming %d ClockFreq %d BusWidth %d Ddr
> %a\n",
> > + HsTiming,
> > + ClockFreq,
> > + BusWidth,
> > + IsDdr ? "TRUE" : "FALSE"
> > + ));
> > +
> > + if (HsTiming == 2) {
> > + //
> > + // Execute HS200 timing switch procedure
> > + //
> > + Status = EmmcSwitchToHS200 (DevBase, PassThru, Rca, ClockFreq,
> BusWidth);
> > + } else {
> > + //
> > + // Execute High Speed timing switch procedure
> > + //
> > + Status = EmmcSwitchToHighSpeed (
> > + DevBase,
> > + PassThru,
> > + Rca,
> > + ClockFreq,
> > + IsDdr,
> > + BusWidth
> > + );
> > + }
> > +
> > + DEBUG ((
> > + DEBUG_INFO,
> > + "EmmcSetBusMode: Switch to %a %r\n",
> > + (HsTiming == 3) ? "HS400" : ((HsTiming == 2) ? "HS200" : "HighSpeed"),
> > + Status
> > + ));
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Execute EMMC device identification procedure.
> > +
> > + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
> > +
> > + @param[in] Private A pointer to the DW_MMC_HC_PRIVATE_DATA
> instance.
> > +
> > + @retval EFI_SUCCESS There is a EMMC card.
> > + @retval Others There is not a EMMC card.
> > +
> > +**/
> > +EFI_STATUS
> > +EmmcIdentification (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINTN DevBase;
> > + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
> > + UINT32 Ocr;
> > + UINT16 Rca;
> > + UINT32 DevStatus;
> > + UINT32 Timeout;
> > +
> > + DevBase = Private->DevBase;
> > + PassThru = &Private->PassThru;
> > +
> > + Status = EmmcReset (PassThru);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_INFO,
> > + "EmmcIdentification: Executing Cmd0 fails with %r\n",
> > + Status
> > + ));
> > + return Status;
> > + }
> > +
> > + Timeout = 100;
> > + do {
> > + Ocr = EMMC_CMD1_CAPACITY_GREATER_THAN_2GB;
> > + Status = EmmcGetOcr (PassThru, &Ocr);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_INFO,
> > + "EmmcIdentification: Executing Cmd1 fails with %r\n",
> > + Status
> > + ));
> > + return Status;
> > + }
> > + if (--Timeout <= 0) {
> > + return EFI_DEVICE_ERROR;
> > + }
> > + MicroSecondDelay (100);
> > + } while ((Ocr & BIT31) == 0);
> > +
> > + Status = EmmcGetAllCid (PassThru);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_INFO,
> > + "EmmcIdentification: Executing Cmd2 fails with %r\n",
> > + Status
> > + ));
> > + return Status;
> > + }
> > + //
> > + // valid RCA starts from 1.
> > + // Here we takes a simple formula to calculate the RCA.
> > + // Don't support multiple devices on the slot, that is
> > + // shared bus slot feature.
> > + //
> > + Rca = 1;
> > + Status = EmmcSetRca (PassThru, Rca);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_INFO,
> > + "EmmcIdentification: Executing Cmd3 fails with %r\n",
> > + Status
> > + ));
> > + return Status;
> > + }
> > + //
> > + // Enter Data Tranfer Mode.
> > + //
> > + DEBUG ((
> > + DEBUG_INFO,
> > + "EmmcIdentification: Found a EMMC device at RCA [%d]\n",
> > + Rca
> > + ));
> > + Private->Slot[0].CardType = EmmcCardType;
> > +
> > + Status = EmmcSetBusMode (DevBase, PassThru, Rca);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + //
> > + // Exit DATA Mode.
> > + //
> > + do {
> > + Status = EmmcSendStatus (PassThru, Rca, &DevStatus);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_INFO,
> > + "EmmcSwitchBusWidth: Send status fails with %r\n",
> > + Status
> > + ));
> > + return Status;
> > + }
> > + } while ((DevStatus & 0xf) == EMMC_STATE_DATA);
> > +
> > + return Status;
> > +}
> > diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
> b/EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
> > new file mode 100644
> > index 000000000000..63246637b6dd
> > --- /dev/null
> > +++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
> > @@ -0,0 +1,1105 @@
> > +/** @file
> > + This file provides some helper functions which are specific for SD card
> > + device.
> > +
> > + Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
> > + Copyright (c) 2018, Linaro. 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 <IndustryStandard/Sd.h>
> > +
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/DebugLib.h>
> > +
> > +#include "DwMmcHcDxe.h"
> > +
> > +/**
> > + Send command GO_IDLE_STATE to the device to make it go to Idle State.
> > +
> > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > +
> > + @retval EFI_SUCCESS The SD device is reset correctly.
> > + @retval Others The device reset fails.
> > +
> > +**/
> > +EFI_STATUS
> > +SdCardReset (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = SD_GO_IDLE_STATE;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > + //Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SEND_IF_COND to the device to inquiry the SD Memory
> Card
> > + interface condition.
> > +
> > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] SupplyVoltage The supplied voltage by the host.
> > + @param[in] CheckPattern The check pattern to be sent to the device.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +SdCardVoltageCheck (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT8 SupplyVoltage,
> > + IN UINT8 CheckPattern
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = SD_SEND_IF_COND;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR7;
> > + SdMmcCmdBlk.CommandArgument = (SupplyVoltage << 8) |
> CheckPattern;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > +
> > + if (!EFI_ERROR (Status)) {
> > + if (SdMmcStatusBlk.Resp0 != SdMmcCmdBlk.CommandArgument) {
> > + return EFI_DEVICE_ERROR;
> > + }
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SDIO_SEND_OP_COND to the device to see whether it is
> SDIO device.
> > +
> > + Refer to SDIO Simplified Spec 3 Section 3.2 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] VoltageWindow The supply voltage window.
> > + @param[in] S18R The boolean to show if it should switch to 1.8v.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +SdioSendOpCond (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT32 VoltageWindow,
> > + IN BOOLEAN S18R
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > + UINT32 Switch;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = SDIO_SEND_OP_COND;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR4;
> > +
> > + Switch = S18R ? BIT24 : 0;
> > +
> > + SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) |
> Switch;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SD_SEND_OP_COND to the device to see whether it is
> SDIO device.
> > +
> > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Rca The relative device address of addressed device.
> > + @param[in] VoltageWindow The supply voltage window.
> > + @param[in] S18R The boolean to show if it should switch to 1.8v.
> > + @param[in] Xpc The boolean to show if it should provide 0.36w
> > + power control.
> > + @param[in] Hcs The boolean to show if it support host capacity
> > + info.
> > + @param[out] Ocr The buffer to store returned OCR register value.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +SdCardSendOpCond (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT16 Rca,
> > + IN UINT32 VoltageWindow,
> > + IN BOOLEAN S18R,
> > + IN BOOLEAN Xpc,
> > + IN BOOLEAN Hcs,
> > + OUT UINT32 *Ocr
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > + UINT32 Switch;
> > + UINT32 MaxPower;
> > + UINT32 HostCapacity;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> > + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + SdMmcCmdBlk.CommandIndex = SD_SEND_OP_COND;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;
> > +
> > + Switch = S18R ? BIT24 : 0;
> > + MaxPower = Xpc ? BIT28 : 0;
> > + HostCapacity = Hcs ? BIT30 : 0;
> > +
> > + SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) |
> Switch | \
> > + MaxPower | HostCapacity;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > + if (!EFI_ERROR (Status)) {
> > + *Ocr = SdMmcStatusBlk.Resp0;
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Broadcast command ALL_SEND_CID to the bus to ask all the SD devices
> to send
> > + the data of their CID registers.
> > +
> > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +SdCardAllSendCid (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = SD_ALL_SEND_CID;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SET_RELATIVE_ADDR to the SD device to assign a
> Relative device
> > + Address (RCA).
> > +
> > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[out] Rca The relative device address to assign.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +SdCardSetRca (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + OUT UINT16 *Rca
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > + if (!EFI_ERROR (Status)) {
> > + *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SEND_CSD to the SD device to get the data of the CSD
> register.
> > +
> > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Rca The relative device address of selected device.
> > + @param[out] Csd The buffer to store the content of the CSD
> register.
> > + Note the caller should ignore the lowest byte of
> > + this buffer as the content of this byte is meaning-
> > + less even if the operation succeeds.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +SdCardGetCsd (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT16 Rca,
> > + OUT SD_CSD *Csd
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = SD_SEND_CSD;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
> > + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > + if (!EFI_ERROR (Status)) {
> > + CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof
> (SD_CSD) - 1);
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SEND_CSD to the SD device to get the data of the CSD
> register.
> > +
> > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Rca The relative device address of selected device.
> > + @param[out] Scr The buffer to store the content of the SCR
> register.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +SdCardGetScr (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT16 Rca,
> > + OUT SD_SCR *Scr
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> > + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + SdMmcCmdBlk.CommandIndex = SD_SEND_SCR;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> > +
> > + Packet.InDataBuffer = Scr;
> > + Packet.InTransferLength = sizeof (SD_SCR);
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SELECT_DESELECT_CARD to the SD device to
> select/deselect it.
> > +
> > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Rca The relative device address of selected device.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +SdCardSelect (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT16 Rca
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> > + if (Rca != 0) {
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
> > + }
> > + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command VOLTAGE_SWITCH to the SD device to switch the voltage
> of the
> > + device.
> > +
> > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +SdCardVoltageSwitch (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = SD_VOLTAGE_SWITCH;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> > + SdMmcCmdBlk.CommandArgument = 0;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SET_BUS_WIDTH to the SD device to set the bus width.
> > +
> > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Rca The relative device address of addressed device.
> > + @param[in] BusWidth The bus width to be set, it could be 1 or 4.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +SdCardSetBusWidth (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT16 Rca,
> > + IN UINT8 BusWidth
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > + UINT8 Value;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> > + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + SdMmcCmdBlk.CommandIndex = SD_SET_BUS_WIDTH;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> > +
> > + if (BusWidth == 1) {
> > + Value = 0;
> > + } else if (BusWidth == 4) {
> > + Value = 2;
> > + } else {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + SdMmcCmdBlk.CommandArgument = Value & 0x3;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SWITCH_FUNC to the SD device to check switchable
> function or
> > + switch card function.
> > +
> > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] AccessMode The value for access mode group.
> > + @param[in] CommandSystem The value for command set group.
> > + @param[in] DriveStrength The value for drive length group.
> > + @param[in] PowerLimit The value for power limit group.
> > + @param[in] Mode Switch or check function.
> > + @param[out] SwitchResp The return switch function status.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +SdCardSwitch (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT8 AccessMode,
> > + IN UINT8 CommandSystem,
> > + IN UINT8 DriveStrength,
> > + IN UINT8 PowerLimit,
> > + IN BOOLEAN Mode,
> > + OUT UINT8 *SwitchResp
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > + UINT32 ModeValue;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = SD_SWITCH_FUNC;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> > +
> > + ModeValue = Mode ? BIT31 : 0;
> > + SdMmcCmdBlk.CommandArgument = (AccessMode & 0xF) | \
> > + ((PowerLimit & 0xF) << 4) | \
> > + ((DriveStrength & 0xF) << 8) | \
> > + ((DriveStrength & 0xF) << 12) | \
> > + ModeValue;
> > +
> > + Packet.InDataBuffer = SwitchResp;
> > + Packet.InTransferLength = 64;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SEND_STATUS to the addressed SD device to get its
> status
> > + register.
> > +
> > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Rca The relative device address of addressed device.
> > + @param[out] DevStatus The returned device status.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +SdCardSendStatus (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT16 Rca,
> > + OUT UINT32 *DevStatus
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> > + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > + if (!EFI_ERROR (Status)) {
> > + *DevStatus = SdMmcStatusBlk.Resp0;
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Send command SEND_TUNING_BLOCK to the SD device for HS200
> optimal sampling
> > + point detection.
> > +
> > + It may be sent up to 40 times until the host finishes the tuning
> procedure.
> > +
> > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> > +
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +SdCardSendTuningBlk (
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru
> > + )
> > +{
> > + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
> > + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
> > + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
> > + EFI_STATUS Status;
> > + UINT8 TuningBlock[64];
> > +
> > + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
> > + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> > + ZeroMem (&Packet, sizeof (Packet));
> > +
> > + Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
> > + Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
> > + Packet.Timeout = DW_MMC_HC_GENERIC_TIMEOUT;
> > +
> > + SdMmcCmdBlk.CommandIndex = SD_SEND_TUNING_BLOCK;
> > + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
> > + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> > + SdMmcCmdBlk.CommandArgument = 0;
> > +
> > + Packet.InDataBuffer = TuningBlock;
> > + Packet.InTransferLength = sizeof (TuningBlock);
> > +
> > + Status = PassThru->PassThru (PassThru, 0, &Packet, NULL);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Switch the bus width to specified width.
> > +
> > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and
> > + SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.
> > +
> > + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Rca The relative device address to be assigned.
> > + @param[in] BusWidth The bus width to be set, it could be 4 or 8.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +SdCardSwitchBusWidth (
> > + IN UINTN DevBase,
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT16 Rca,
> > + IN BOOLEAN IsDdr,
> > + IN UINT8 BusWidth
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT32 DevStatus;
> > +
> > + Status = SdCardSetBusWidth (PassThru, Rca, BusWidth);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "SdCardSwitchBusWidth: Switch to bus width %d fails with %r\n",
> > + BusWidth,
> > + Status
> > + ));
> > + return Status;
> > + }
> > +
> > + Status = SdCardSendStatus (PassThru, Rca, &DevStatus);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "SdCardSwitchBusWidth: Send status fails with %r\n",
> > + Status
> > + ));
> > + return Status;
> > + }
> > + //
> > + // Check the switch operation is really successful or not.
> > + //
> > + if ((DevStatus >> 16) != 0) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "SdCardSwitchBusWidth: The switch operation fails as DevStatus
> 0x%08x\n",
> > + DevStatus
> > + ));
> > + return EFI_DEVICE_ERROR;
> > + }
> > +
> > + Status = DwMmcHcSetBusWidth (DevBase, IsDdr, BusWidth);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Switch the high speed timing according to request.
> > +
> > + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> > +
> > + @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
> > + @param[in] PassThru A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL
> > + instance.
> > + @param[in] Rca The relative device address to be assigned.
> > + @param[in] S18A The boolean to show if it's a UHS-I SD card.
> > + @param[in] BusWidths The bus width of the SD card.
> > +
> > + @retval EFI_SUCCESS The operation is done correctly.
> > + @retval Others The operation fails.
> > +
> > +**/
> > +EFI_STATUS
> > +SdCardSetBusMode (
> > + IN UINTN DevBase,
> > + IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
> > + IN UINT16 Rca,
> > + IN BOOLEAN S18A,
> > + IN UINT32 BusWidths
> > + )
> > +{
> > + EFI_STATUS Status;
> > + DW_MMC_HC_SLOT_CAP *Capability;
> > + UINT32 ClockFreq;
> > + UINT8 AccessMode;
> > + UINT8 SwitchResp[64];
> > + DW_MMC_HC_PRIVATE_DATA *Private;
> > + BOOLEAN IsDdr;
> > +
> > + Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru);
> > +
> > + Capability = &Private->Capability[0];
> > +
> > + if ((Capability->BusWidth == 1) || (Capability->BusWidth == 4)) {
> > + BusWidths &= Capability[0].BusWidth;
> > + } else {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "SdCardSetBusMode: BusWidths (%d) in capability are wrong\n",
> > + Capability->BusWidth
> > + ));
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if (BusWidths == 0) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "SdCardSetBusMode: Get wrong BusWidths:%d\n",
> > + BusWidths
> > + ));
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if (Private->Capability[0].Ddr50) {
> > + IsDdr = TRUE;
> > + } else {
> > + IsDdr = FALSE;
> > + }
> > +
> > + Status = SdCardSwitchBusWidth (DevBase, PassThru, Rca, IsDdr,
> BusWidths);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "SdCardSetBusMode: Executing SdCardSwitchBusWidth fails with
> %r\n",
> > + Status
> > + ));
> > + return Status;
> > + }
> > +
> > + //
> > + // Get the supported bus speed from SWITCH cmd return data group #1.
> > + //
> > + Status = SdCardSwitch (PassThru, 0xF, 0xF, 0xF, 0xF, FALSE, SwitchResp);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > + //
> > + // Calculate supported bus speed/bus width/clock frequency by host and
> device
> > + // capability.
> > + //
> > + ClockFreq = 0;
> > + if (S18A && (Capability->Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) {
> > + ClockFreq = 208;
> > + AccessMode = 3;
> > + } else if (S18A && (Capability->Sdr50 != 0) &&
> > + ((SwitchResp[13] & BIT2) != 0)) {
> > + ClockFreq = 100;
> > + AccessMode = 2;
> > + } else if (S18A && (Capability->Ddr50 != 0) &&
> > + ((SwitchResp[13] & BIT4) != 0)) {
> > + ClockFreq = 50;
> > + AccessMode = 4;
> > + } else if ((SwitchResp[13] & BIT1) != 0) {
> > + ClockFreq = 50;
> > + AccessMode = 1;
> > + } else {
> > + ClockFreq = 25;
> > + AccessMode = 0;
> > + }
> > +
> > + Status = SdCardSwitch (PassThru, AccessMode, 0xF, 0xF, 0xF, TRUE,
> SwitchResp);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + if ((SwitchResp[16] & 0xF) != AccessMode) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "SdCardSetBusMode: Switch to AccessMode %d ClockFreq %d fails!
> The Switch response is 0x%1x\n",
> > + AccessMode,
> > + ClockFreq,
> > + SwitchResp[16] & 0xF
> > + ));
> > + return EFI_DEVICE_ERROR;
> > + }
> > +
> > + DEBUG ((
> > + DEBUG_INFO,
> > + "SdCardSetBusMode: Switch to AccessMode %d ClockFreq %d \n",
> > + AccessMode,
> > + ClockFreq
> > + ));
> > +
> > + Status = DwMmcHcClockSupply (DevBase, ClockFreq * 1000, *Capability);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +EFI_STATUS
> > +SdCardIdentification (
> > + IN DW_MMC_HC_PRIVATE_DATA *Private
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINTN DevBase;
> > + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
> > + UINT32 Ocr;
> > + UINT16 Rca;
> > + BOOLEAN Xpc;
> > + BOOLEAN S18r;
> > + UINT64 MaxCurrent;
> > + SD_SCR Scr;
> > + SD_CSD Csd;
> > +
> > + DevBase = Private->DevBase;
> > + PassThru = &Private->PassThru;
> > + //
> > + // 1. Send Cmd0 to the device
> > + //
> > + Status = SdCardReset (PassThru);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_INFO,
> > + "SdCardIdentification: Executing Cmd0 fails with %r\n",
> > + Status
> > + ));
> > + return Status;
> > + }
> > + MicroSecondDelay (10000);
> > + //
> > + // 2. Send Cmd8 to the device
> > + //
> > + Status = SdCardVoltageCheck (PassThru, 0x1, 0xFF);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_INFO,
> > + "SdCardIdentification: Executing Cmd8 fails with %r\n",
> > + Status
> > + ));
> > + return Status;
> > + }
> > + //
> > + // 3. Send Acmd41 with voltage window 0 to the device
> > + //
> > + Status = SdCardSendOpCond (PassThru, 0, 0, FALSE, FALSE, FALSE, &Ocr);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_INFO,
> > + "SdCardIdentification: Executing SdCardSendOpCond fails with %r\n",
> > + Status
> > + ));
> > + return EFI_DEVICE_ERROR;
> > + }
> > +
> > + if (Private->Capability[0].Voltage33 != 0) {
> > + //
> > + // Support 3.3V
> > + //
> > + MaxCurrent = ((UINT32)Private->MaxCurrent[0] & 0xFF) * 4;
> > + S18r = FALSE;
> > + } else if (Private->Capability[0].Voltage30 != 0) {
> > + //
> > + // Support 3.0V
> > + //
> > + MaxCurrent = (((UINT32)Private->MaxCurrent[0] >> 8) & 0xFF) * 4;
> > + S18r = FALSE;
> > + } else if (Private->Capability[0].Voltage18 != 0) {
> > + //
> > + // Support 1.8V
> > + //
> > + MaxCurrent = (((UINT32)Private->MaxCurrent[0] >> 16) & 0xFF) * 4;
> > + S18r = TRUE;
> > + } else {
> > + ASSERT (FALSE);
> > + return EFI_DEVICE_ERROR;
> > + }
> > +
> > + if (MaxCurrent >= 150) {
> > + Xpc = TRUE;
> > + } else {
> > + Xpc = FALSE;
> > + }
> > +
> > + //
> > + // 4. Repeatly send Acmd41 with supply voltage window to the device.
> > + // Note here we only support the cards complied with SD physical
> > + // layer simplified spec version 2.0 and version 3.0 and above.
> > + //
> > + do {
> > + Status = SdCardSendOpCond (PassThru, 0, Ocr, S18r, Xpc, TRUE, &Ocr);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "SdCardIdentification: SdCardSendOpCond fails with %r Ocr %x, S18r
> %x, Xpc %x\n",
> > + Status,
> > + Ocr,
> > + S18r,
> > + Xpc
> > + ));
> > + return EFI_DEVICE_ERROR;
> > + }
> > + } while ((Ocr & BIT31) == 0);
> > +
> > + Status = SdCardAllSendCid (PassThru);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "SdCardIdentification: Executing SdCardAllSendCid fails with %r\n",
> > + Status
> > + ));
> > + return Status;
> > + }
> > +
> > + Status = SdCardSetRca (PassThru, &Rca);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "SdCardIdentification: Executing SdCardSetRca fails with %r\n",
> > + Status
> > + ));
> > + return Status;
> > + }
> > +
> > + Status = SdCardGetCsd (PassThru, Rca, &Csd);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "SdCardIdentification: Executing SdCardGetCsd fails with %r\n",
> > + Status
> > + ));
> > + return Status;
> > + }
> > +
> > + Status = SdCardSelect (PassThru, Rca);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "SdCardIdentification: Selecting card fails with %r\n",
> > + Status
> > + ));
> > + return Status;
> > + }
> > +
> > + Status = SdCardGetScr (PassThru, Rca, &Scr);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((
> > + DEBUG_ERROR,
> > + "SdCardIdentification: Executing SdCardGetScr fails with %r\n",
> > + Status
> > + ));
> > + return Status;
> > + }
> > +
> > + //
> > + // Enter Data Tranfer Mode.
> > + //
> > + DEBUG ((DEBUG_INFO, "SdCardIdentification: Found a SD device\n"));
> > + Private->Slot[0].CardType = SdCardType;
> > +
> > + Status = SdCardSetBusMode (DevBase, PassThru, Rca, S18r,
> Scr.SdBusWidths);
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + Private->Slot[0].Initialized = TRUE;
> > +
> > + return Status;
> > +}
> > --
> > 2.12.3
> >
> >
> >
> >
> >
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2021-03-22 3:32 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-03-19 8:22 [PATCH V4 1/1] EmbeddedPkg: DwMmcHcDxe: Add support for Designware SDMMC driver Loh, Tien Hock
2021-03-19 8:22 ` Loh, Tien Hock
2021-03-19 15:33 ` [edk2-devel] " Michael D Kinney
2021-03-22 3:32 ` Loh, Tien Hock
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox