* [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