diff options
author | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
---|---|---|
committer | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe')
10 files changed, 8782 insertions, 0 deletions
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/ComponentName.c new file mode 100644 index 000000000..85a5ce841 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/ComponentName.c @@ -0,0 +1,205 @@ +/** @file
+ UEFI Component Name(2) protocol implementation for SD/MMC host controller driver.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdMmcPciHcDxe.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSdMmcPciHcComponentName = {
+ SdMmcPciHcComponentNameGetDriverName,
+ SdMmcPciHcComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSdMmcPciHcComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SdMmcPciHcComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SdMmcPciHcComponentNameGetControllerName,
+ "en"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdMmcPciHcDriverNameTable[] = {
+ { "eng;en", L"Edkii Sd/Mmc Host Controller Driver" },
+ { NULL , NULL }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdMmcPciHcControllerNameTable[] = {
+ { "eng;en", L"Edkii 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
+SdMmcPciHcComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mSdMmcPciHcDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gSdMmcPciHcComponentName)
+ );
+}
+
+/**
+ 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
+SdMmcPciHcComponentNameGetControllerName (
+ 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,
+ gSdMmcPciHcDriverBinding.DriverBindingHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mSdMmcPciHcControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gSdMmcPciHcComponentName)
+ );
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c new file mode 100644 index 000000000..8b5f8e8ee --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c @@ -0,0 +1,1363 @@ +/** @file
+ This file provides some helper functions which are specific for EMMC device.
+
+ Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdMmcPciHcDxe.h"
+
+/**
+ 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,
+ IN UINT8 Slot
+ )
+{
+ 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 = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc;
+ SdMmcCmdBlk.ResponseType = 0;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ gBS->Stall (1000);
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &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] Slot The slot number of the SD card to send the command to.
+ @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 UINT8 Slot,
+ 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 = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;
+ SdMmcCmdBlk.CommandArgument = *Argument;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &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.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcGetAllCid (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ 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 = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &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] Slot The slot number of the SD card to send the command to.
+ @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 UINT8 Slot,
+ 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 = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &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] Slot The slot number of the SD card to send the command to.
+ @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 UINT8 Slot,
+ 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 = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ CopyMem (((UINT8*)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] Slot The slot number of the SD card to send the command to.
+ @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 UINT8 Slot,
+ 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 = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &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[in] Slot The slot number of the SD card to send the command to.
+ @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,
+ IN UINT8 Slot,
+ 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 = SD_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 = SdMmcPassThruPassThru (PassThru, Slot, &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] Slot The slot number of the SD card to send the command to.
+ @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 Slot,
+ 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 = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SWITCH;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
+ SdMmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | (Value << 8) | CmdSet;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &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] Slot The slot number of the SD card to send the command to.
+ @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 UINT8 Slot,
+ 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 = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &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] Slot The slot number of the SD card to send the command to.
+ @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 Slot,
+ 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 = SD_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 = SdMmcPassThruPassThru (PassThru, Slot, &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 and SD Host Controller
+ Simplified Spec 3.0 Figure 2-29 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] Slot The slot number of the SD card to send the command to.
+ @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 EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl2;
+ UINT8 Retry;
+
+ //
+ // Notify the host that the sampling clock tuning procedure starts.
+ //
+ HostCtrl2 = BIT6;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.
+ //
+ Retry = 0;
+ do {
+ Status = EmmcSendTuningBlk (PassThru, Slot, BusWidth);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcTuningClkForHs200: Send tuning block fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((HostCtrl2 & (BIT6 | BIT7)) == 0) {
+ break;
+ }
+
+ if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {
+ return EFI_SUCCESS;
+ }
+ } while (++Retry < 40);
+
+ DEBUG ((DEBUG_ERROR, "EmmcTuningClkForHs200: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2));
+ //
+ // Abort the tuning procedure and reset the tuning circuit.
+ //
+ HostCtrl2 = (UINT8)~(BIT6 | BIT7);
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Check the SWITCH operation status.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number on which command should be sent.
+ @param[in] Rca The relative device address.
+
+ @retval EFI_SUCCESS The SWITCH finished siccessfully.
+ @retval others The SWITCH failed.
+**/
+EFI_STATUS
+EmmcCheckSwitchStatus (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca
+ )
+{
+ EFI_STATUS Status;
+ UINT32 DevStatus;
+
+ Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcCheckSwitchStatus: 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, "EmmcCheckSwitchStatus: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Switch the bus width to specified width.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9 and SD Host Controller
+ Simplified Spec 3.0 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] Slot The slot number of the SD card to send the command to.
+ @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 EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN BOOLEAN IsDdr,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Access;
+ UINT8 Index;
+ UINT8 Value;
+ UINT8 CmdSet;
+
+ //
+ // Write Byte, the Value field is written into the byte pointed by Index.
+ //
+ Access = 0x03;
+ Index = OFFSET_OF (EMMC_EXT_CSD, BusWidth);
+ 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, Slot, 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;
+ }
+
+ Status = EmmcCheckSwitchStatus (PassThru, Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth);
+
+ return Status;
+}
+
+/**
+ Switch the bus timing and clock frequency.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6 and SD Host Controller
+ Simplified Spec 3.0 Figure 3-3 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] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] DriverStrength Driver strength to set for speed modes that support it.
+ @param[in] BusTiming The bus mode timing indicator.
+ @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
+EmmcSwitchBusTiming (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN EDKII_SD_MMC_DRIVER_STRENGTH DriverStrength,
+ IN SD_MMC_BUS_MODE BusTiming,
+ IN UINT32 ClockFreq
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Access;
+ UINT8 Index;
+ UINT8 Value;
+ UINT8 CmdSet;
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ UINT8 HostCtrl1;
+ BOOLEAN DelaySendStatus;
+
+ Private = SD_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);
+ CmdSet = 0;
+ switch (BusTiming) {
+ case SdMmcMmcHs400:
+ Value = (UINT8)((DriverStrength.Emmc << 4) | 3);
+ break;
+ case SdMmcMmcHs200:
+ Value = (UINT8)((DriverStrength.Emmc << 4) | 2);
+ break;
+ case SdMmcMmcHsSdr:
+ case SdMmcMmcHsDdr:
+ Value = 1;
+ break;
+ case SdMmcMmcLegacy:
+ Value = 0;
+ break;
+ default:
+ DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Unsupported BusTiming(%d)\n", BusTiming));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EmmcSwitch (PassThru, Slot, Access, Index, Value, CmdSet);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Switch to bus timing %d fails with %r\n", BusTiming, Status));
+ return Status;
+ }
+
+ if (BusTiming == SdMmcMmcHsSdr || BusTiming == SdMmcMmcHsDdr) {
+ HostCtrl1 = BIT2;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ HostCtrl1 = (UINT8)~BIT2;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, BusTiming);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // For cases when we switch bus timing to higher mode from current we want to
+ // send SEND_STATUS at current, lower, frequency then the target frequency to avoid
+ // stability issues. It has been observed that some designs are unable to process the
+ // SEND_STATUS at higher frequency during switch to HS200 @200MHz irrespective of the number of retries
+ // and only running the clock tuning is able to make them work at target frequency.
+ //
+ // For cases when we are downgrading the frequency and current high frequency is invalid
+ // we have to first change the frequency to target frequency and then send the SEND_STATUS.
+ //
+ if (Private->Slot[Slot].CurrentFreq < (ClockFreq * 1000)) {
+ Status = EmmcCheckSwitchStatus (PassThru, Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DelaySendStatus = FALSE;
+ } else {
+ DelaySendStatus = TRUE;
+ }
+
+ //
+ // Convert the clock freq unit from MHz to KHz.
+ //
+ Status = SdMmcHcClockSupply (Private, Slot, BusTiming, FALSE, ClockFreq * 1000);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (DelaySendStatus) {
+ Status = EmmcCheckSwitchStatus (PassThru, Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Switch to the High Speed timing according to request.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 Figure 2-29 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] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] BusMode Pointer to SD_MMC_BUS_SETTINGS structure containing bus settings.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchToHighSpeed (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN SD_MMC_BUS_SETTINGS *BusMode
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN IsDdr;
+
+ if ((BusMode->BusTiming != SdMmcMmcHsSdr && BusMode->BusTiming != SdMmcMmcHsDdr && BusMode->BusTiming != SdMmcMmcLegacy) ||
+ BusMode->ClockFreq > 52) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BusMode->BusTiming == SdMmcMmcHsDdr) {
+ IsDdr = TRUE;
+ } else {
+ IsDdr = FALSE;
+ }
+
+ Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, IsDdr, BusMode->BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);
+}
+
+/**
+ Switch to the HS200 timing. This function assumes that eMMC bus is still in legacy mode.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 Figure 2-29 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] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] BusMode Pointer to SD_MMC_BUS_SETTINGS structure containing bus settings.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchToHS200 (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN SD_MMC_BUS_SETTINGS *BusMode
+ )
+{
+ EFI_STATUS Status;
+
+ if (BusMode->BusTiming != SdMmcMmcHs200 ||
+ (BusMode->BusWidth != 4 && BusMode->BusWidth != 8)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, FALSE, BusMode->BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcTuningClkForHs200 (PciIo, PassThru, Slot, BusMode->BusWidth);
+
+ return Status;
+}
+
+/**
+ Switch to the HS400 timing. This function assumes that eMMC bus is still in legacy mode.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 Figure 2-29 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] Slot The slot number of the SD card to send the command to.
+ @param[in] Rca The relative device address to be assigned.
+ @param[in] BusMode Pointer to SD_MMC_BUS_SETTINGS structure containing bus settings.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchToHS400 (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN SD_MMC_BUS_SETTINGS *BusMode
+ )
+{
+ EFI_STATUS Status;
+ SD_MMC_BUS_SETTINGS Hs200BusMode;
+ UINT32 HsFreq;
+
+ if (BusMode->BusTiming != SdMmcMmcHs400 ||
+ BusMode->BusWidth != 8) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Hs200BusMode.BusTiming = SdMmcMmcHs200;
+ Hs200BusMode.BusWidth = BusMode->BusWidth;
+ Hs200BusMode.ClockFreq = BusMode->ClockFreq;
+ Hs200BusMode.DriverStrength = BusMode->DriverStrength;
+
+ Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, &Hs200BusMode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Set to High Speed timing and set the clock frequency to a value less than or equal to 52MHz.
+ // This step is necessary to be able to switch Bus into 8 bit DDR mode which is unsupported in HS200.
+ //
+ HsFreq = BusMode->ClockFreq < 52 ? BusMode->ClockFreq : 52;
+ Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, SdMmcMmcHsSdr, HsFreq);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, TRUE, BusMode->BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);
+}
+
+/**
+ Check if passed BusTiming is supported in both controller and card.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] ExtCsd Pointer to the card's extended CSD
+ @param[in] BusTiming Bus timing to check
+
+ @retval TRUE Both card and controller support given BusTiming
+ @retval FALSE Card or controller doesn't support given BusTiming
+**/
+BOOLEAN
+EmmcIsBusTimingSupported (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN EMMC_EXT_CSD *ExtCsd,
+ IN SD_MMC_BUS_MODE BusTiming
+ )
+{
+ BOOLEAN Supported;
+ SD_MMC_HC_SLOT_CAP *Capabilities;
+
+ Capabilities = &Private->Capability[SlotIndex];
+
+ Supported = FALSE;
+ switch (BusTiming) {
+ case SdMmcMmcHs400:
+ if ((((ExtCsd->DeviceType & (BIT6 | BIT7)) != 0) && (Capabilities->Hs400 != 0)) && Capabilities->BusWidth8 != 0) {
+ Supported = TRUE;
+ }
+ break;
+ case SdMmcMmcHs200:
+ if ((((ExtCsd->DeviceType & (BIT4 | BIT5)) != 0) && (Capabilities->Sdr104 != 0))) {
+ Supported = TRUE;
+ }
+ break;
+ case SdMmcMmcHsDdr:
+ if ((((ExtCsd->DeviceType & (BIT2 | BIT3)) != 0) && (Capabilities->Ddr50 != 0))) {
+ Supported = TRUE;
+ }
+ break;
+ case SdMmcMmcHsSdr:
+ if ((((ExtCsd->DeviceType & BIT1) != 0) && (Capabilities->HighSpeed != 0))) {
+ Supported = TRUE;
+ }
+ break;
+ case SdMmcMmcLegacy:
+ if ((ExtCsd->DeviceType & BIT0) != 0) {
+ Supported = TRUE;
+ }
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+
+ return Supported;
+}
+
+/**
+ Get the target bus timing to set on the link. This function
+ will try to select highest bus timing supported by card, controller
+ and the driver.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] ExtCsd Pointer to the card's extended CSD
+
+ @return Bus timing value that should be set on link
+**/
+SD_MMC_BUS_MODE
+EmmcGetTargetBusTiming (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN EMMC_EXT_CSD *ExtCsd
+ )
+{
+ SD_MMC_BUS_MODE BusTiming;
+
+ //
+ // We start with highest bus timing that this driver currently supports and
+ // return as soon as we find supported timing.
+ //
+ BusTiming = SdMmcMmcHs400;
+ while (BusTiming > SdMmcMmcLegacy) {
+ if (EmmcIsBusTimingSupported (Private, SlotIndex, ExtCsd, BusTiming)) {
+ break;
+ }
+ BusTiming--;
+ }
+
+ return BusTiming;
+}
+
+/**
+ Check if the passed bus width is supported by controller and card.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] BusTiming Bus timing set on the link
+ @param[in] BusWidth Bus width to check
+
+ @retval TRUE Passed bus width is supported in current bus configuration
+ @retval FALSE Passed bus width is not supported in current bus configuration
+**/
+BOOLEAN
+EmmcIsBusWidthSupported (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN SD_MMC_BUS_MODE BusTiming,
+ IN UINT16 BusWidth
+ )
+{
+ if (BusWidth == 8 && Private->Capability[SlotIndex].BusWidth8 != 0) {
+ return TRUE;
+ } else if (BusWidth == 4 && BusTiming != SdMmcMmcHs400) {
+ return TRUE;
+ } else if (BusWidth == 1 && (BusTiming == SdMmcMmcHsSdr || BusTiming == SdMmcMmcLegacy)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Get the target bus width to be set on the bus.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] ExtCsd Pointer to card's extended CSD
+ @param[in] BusTiming Bus timing set on the bus
+
+ @return Bus width to be set on the bus
+**/
+UINT8
+EmmcGetTargetBusWidth (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN EMMC_EXT_CSD *ExtCsd,
+ IN SD_MMC_BUS_MODE BusTiming
+ )
+{
+ UINT8 BusWidth;
+ UINT8 PreferredBusWidth;
+
+ PreferredBusWidth = Private->Slot[SlotIndex].OperatingParameters.BusWidth;
+
+ if (PreferredBusWidth != EDKII_SD_MMC_BUS_WIDTH_IGNORE &&
+ EmmcIsBusWidthSupported (Private, SlotIndex, BusTiming, PreferredBusWidth)) {
+ BusWidth = PreferredBusWidth;
+ } else if (EmmcIsBusWidthSupported (Private, SlotIndex, BusTiming, 8)) {
+ BusWidth = 8;
+ } else if (EmmcIsBusWidthSupported (Private, SlotIndex, BusTiming, 4)) {
+ BusWidth = 4;
+ } else {
+ BusWidth = 1;
+ }
+
+ return BusWidth;
+}
+
+/**
+ Get the target clock frequency to be set on the bus.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] ExtCsd Pointer to card's extended CSD
+ @param[in] BusTiming Bus timing to be set on the bus
+
+ @return Value of the clock frequency to be set on bus in MHz
+**/
+UINT32
+EmmcGetTargetClockFreq (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN EMMC_EXT_CSD *ExtCsd,
+ IN SD_MMC_BUS_MODE BusTiming
+ )
+{
+ UINT32 PreferredClockFreq;
+ UINT32 MaxClockFreq;
+
+ PreferredClockFreq = Private->Slot[SlotIndex].OperatingParameters.ClockFreq;
+
+ switch (BusTiming) {
+ case SdMmcMmcHs400:
+ case SdMmcMmcHs200:
+ MaxClockFreq = 200;
+ break;
+ case SdMmcMmcHsSdr:
+ case SdMmcMmcHsDdr:
+ MaxClockFreq = 52;
+ break;
+ default:
+ MaxClockFreq = 26;
+ break;
+ }
+
+ if (PreferredClockFreq != EDKII_SD_MMC_CLOCK_FREQ_IGNORE && PreferredClockFreq < MaxClockFreq) {
+ return PreferredClockFreq;
+ } else {
+ return MaxClockFreq;
+ }
+}
+
+/**
+ Get the driver strength to be set on bus.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] ExtCsd Pointer to card's extended CSD
+ @param[in] BusTiming Bus timing set on the bus
+
+ @return Value of the driver strength to be set on the bus
+**/
+EDKII_SD_MMC_DRIVER_STRENGTH
+EmmcGetTargetDriverStrength (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN EMMC_EXT_CSD *ExtCsd,
+ IN SD_MMC_BUS_MODE BusTiming
+ )
+{
+ EDKII_SD_MMC_DRIVER_STRENGTH PreferredDriverStrength;
+ EDKII_SD_MMC_DRIVER_STRENGTH DriverStrength;
+
+ PreferredDriverStrength = Private->Slot[SlotIndex].OperatingParameters.DriverStrength;
+ DriverStrength.Emmc = EmmcDriverStrengthType0;
+
+ if (PreferredDriverStrength.Emmc != EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE &&
+ (ExtCsd->DriverStrength & (BIT0 << PreferredDriverStrength.Emmc))) {
+ DriverStrength.Emmc = PreferredDriverStrength.Emmc;
+ }
+
+ return DriverStrength;
+}
+
+/**
+ Get the target settings for the bus mode.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] ExtCsd Pointer to card's extended CSD
+ @param[out] BusMode Target configuration of the bus
+**/
+VOID
+EmmcGetTargetBusMode (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN EMMC_EXT_CSD *ExtCsd,
+ OUT SD_MMC_BUS_SETTINGS *BusMode
+ )
+{
+ BusMode->BusTiming = EmmcGetTargetBusTiming (Private, SlotIndex, ExtCsd);
+ BusMode->BusWidth = EmmcGetTargetBusWidth (Private, SlotIndex, ExtCsd, BusMode->BusTiming);
+ BusMode->ClockFreq = EmmcGetTargetClockFreq (Private, SlotIndex, ExtCsd, BusMode->BusTiming);
+ BusMode->DriverStrength = EmmcGetTargetDriverStrength (Private, SlotIndex, ExtCsd, BusMode->BusTiming);
+}
+
+/**
+ Switch the high speed timing according to request.
+
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
+ Simplified Spec 3.0 Figure 2-29 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] Slot The slot number of the SD card to send the command to.
+ @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 EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca
+ )
+{
+ EFI_STATUS Status;
+ EMMC_CSD Csd;
+ EMMC_EXT_CSD ExtCsd;
+ SD_MMC_BUS_SETTINGS BusMode;
+ SD_MMC_HC_PRIVATE_DATA *Private;
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+
+ Status = EmmcGetCsd (PassThru, Slot, Rca, &Csd);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetCsd fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = EmmcSelect (PassThru, Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: Select fails with %r\n", Status));
+ return Status;
+ }
+
+ ASSERT (Private->BaseClkFreq[Slot] != 0);
+
+ //
+ // Get Device_Type from EXT_CSD register.
+ //
+ Status = EmmcGetExtCsd (PassThru, Slot, &ExtCsd);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetExtCsd fails with %r\n", Status));
+ return Status;
+ }
+
+ EmmcGetTargetBusMode (Private, Slot, &ExtCsd, &BusMode);
+
+ DEBUG ((DEBUG_INFO, "EmmcSetBusMode: Target bus mode: timing = %d, width = %d, clock freq = %d, driver strength = %d\n",
+ BusMode.BusTiming, BusMode.BusWidth, BusMode.ClockFreq, BusMode.DriverStrength.Emmc));
+
+ if (BusMode.BusTiming == SdMmcMmcHs400) {
+ Status = EmmcSwitchToHS400 (PciIo, PassThru, Slot, Rca, &BusMode);
+ } else if (BusMode.BusTiming == SdMmcMmcHs200) {
+ Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, &BusMode);
+ } else {
+ //
+ // Note that EmmcSwitchToHighSpeed is also called for SdMmcMmcLegacy
+ // bus timing. This is because even though we might not want to
+ // change the timing itself we still want to allow customization of
+ // bus parameters such as clock frequency and bus width.
+ //
+ Status = EmmcSwitchToHighSpeed (PciIo, PassThru, Slot, Rca, &BusMode);
+ }
+
+ DEBUG ((DEBUG_INFO, "EmmcSetBusMode: Switch to %a %r\n", (BusMode.BusTiming == SdMmcMmcHs400) ? "HS400" : ((BusMode.BusTiming == SdMmcMmcHs200) ? "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 SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS There is a EMMC card.
+ @retval Others There is not a EMMC card.
+
+**/
+EFI_STATUS
+EmmcIdentification (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ UINT32 Ocr;
+ UINT16 Rca;
+ UINTN Retry;
+
+ PciIo = Private->PciIo;
+ PassThru = &Private->PassThru;
+
+ Status = EmmcReset (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd0 fails with %r\n", Status));
+ return Status;
+ }
+
+ Ocr = 0;
+ Retry = 0;
+ do {
+ Status = EmmcGetOcr (PassThru, Slot, &Ocr);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd1 fails with %r\n", Status));
+ return Status;
+ }
+ Ocr |= BIT30;
+
+ if (Retry++ == 100) {
+ DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd1 fails too many times\n"));
+ return EFI_DEVICE_ERROR;
+ }
+ gBS->Stall(10 * 1000);
+ } while ((Ocr & BIT31) == 0);
+
+ Status = EmmcGetAllCid (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd2 fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Slot starts from 0 and 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 = Slot + 1;
+ Status = EmmcSetRca (PassThru, Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcIdentification: Executing Cmd3 fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Enter Data Tranfer Mode.
+ //
+ DEBUG ((DEBUG_INFO, "EmmcIdentification: Found a EMMC device at slot [%d], RCA [%d]\n", Slot, Rca));
+ Private->Slot[Slot].CardType = EmmcCardType;
+
+ Status = EmmcSetBusMode (PciIo, PassThru, Slot, Rca);
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c new file mode 100644 index 000000000..b630daab7 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c @@ -0,0 +1,1376 @@ +/** @file
+ This file provides some helper functions which are specific for SD card device.
+
+ Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdMmcPciHcDxe.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.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @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,
+ IN UINT8 Slot
+ )
+{
+ 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 = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_GO_IDLE_STATE;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &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] Slot The slot number of the SD card to send the command to.
+ @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 Slot,
+ 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 = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_IF_COND;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR7;
+ SdMmcCmdBlk.CommandArgument = (SupplyVoltage << 8) | CheckPattern;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &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] Slot The slot number of the SD card to send the command to.
+ @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 UINT8 Slot,
+ 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 = SD_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 = SdMmcPassThruPassThru (PassThru, Slot, &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] Slot The slot number of the SD card to send the command to.
+ @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 UINT8 Slot,
+ 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 = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &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 = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ *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.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardAllSendCid (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ 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 = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_ALL_SEND_CID;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &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[in] Slot The slot number of the SD card to send the command to.
+ @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,
+ IN UINT8 Slot,
+ 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 = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);
+ }
+
+ 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] Slot The slot number of the SD card to send the command to.
+ @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 UINT8 Slot,
+ 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 = SD_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 = SdMmcPassThruPassThru (PassThru, Slot, &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.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardVoltageSwitch (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ 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 = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_VOLTAGE_SWITCH;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = 0;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &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] Slot The slot number of the SD card to send the command to.
+ @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 UINT8 Slot,
+ 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 = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &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 = SdMmcPassThruPassThru (PassThru, Slot, &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] Slot The slot number of the SD card to send the command to.
+ @param[in] BusTiming Target bus timing based on which access group value will be set.
+ @param[in] CommandSystem The value for command set group.
+ @param[in] DriverStrength The value for driver strength 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 Slot,
+ IN SD_MMC_BUS_MODE BusTiming,
+ IN UINT8 CommandSystem,
+ IN SD_DRIVER_STRENGTH_TYPE DriverStrength,
+ 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;
+ UINT8 AccessMode;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SWITCH_FUNC;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+ ModeValue = Mode ? BIT31 : 0;
+
+ switch (BusTiming) {
+ case SdMmcUhsDdr50:
+ AccessMode = 0x4;
+ break;
+ case SdMmcUhsSdr104:
+ AccessMode = 0x3;
+ break;
+ case SdMmcUhsSdr50:
+ AccessMode = 0x2;
+ break;
+ case SdMmcUhsSdr25:
+ case SdMmcSdHs:
+ AccessMode = 0x1;
+ break;
+ case SdMmcUhsSdr12:
+ case SdMmcSdDs:
+ AccessMode = 0;
+ break;
+ default:
+ AccessMode = 0xF;
+ }
+
+ SdMmcCmdBlk.CommandArgument = (AccessMode & 0xF) | ((CommandSystem & 0xF) << 4) | \
+ ((DriverStrength & 0xF) << 8) | ((PowerLimit & 0xF) << 12) | \
+ ModeValue;
+
+ Packet.InDataBuffer = SwitchResp;
+ Packet.InTransferLength = 64;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Mode) {
+ if ((((AccessMode & 0xF) != 0xF) && ((SwitchResp[16] & 0xF) != AccessMode)) ||
+ (((CommandSystem & 0xF) != 0xF) && (((SwitchResp[16] >> 4) & 0xF) != CommandSystem)) ||
+ (((DriverStrength & 0xF) != 0xF) && ((SwitchResp[15] & 0xF) != DriverStrength)) ||
+ (((PowerLimit & 0xF) != 0xF) && (((SwitchResp[15] >> 4) & 0xF) != PowerLimit))) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ 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] Slot The slot number of the SD card to send the command to.
+ @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 UINT8 Slot,
+ 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 = SD_MMC_HC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &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.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSendTuningBlk (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ 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 = SD_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 = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Tunning the sampling point of SDR104 or SDR50 bus speed mode.
+
+ Command SD_SEND_TUNING_BLOCK 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 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] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardTuningClock (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl2;
+ UINT8 Retry;
+
+ //
+ // Notify the host that the sampling clock tuning procedure starts.
+ //
+ HostCtrl2 = BIT6;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.
+ //
+ Retry = 0;
+ do {
+ Status = SdCardSendTuningBlk (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardSendTuningBlk: Send tuning block fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((HostCtrl2 & (BIT6 | BIT7)) == 0) {
+ break;
+ }
+ if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {
+ return EFI_SUCCESS;
+ }
+ } while (++Retry < 40);
+
+ DEBUG ((DEBUG_ERROR, "SdCardTuningClock: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2));
+ //
+ // Abort the tuning procedure and reset the tuning circuit.
+ //
+ HostCtrl2 = (UINT8)~(BIT6 | BIT7);
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ 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] Slot The slot number of the SD card to send the command to.
+ @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 EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN UINT8 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT32 DevStatus;
+
+ Status = SdCardSetBusWidth (PassThru, Slot, 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, Slot, 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 is 0x%08x\n", DevStatus));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth);
+
+ return Status;
+}
+
+/**
+ Check if passed BusTiming is supported in both controller and card.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] CardSupportedBusTimings Bitmask indicating which bus timings are supported by card
+ @param[in] IsInUhsI Flag indicating if link is in UHS-I
+
+ @retval TRUE Both card and controller support given BusTiming
+ @retval FALSE Card or controller doesn't support given BusTiming
+**/
+BOOLEAN
+SdIsBusTimingSupported (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN UINT8 CardSupportedBusTimings,
+ IN BOOLEAN IsInUhsI,
+ IN SD_MMC_BUS_MODE BusTiming
+ )
+{
+ SD_MMC_HC_SLOT_CAP *Capability;
+
+ Capability = &Private->Capability[SlotIndex];
+
+ if (IsInUhsI) {
+ switch (BusTiming) {
+ case SdMmcUhsSdr104:
+ if ((Capability->Sdr104 != 0) && ((CardSupportedBusTimings & BIT3) != 0)) {
+ return TRUE;
+ }
+ break;
+ case SdMmcUhsDdr50:
+ if ((Capability->Ddr50 != 0) && ((CardSupportedBusTimings & BIT4) != 0)) {
+ return TRUE;
+ }
+ break;
+ case SdMmcUhsSdr50:
+ if ((Capability->Sdr50 != 0) && ((CardSupportedBusTimings & BIT2) != 0)) {
+ return TRUE;
+ }
+ break;
+ case SdMmcUhsSdr25:
+ if ((CardSupportedBusTimings & BIT1) != 0) {
+ return TRUE;
+ }
+ break;
+ case SdMmcUhsSdr12:
+ if ((CardSupportedBusTimings & BIT0) != 0) {
+ return TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (BusTiming) {
+ case SdMmcSdHs:
+ if ((Capability->HighSpeed != 0) && (CardSupportedBusTimings & BIT1) != 0) {
+ return TRUE;
+ }
+ break;
+ case SdMmcSdDs:
+ if ((CardSupportedBusTimings & BIT0) != 0) {
+ return TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Get the target bus timing to set on the link. This function
+ will try to select highest bus timing supported by card, controller
+ and the driver.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] CardSupportedBusTimings Bitmask indicating which bus timings are supported by card
+ @param[in] IsInUhsI Flag indicating if link is in UHS-I
+
+ @return Bus timing value that should be set on link
+**/
+SD_MMC_BUS_MODE
+SdGetTargetBusTiming (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN UINT8 CardSupportedBusTimings,
+ IN BOOLEAN IsInUhsI
+ )
+{
+ SD_MMC_BUS_MODE BusTiming;
+
+ if (IsInUhsI) {
+ BusTiming = SdMmcUhsSdr104;
+ } else {
+ BusTiming = SdMmcSdHs;
+ }
+
+ while (BusTiming > SdMmcSdDs) {
+ if (SdIsBusTimingSupported (Private, SlotIndex, CardSupportedBusTimings, IsInUhsI, BusTiming)) {
+ break;
+ }
+ BusTiming--;
+ }
+
+ return BusTiming;
+}
+
+/**
+ Get the target bus width to be set on the bus.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] BusTiming Bus timing set on the bus
+
+ @return Bus width to be set on the bus
+**/
+UINT8
+SdGetTargetBusWidth (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN SD_MMC_BUS_MODE BusTiming
+ )
+{
+ UINT8 BusWidth;
+ UINT8 PreferredBusWidth;
+
+ PreferredBusWidth = Private->Slot[SlotIndex].OperatingParameters.BusWidth;
+
+ if (BusTiming == SdMmcSdDs || BusTiming == SdMmcSdHs) {
+ if (PreferredBusWidth != EDKII_SD_MMC_BUS_WIDTH_IGNORE &&
+ (PreferredBusWidth == 1 || PreferredBusWidth == 4)) {
+ BusWidth = PreferredBusWidth;
+ } else {
+ BusWidth = 4;
+ }
+ } else {
+ //
+ // UHS-I modes support only 4-bit width.
+ // Switch to 4-bit has been done before calling this function anyway so
+ // this is purely informational.
+ //
+ BusWidth = 4;
+ }
+
+ return BusWidth;
+}
+
+/**
+ Get the target clock frequency to be set on the bus.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] BusTiming Bus timing to be set on the bus
+
+ @return Value of the clock frequency to be set on bus in MHz
+**/
+UINT32
+SdGetTargetBusClockFreq (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN SD_MMC_BUS_MODE BusTiming
+ )
+{
+ UINT32 PreferredClockFreq;
+ UINT32 MaxClockFreq;
+
+ PreferredClockFreq = Private->Slot[SlotIndex].OperatingParameters.ClockFreq;
+
+ switch (BusTiming) {
+ case SdMmcUhsSdr104:
+ MaxClockFreq = 208;
+ break;
+ case SdMmcUhsSdr50:
+ MaxClockFreq = 100;
+ break;
+ case SdMmcUhsDdr50:
+ case SdMmcUhsSdr25:
+ case SdMmcSdHs:
+ MaxClockFreq = 50;
+ break;
+ case SdMmcUhsSdr12:
+ case SdMmcSdDs:
+ default:
+ MaxClockFreq = 25;
+ }
+
+ if (PreferredClockFreq != EDKII_SD_MMC_CLOCK_FREQ_IGNORE && PreferredClockFreq < MaxClockFreq) {
+ return PreferredClockFreq;
+ } else {
+ return MaxClockFreq;
+ }
+}
+
+/**
+ Get the driver strength to be set on bus.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] CardSupportedDriverStrengths Bitmask indicating which driver strengths are supported on the card
+ @param[in] BusTiming Bus timing set on the bus
+
+ @return Value of the driver strength to be set on the bus
+**/
+EDKII_SD_MMC_DRIVER_STRENGTH
+SdGetTargetDriverStrength (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN UINT8 CardSupportedDriverStrengths,
+ IN SD_MMC_BUS_MODE BusTiming
+ )
+{
+ EDKII_SD_MMC_DRIVER_STRENGTH PreferredDriverStrength;
+ EDKII_SD_MMC_DRIVER_STRENGTH DriverStrength;
+
+ if (BusTiming == SdMmcSdDs || BusTiming == SdMmcSdHs) {
+ DriverStrength.Sd = SdDriverStrengthIgnore;
+ return DriverStrength;
+ }
+
+ PreferredDriverStrength = Private->Slot[SlotIndex].OperatingParameters.DriverStrength;
+ DriverStrength.Sd = SdDriverStrengthTypeB;
+
+ if (PreferredDriverStrength.Sd != EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE &&
+ (CardSupportedDriverStrengths & (BIT0 << PreferredDriverStrength.Sd))) {
+
+ if ((PreferredDriverStrength.Sd == SdDriverStrengthTypeA &&
+ (Private->Capability[SlotIndex].DriverTypeA != 0)) ||
+ (PreferredDriverStrength.Sd == SdDriverStrengthTypeC &&
+ (Private->Capability[SlotIndex].DriverTypeC != 0)) ||
+ (PreferredDriverStrength.Sd == SdDriverStrengthTypeD &&
+ (Private->Capability[SlotIndex].DriverTypeD != 0))) {
+ DriverStrength.Sd = PreferredDriverStrength.Sd;
+ }
+ }
+
+ return DriverStrength;
+}
+
+/**
+ Get the target settings for the bus mode.
+
+ @param[in] Private Pointer to controller private data
+ @param[in] SlotIndex Index of the slot in the controller
+ @param[in] SwitchQueryResp Pointer to switch query response
+ @param[in] IsInUhsI Flag indicating if link is in UHS-I mode
+ @param[out] BusMode Target configuration of the bus
+**/
+VOID
+SdGetTargetBusMode (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 SlotIndex,
+ IN UINT8 *SwitchQueryResp,
+ IN BOOLEAN IsInUhsI,
+ OUT SD_MMC_BUS_SETTINGS *BusMode
+ )
+{
+ BusMode->BusTiming = SdGetTargetBusTiming (Private, SlotIndex, SwitchQueryResp[13], IsInUhsI);
+ BusMode->BusWidth = SdGetTargetBusWidth (Private, SlotIndex, BusMode->BusTiming);
+ BusMode->ClockFreq = SdGetTargetBusClockFreq (Private, SlotIndex, BusMode->BusTiming);
+ BusMode->DriverStrength = SdGetTargetDriverStrength (Private, SlotIndex, SwitchQueryResp[9], BusMode->BusTiming);
+}
+
+/**
+ Switch the high speed timing according to request.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and
+ SD Host Controller Simplified Spec 3.0 section Figure 2-29 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] Slot The slot number of the SD card to send the command to.
+ @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.
+
+ @retval EFI_SUCCESS The operation is done correctly.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdCardSetBusMode (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca,
+ IN BOOLEAN S18A
+ )
+{
+ EFI_STATUS Status;
+ SD_MMC_HC_SLOT_CAP *Capability;
+ UINT8 HostCtrl1;
+ UINT8 SwitchResp[64];
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ SD_MMC_BUS_SETTINGS BusMode;
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+
+ Capability = &Private->Capability[Slot];
+
+ Status = SdCardSelect (PassThru, Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (S18A) {
+ //
+ // For UHS-I speed modes 4-bit data bus is requiered so we
+ // switch here irrespective of platform preference.
+ //
+ Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca, 4);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Get the supported bus speed from SWITCH cmd return data group #1.
+ //
+ Status = SdCardSwitch (PassThru, Slot, 0xFF, 0xF, SdDriverStrengthIgnore, 0xF, FALSE, SwitchResp);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SdGetTargetBusMode (Private, Slot, SwitchResp, S18A, &BusMode);
+
+ DEBUG ((DEBUG_INFO, "SdCardSetBusMode: Target bus mode: bus timing = %d, bus width = %d, clock freq[MHz] = %d, driver strength = %d\n",
+ BusMode.BusTiming, BusMode.BusWidth, BusMode.ClockFreq, BusMode.DriverStrength.Sd));
+
+ if (!S18A) {
+ Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca, BusMode.BusWidth);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Status = SdCardSwitch (PassThru, Slot, BusMode.BusTiming, 0xF, BusMode.DriverStrength.Sd, 0xF, TRUE, SwitchResp);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcSetDriverStrength (Private->PciIo, Slot, BusMode.DriverStrength.Sd);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Set to High Speed timing
+ //
+ if (BusMode.BusTiming == SdMmcSdHs) {
+ HostCtrl1 = BIT2;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, BusMode.BusTiming);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcHcClockSupply (Private, Slot, BusMode.BusTiming, FALSE, BusMode.ClockFreq * 1000);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((BusMode.BusTiming == SdMmcUhsSdr104) || ((BusMode.BusTiming == SdMmcUhsSdr50) && (Capability->TuningSDR50 != 0))) {
+ Status = SdCardTuningClock (PciIo, PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Execute SD device identification procedure.
+
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 3.6 for details.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS There is a SD card.
+ @retval Others There is not a SD card.
+
+**/
+EFI_STATUS
+SdCardIdentification (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ UINT32 Ocr;
+ UINT16 Rca;
+ BOOLEAN Xpc;
+ BOOLEAN S18r;
+ UINT64 MaxCurrent;
+ UINT16 ControllerVer;
+ UINT8 PowerCtrl;
+ UINT32 PresentState;
+ UINT8 HostCtrl2;
+ UINTN Retry;
+
+ PciIo = Private->PciIo;
+ PassThru = &Private->PassThru;
+ //
+ // 1. Send Cmd0 to the device
+ //
+ Status = SdCardReset (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Executing Cmd0 fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // 2. Send Cmd8 to the device
+ //
+ Status = SdCardVoltageCheck (PassThru, Slot, 0x1, 0xFF);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Executing Cmd8 fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // 3. Send SDIO Cmd5 to the device to the SDIO device OCR register.
+ //
+ Status = SdioSendOpCond (PassThru, Slot, 0, FALSE);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Found SDIO device, ignore it as we don't support\n"));
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // 4. Send Acmd41 with voltage window 0 to the device
+ //
+ Status = SdCardSendOpCond (PassThru, Slot, 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[Slot].Voltage33 != 0) {
+ //
+ // Support 3.3V
+ //
+ MaxCurrent = ((UINT32)Private->MaxCurrent[Slot] & 0xFF) * 4;
+ } else if (Private->Capability[Slot].Voltage30 != 0) {
+ //
+ // Support 3.0V
+ //
+ MaxCurrent = (((UINT32)Private->MaxCurrent[Slot] >> 8) & 0xFF) * 4;
+ } else if (Private->Capability[Slot].Voltage18 != 0) {
+ //
+ // Support 1.8V
+ //
+ MaxCurrent = (((UINT32)Private->MaxCurrent[Slot] >> 16) & 0xFF) * 4;
+ } else {
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (MaxCurrent >= 150) {
+ Xpc = TRUE;
+ } else {
+ Xpc = FALSE;
+ }
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (((ControllerVer & 0xFF) >= SD_MMC_HC_CTRL_VER_300) &&
+ ((ControllerVer & 0xFF) <= SD_MMC_HC_CTRL_VER_420)) {
+ S18r = TRUE;
+ } else if (((ControllerVer & 0xFF) == SD_MMC_HC_CTRL_VER_100) || ((ControllerVer & 0xFF) == SD_MMC_HC_CTRL_VER_200)) {
+ S18r = FALSE;
+ } else {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // 5. 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.
+ //
+ Ocr = 0;
+ Retry = 0;
+ do {
+ Status = SdCardSendOpCond (PassThru, Slot, 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;
+ }
+
+ if (Retry++ == 100) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: SdCardSendOpCond fails too many times\n"));
+ return EFI_DEVICE_ERROR;
+ }
+ gBS->Stall(10 * 1000);
+ } while ((Ocr & BIT31) == 0);
+
+ //
+ // 6. If the S18A bit is set and the Host Controller supports 1.8V signaling
+ // (One of support bits is set to 1: SDR50, SDR104 or DDR50 in the
+ // Capabilities register), switch its voltage to 1.8V.
+ //
+ if ((Private->Capability[Slot].Sdr50 != 0 ||
+ Private->Capability[Slot].Sdr104 != 0 ||
+ Private->Capability[Slot].Ddr50 != 0) &&
+ ((Ocr & BIT24) != 0)) {
+ Status = SdCardVoltageSwitch (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardVoltageSwitch fails with %r\n", Status));
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ } else {
+ Status = SdMmcHcStopClock (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ }
+
+ SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
+ if (((PresentState >> 20) & 0xF) != 0) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: SwitchVoltage fails with PresentState = 0x%x\n", PresentState));
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ }
+ HostCtrl2 = BIT3;
+ SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+
+ gBS->Stall (5000);
+
+ SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);
+ if ((HostCtrl2 & BIT3) == 0) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: SwitchVoltage fails with HostCtrl2 = 0x%x\n", HostCtrl2));
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ }
+
+ Status = SdMmcHcStartSdClock (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ gBS->Stall (1000);
+
+ SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
+ if (((PresentState >> 20) & 0xF) != 0xF) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: SwitchVoltage fails with PresentState = 0x%x, It should be 0xF\n", PresentState));
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ }
+ }
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Switch to 1.8v signal voltage success\n"));
+ }
+
+ Status = SdCardAllSendCid (PassThru, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardAllSendCid fails with %r\n", Status));
+ return Status;
+ }
+
+ Status = SdCardSetRca (PassThru, Slot, &Rca);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardSetRca fails with %r\n", Status));
+ return Status;
+ }
+ //
+ // Enter Data Tranfer Mode.
+ //
+ DEBUG ((DEBUG_INFO, "SdCardIdentification: Found a SD device at slot [%d]\n", Slot));
+ Private->Slot[Slot].CardType = SdCardType;
+
+ Status = SdCardSetBusMode (PciIo, PassThru, Slot, Rca, ((Ocr & BIT24) != 0));
+
+ return Status;
+
+Error:
+ //
+ // Set SD Bus Power = 0
+ //
+ PowerCtrl = (UINT8)~BIT0;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, sizeof (PowerCtrl), &PowerCtrl);
+ return EFI_DEVICE_ERROR;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c new file mode 100644 index 000000000..57f4cf329 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c @@ -0,0 +1,1423 @@ +/** @file
+ This driver is used to manage SD/MMC PCI host controllers which are compliance
+ with SD Host Controller Simplified Specification version 3.00 plus the 64-bit
+ System Addressing support in SD Host Controller Simplified Specification version
+ 4.20.
+
+ It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.
+
+ Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
+ Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdMmcPciHcDxe.h"
+
+EDKII_SD_MMC_OVERRIDE *mOverride;
+
+//
+// Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gSdMmcPciHcDriverBinding = {
+ SdMmcPciHcDriverBindingSupported,
+ SdMmcPciHcDriverBindingStart,
+ SdMmcPciHcDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+#define SLOT_INIT_TEMPLATE {0, UnknownSlot, 0, 0, 0, 0, \
+ {EDKII_SD_MMC_BUS_WIDTH_IGNORE,\
+ EDKII_SD_MMC_CLOCK_FREQ_IGNORE,\
+ {EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE}}}
+
+//
+// Template for SD/MMC host controller private data.
+//
+SD_MMC_HC_PRIVATE_DATA gSdMmcPciHcTemplate = {
+ SD_MMC_HC_PRIVATE_SIGNATURE, // Signature
+ NULL, // ControllerHandle
+ NULL, // PciIo
+ { // PassThru
+ sizeof (UINT32),
+ SdMmcPassThruPassThru,
+ SdMmcPassThruGetNextSlot,
+ SdMmcPassThruBuildDevicePath,
+ SdMmcPassThruGetSlotNumber,
+ SdMmcPassThruResetDevice
+ },
+ 0, // PciAttributes
+ 0, // PreviousSlot
+ NULL, // TimerEvent
+ NULL, // ConnectEvent
+ // Queue
+ INITIALIZE_LIST_HEAD_VARIABLE (gSdMmcPciHcTemplate.Queue),
+ { // Slot
+ SLOT_INIT_TEMPLATE,
+ SLOT_INIT_TEMPLATE,
+ SLOT_INIT_TEMPLATE,
+ SLOT_INIT_TEMPLATE,
+ SLOT_INIT_TEMPLATE,
+ SLOT_INIT_TEMPLATE
+ },
+ { // 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.
+//
+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
+InitializeSdMmcPciHcDxe (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gSdMmcPciHcDriverBinding,
+ ImageHandle,
+ &gSdMmcPciHcComponentName,
+ &gSdMmcPciHcComponentName2
+ );
+ 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
+ )
+{
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ LIST_ENTRY *Link;
+ SD_MMC_HC_TRB *Trb;
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ BOOLEAN InfiniteWait;
+ EFI_EVENT TrbEvent;
+
+ Private = (SD_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 = SD_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 = SdMmcCheckTrbEnv (Private, Trb);
+ if (!EFI_ERROR (Status)) {
+ Trb->Started = TRUE;
+ Status = SdMmcExecTrb (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ } else {
+ goto Done;
+ }
+ }
+ Status = SdMmcCheckTrbResult (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;
+ SdMmcFreeTrb (Trb);
+ DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT\n", TrbEvent));
+ gBS->SignalEvent (TrbEvent);
+ return;
+ }
+ } else if ((Trb != NULL) && (Status == EFI_CRC_ERROR) && (Trb->Retries > 0)) {
+ Trb->Retries--;
+ Trb->Started = FALSE;
+ } else if ((Trb != NULL)) {
+ RemoveEntryList (Link);
+ Trb->Packet->TransactionStatus = Status;
+ TrbEvent = Trb->Event;
+ SdMmcFreeTrb (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
+SdMmcPciHcEnumerateDevice (
+ IN EFI_EVENT Event,
+ IN VOID* Context
+ )
+{
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+ UINT8 Slot;
+ BOOLEAN MediaPresent;
+ UINT32 RoutineNum;
+ CARD_TYPE_DETECT_ROUTINE *Routine;
+ UINTN Index;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ SD_MMC_HC_TRB *Trb;
+ EFI_TPL OldTpl;
+
+ Private = (SD_MMC_HC_PRIVATE_DATA*)Context;
+
+ for (Slot = 0; Slot < SD_MMC_HC_MAX_SLOT; Slot++) {
+ if ((Private->Slot[Slot].Enable) && (Private->Slot[Slot].SlotType == RemovableSlot)) {
+ Status = SdMmcHcCardDetect (Private->PciIo, Slot, &MediaPresent);
+ if ((Status == EFI_MEDIA_CHANGED) && !MediaPresent) {
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcEnumerateDevice: device disconnected at slot %d of pci %p\n", Slot, Private->PciIo));
+ Private->Slot[Slot].MediaPresent = FALSE;
+ Private->Slot[Slot].Initialized = 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 = SD_MMC_HC_TRB_FROM_THIS (Link);
+ if (Trb->Slot == Slot) {
+ RemoveEntryList (Link);
+ Trb->Packet->TransactionStatus = EFI_NO_MEDIA;
+ gBS->SignalEvent (Trb->Event);
+ SdMmcFreeTrb (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, "SdMmcPciHcEnumerateDevice: device connected at slot %d of pci %p\n", Slot, Private->PciIo));
+ //
+ // Reset the specified slot of the SD/MMC Pci Host Controller
+ //
+ Status = SdMmcHcReset (Private, Slot);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // Reinitialize slot and restart identification process for the new attached device
+ //
+ Status = SdMmcHcInitHost (Private, Slot);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Private->Slot[Slot].MediaPresent = TRUE;
+ Private->Slot[Slot].Initialized = TRUE;
+ RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE);
+ for (Index = 0; Index < RoutineNum; Index++) {
+ Routine = &mCardTypeDetectRoutineTable[Index];
+ if (*Routine != NULL) {
+ Status = (*Routine) (Private, Slot);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ }
+ //
+ // This card doesn't get initialized correctly.
+ //
+ if (Index == RoutineNum) {
+ Private->Slot[Slot].Initialized = FALSE;
+ }
+
+ //
+ // Notify the upper layer the connect state change through ReinstallProtocolInterface.
+ //
+ gBS->ReinstallProtocolInterface (
+ Private->ControllerHandle,
+ &gEfiSdMmcPassThruProtocolGuid,
+ &Private->PassThru,
+ &Private->PassThru
+ );
+ }
+ }
+ }
+
+ return;
+}
+
+/**
+ 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 determine 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
+SdMmcPciHcDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 PciData;
+
+ PciIo = NULL;
+ ParentDevicePath = NULL;
+
+ //
+ // SdPciHcDxe is a device driver, and should ingore the
+ // "RemainingDevicePath" according to EFI spec.
+ //
+ 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 EfiPciIoProtocol.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Now further check the PCI header: Base class (offset 0x08) and
+ // Sub Class (offset 0x05). This controller should be an SD/MMC PCI
+ // Host Controller.
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ sizeof (PciData),
+ &PciData
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Since we already got the PciData, we can close protocol to avoid to carry it
+ // on for multiple exit points.
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Examine SD PCI Host Controller PCI Configuration table fields.
+ //
+ if ((PciData.Hdr.ClassCode[2] == PCI_CLASS_SYSTEM_PERIPHERAL) &&
+ (PciData.Hdr.ClassCode[1] == PCI_SUBCLASS_SD_HOST_CONTROLLER) &&
+ ((PciData.Hdr.ClassCode[0] == 0x00) || (PciData.Hdr.ClassCode[0] == 0x01))) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ 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
+SdMmcPciHcDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 Supports;
+ UINT64 PciAttributes;
+ UINT8 SlotNum;
+ UINT8 FirstBar;
+ UINT8 Slot;
+ UINT8 Index;
+ CARD_TYPE_DETECT_ROUTINE *Routine;
+ UINT32 RoutineNum;
+ BOOLEAN MediaPresent;
+ BOOLEAN Support64BitDma;
+
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStart: Start\n"));
+
+ //
+ // Open PCI I/O Protocol and save pointer to open protocol
+ // in private data area.
+ //
+ PciIo = NULL;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Enable the SD Host Controller MMIO space
+ //
+ Private = NULL;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &PciAttributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ } else {
+ goto Done;
+ }
+
+ Private = AllocateCopyPool (sizeof (SD_MMC_HC_PRIVATE_DATA), &gSdMmcPciHcTemplate);
+ if (Private == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Private->ControllerHandle = Controller;
+ Private->PciIo = PciIo;
+ Private->PciAttributes = PciAttributes;
+ InitializeListHead (&Private->Queue);
+
+ //
+ // Get SD/MMC Pci Host Controller Slot info
+ //
+ Status = SdMmcHcGetSlotInfo (PciIo, &FirstBar, &SlotNum);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Attempt to locate the singleton instance of the SD/MMC override protocol,
+ // which implements platform specific workarounds for non-standard SDHCI
+ // implementations.
+ //
+ if (mOverride == NULL) {
+ Status = gBS->LocateProtocol (&gEdkiiSdMmcOverrideProtocolGuid, NULL,
+ (VOID **)&mOverride);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "%a: found SD/MMC override protocol\n",
+ __FUNCTION__));
+ }
+ }
+
+ Support64BitDma = TRUE;
+ for (Slot = FirstBar; Slot < (FirstBar + SlotNum); Slot++) {
+ Private->Slot[Slot].Enable = TRUE;
+ //
+ // Get SD/MMC Pci Host Controller Version
+ //
+ Status = SdMmcHcGetControllerVersion (PciIo, Slot, &Private->ControllerVersion[Slot]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = SdMmcHcGetCapability (PciIo, Slot, &Private->Capability[Slot]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Private->BaseClkFreq[Slot] = Private->Capability[Slot].BaseClkFreq;
+
+ if (mOverride != NULL) {
+ if (mOverride->Capability != NULL) {
+ Status = mOverride->Capability (
+ Controller,
+ Slot,
+ &Private->Capability[Slot],
+ &Private->BaseClkFreq[Slot]
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "%a: Failed to override capability - %r\n",
+ __FUNCTION__, Status));
+ continue;
+ }
+ }
+
+ if (mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ Controller,
+ Slot,
+ EdkiiSdMmcGetOperatingParam,
+ (VOID*)&Private->Slot[Slot].OperatingParameters
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "%a: Failed to get operating parameters, using defaults\n", __FUNCTION__));
+ }
+ }
+ }
+
+ DumpCapabilityReg (Slot, &Private->Capability[Slot]);
+ DEBUG ((
+ DEBUG_INFO,
+ "Slot[%d] Base Clock Frequency: %dMHz\n",
+ Slot,
+ Private->BaseClkFreq[Slot]
+ ));
+
+ //
+ // If any of the slots does not support 64b system bus
+ // do not enable 64b DMA in the PCI layer.
+ //
+ if ((Private->ControllerVersion[Slot] == SD_MMC_HC_CTRL_VER_300 &&
+ Private->Capability[Slot].SysBus64V3 == 0) ||
+ (Private->ControllerVersion[Slot] == SD_MMC_HC_CTRL_VER_400 &&
+ Private->Capability[Slot].SysBus64V3 == 0) ||
+ (Private->ControllerVersion[Slot] >= SD_MMC_HC_CTRL_VER_410 &&
+ Private->Capability[Slot].SysBus64V4 == 0)) {
+ Support64BitDma = FALSE;
+ }
+
+ Status = SdMmcHcGetMaxCurrent (PciIo, Slot, &Private->MaxCurrent[Slot]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Private->Slot[Slot].SlotType = Private->Capability[Slot].SlotType;
+ if ((Private->Slot[Slot].SlotType != RemovableSlot) && (Private->Slot[Slot].SlotType != EmbeddedSlot)) {
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcDxe doesn't support the slot type [%d]!!!\n", Private->Slot[Slot].SlotType));
+ continue;
+ }
+
+ //
+ // Reset the specified slot of the SD/MMC Pci Host Controller
+ //
+ Status = SdMmcHcReset (Private, Slot);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // Check whether there is a SD/MMC card attached
+ //
+ if (Private->Slot[Slot].SlotType == RemovableSlot) {
+ Status = SdMmcHcCardDetect (PciIo, Slot, &MediaPresent);
+ if (EFI_ERROR (Status) && (Status != EFI_MEDIA_CHANGED)) {
+ continue;
+ } else if (!MediaPresent) {
+ DEBUG ((
+ DEBUG_INFO,
+ "SdMmcHcCardDetect: No device attached in Slot[%d]!!!\n",
+ Slot
+ ));
+ continue;
+ }
+ }
+
+ Status = SdMmcHcInitHost (Private, Slot);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Private->Slot[Slot].MediaPresent = TRUE;
+ Private->Slot[Slot].Initialized = TRUE;
+ RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE);
+ for (Index = 0; Index < RoutineNum; Index++) {
+ Routine = &mCardTypeDetectRoutineTable[Index];
+ if (*Routine != NULL) {
+ Status = (*Routine) (Private, Slot);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ }
+ //
+ // This card doesn't get initialized correctly.
+ //
+ if (Index == RoutineNum) {
+ Private->Slot[Slot].Initialized = FALSE;
+ }
+ }
+
+ //
+ // Enable 64-bit DMA support in the PCI layer if this controller
+ // supports it.
+ //
+ if (Support64BitDma) {
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "SdMmcPciHcDriverBindingStart: failed to enable 64-bit DMA (%r)\n", Status));
+ }
+ }
+
+ //
+ // 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, SD_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,
+ SdMmcPciHcEnumerateDevice,
+ Private,
+ &Private->ConnectEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->SetTimer (Private->ConnectEvent, TimerPeriodic, SD_MMC_HC_ENUM_TIMER);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ &(Private->PassThru),
+ NULL
+ );
+
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStart: %r End on %x\n", Status, Controller));
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if ((Private != NULL) && (Private->PciAttributes != 0)) {
+ //
+ // Restore original PCI attributes
+ //
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->PciAttributes,
+ NULL
+ );
+ }
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ 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
+SdMmcPciHcDriverBindingStop (
+ 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;
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ SD_MMC_HC_TRB *Trb;
+
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStop: Start\n"));
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID**) &PassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private = SD_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 = SD_MMC_HC_TRB_FROM_THIS (Link);
+ Trb->Packet->TransactionStatus = EFI_ABORTED;
+ gBS->SignalEvent (Trb->Event);
+ SdMmcFreeTrb (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
+ );
+ //
+ // Restore original PCI attributes
+ //
+ PciIo = Private->PciIo;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->PciAttributes,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (Private);
+
+ DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStop: End with %r\n", Status));
+
+ return Status;
+}
+
+/**
+ Execute TRB synchronously.
+
+ @param[in] Private Pointer to driver private data.
+ @param[in] Trb Pointer to TRB to execute.
+
+ @retval EFI_SUCCESS TRB executed successfully.
+ @retval Other TRB failed.
+**/
+EFI_STATUS
+SdMmcPassThruExecSyncTrb (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ //
+ // 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);
+ }
+
+ while (Trb->Retries) {
+ Status = SdMmcWaitTrbEnv (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcExecTrb (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcWaitTrbResult (Private, Trb);
+ if (Status == EFI_CRC_ERROR) {
+ Trb->Retries--;
+ } else {
+ return 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
+SdMmcPassThruPassThru (
+ 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;
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ SD_MMC_HC_TRB *Trb;
+
+ 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 = SD_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ if (!Private->Slot[Slot].Enable) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!Private->Slot[Slot].MediaPresent) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (!Private->Slot[Slot].Initialized) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Trb = SdMmcCreateTrb (Private, Slot, Packet, Event);
+ if (Trb == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Immediately return for async I/O.
+ //
+ if (Event != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Status = SdMmcPassThruExecSyncTrb (Private, Trb);
+
+ SdMmcFreeTrb (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
+SdMmcPassThruGetNextSlot (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 *Slot
+ )
+{
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ UINT8 Index;
+
+ if ((This == NULL) || (Slot == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ if (*Slot == 0xFF) {
+ for (Index = 0; Index < SD_MMC_HC_MAX_SLOT; Index++) {
+ if (Private->Slot[Index].Enable) {
+ *Slot = Index;
+ Private->PreviousSlot = Index;
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_NOT_FOUND;
+ } else if (*Slot == Private->PreviousSlot) {
+ for (Index = *Slot + 1; Index < SD_MMC_HC_MAX_SLOT; Index++) {
+ if (Private->Slot[Index].Enable) {
+ *Slot = Index;
+ Private->PreviousSlot = Index;
+ return EFI_SUCCESS;
+ }
+ }
+ 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 responsibility 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
+SdMmcPassThruBuildDevicePath (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ SD_DEVICE_PATH *SdNode;
+ EMMC_DEVICE_PATH *EmmcNode;
+
+ if ((This == NULL) || (DevicePath == NULL) || (Slot >= SD_MMC_HC_MAX_SLOT)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = SD_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
+SdMmcPassThruGetSlotNumber (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT8 *Slot
+ )
+{
+ SD_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 = SD_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 >= SD_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
+SdMmcPassThruResetDevice (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
+ IN UINT8 Slot
+ )
+{
+ SD_MMC_HC_PRIVATE_DATA *Private;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ SD_MMC_HC_TRB *Trb;
+ EFI_TPL OldTpl;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);
+
+ if (!Private->Slot[Slot].Enable) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!Private->Slot[Slot].MediaPresent) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (!Private->Slot[Slot].Initialized) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // 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 = SD_MMC_HC_TRB_FROM_THIS (Link);
+ Trb->Packet->TransactionStatus = EFI_ABORTED;
+ gBS->SignalEvent (Trb->Event);
+ SdMmcFreeTrb (Trb);
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h new file mode 100644 index 000000000..40e4373e5 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h @@ -0,0 +1,864 @@ +/** @file
+
+ Provides some data structure definitions used by the SD/MMC host controller driver.
+
+Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
+Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SD_MMC_PCI_HC_DXE_H_
+#define _SD_MMC_PCI_HC_DXE_H_
+
+#include <Uefi.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Emmc.h>
+#include <IndustryStandard/Sd.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/SdMmcOverride.h>
+#include <Protocol/SdMmcPassThru.h>
+
+#include "SdMmcPciHci.h"
+
+extern EFI_COMPONENT_NAME_PROTOCOL gSdMmcPciHcComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gSdMmcPciHcComponentName2;
+extern EFI_DRIVER_BINDING_PROTOCOL gSdMmcPciHcDriverBinding;
+
+extern EDKII_SD_MMC_OVERRIDE *mOverride;
+
+#define SD_MMC_HC_PRIVATE_SIGNATURE SIGNATURE_32 ('s', 'd', 't', 'f')
+
+#define SD_MMC_HC_PRIVATE_FROM_THIS(a) \
+ CR(a, SD_MMC_HC_PRIVATE_DATA, PassThru, SD_MMC_HC_PRIVATE_SIGNATURE)
+
+//
+// Generic time out value, 1 microsecond as unit.
+//
+#define SD_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 SD_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 SD_MMC_HC_ENUM_TIMER EFI_TIMER_PERIOD_MILLISECONDS(100)
+
+typedef enum {
+ UnknownCardType,
+ SdCardType,
+ SdioCardType,
+ MmcCardType,
+ EmmcCardType
+} SD_MMC_CARD_TYPE;
+
+typedef enum {
+ RemovableSlot,
+ EmbeddedSlot,
+ SharedBusSlot,
+ UnknownSlot
+} EFI_SD_MMC_SLOT_TYPE;
+
+typedef struct {
+ BOOLEAN Enable;
+ EFI_SD_MMC_SLOT_TYPE SlotType;
+ BOOLEAN MediaPresent;
+ BOOLEAN Initialized;
+ SD_MMC_CARD_TYPE CardType;
+ UINT64 CurrentFreq;
+ EDKII_SD_MMC_OPERATING_PARAMETERS OperatingParameters;
+} SD_MMC_HC_SLOT;
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE ControllerHandle;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ EFI_SD_MMC_PASS_THRU_PROTOCOL PassThru;
+
+ UINT64 PciAttributes;
+ //
+ // 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;
+
+ SD_MMC_HC_SLOT Slot[SD_MMC_HC_MAX_SLOT];
+ SD_MMC_HC_SLOT_CAP Capability[SD_MMC_HC_MAX_SLOT];
+ UINT64 MaxCurrent[SD_MMC_HC_MAX_SLOT];
+ UINT16 ControllerVersion[SD_MMC_HC_MAX_SLOT];
+
+ //
+ // Some controllers may require to override base clock frequency
+ // value stored in Capabilities Register 1.
+ //
+ UINT32 BaseClkFreq[SD_MMC_HC_MAX_SLOT];
+} SD_MMC_HC_PRIVATE_DATA;
+
+typedef struct {
+ SD_MMC_BUS_MODE BusTiming;
+ UINT8 BusWidth;
+ UINT32 ClockFreq;
+ EDKII_SD_MMC_DRIVER_STRENGTH DriverStrength;
+} SD_MMC_BUS_SETTINGS;
+
+#define SD_MMC_HC_TRB_SIG SIGNATURE_32 ('T', 'R', 'B', 'T')
+
+#define SD_MMC_TRB_RETRIES 5
+
+//
+// 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;
+ SD_MMC_HC_TRANSFER_MODE Mode;
+ SD_MMC_HC_ADMA_LENGTH_MODE AdmaLengthMode;
+
+ EFI_EVENT Event;
+ BOOLEAN Started;
+ BOOLEAN CommandComplete;
+ UINT64 Timeout;
+ UINT32 Retries;
+
+ BOOLEAN PioModeTransferCompleted;
+ UINT32 PioBlockIndex;
+
+ SD_MMC_HC_ADMA_32_DESC_LINE *Adma32Desc;
+ SD_MMC_HC_ADMA_64_V3_DESC_LINE *Adma64V3Desc;
+ SD_MMC_HC_ADMA_64_V4_DESC_LINE *Adma64V4Desc;
+ EFI_PHYSICAL_ADDRESS AdmaDescPhy;
+ VOID *AdmaMap;
+ UINT32 AdmaPages;
+
+ SD_MMC_HC_PRIVATE_DATA *Private;
+} SD_MMC_HC_TRB;
+
+#define SD_MMC_HC_TRB_FROM_THIS(a) \
+ CR(a, SD_MMC_HC_TRB, TrbList, SD_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;
+} SD_MMC_HC_QUEUE;
+
+//
+// Prototypes
+//
+/**
+ Execute card identification procedure.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The card is identified correctly.
+ @retval Others The card can't be identified.
+
+**/
+typedef
+EFI_STATUS
+(*CARD_TYPE_DETECT_ROUTINE) (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ );
+
+/**
+ 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
+SdMmcPassThruPassThru (
+ 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
+SdMmcPassThruGetNextSlot (
+ 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 responsibility 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
+SdMmcPassThruBuildDevicePath (
+ 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
+SdMmcPassThruGetSlotNumber (
+ 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
+SdMmcPassThruResetDevice (
+ 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 determine 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
+SdMmcPciHcDriverBindingSupported (
+ 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 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
+SdMmcPciHcDriverBindingStart (
+ 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
+SdMmcPciHcDriverBindingStop (
+ 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
+SdMmcPciHcComponentNameGetDriverName (
+ 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
+SdMmcPciHcComponentNameGetControllerName (
+ 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 SD_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.
+
+**/
+SD_MMC_HC_TRB *
+SdMmcCreateTrb (
+ IN SD_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 SD_MMC_HC_TRB instance.
+
+**/
+VOID
+SdMmcFreeTrb (
+ IN SD_MMC_HC_TRB *Trb
+ );
+
+/**
+ Check if the env is ready for execute specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_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
+SdMmcCheckTrbEnv (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ );
+
+/**
+ Wait for the env to be ready for execute specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_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
+SdMmcWaitTrbEnv (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ );
+
+/**
+ Execute the specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_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
+SdMmcExecTrb (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ );
+
+/**
+ Check the TRB execution result.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_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
+SdMmcCheckTrbResult (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ );
+
+/**
+ Wait for the TRB execution result.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+SdMmcWaitTrbResult (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_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 SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS There is a EMMC card.
+ @retval Others There is not a EMMC card.
+
+**/
+EFI_STATUS
+EmmcIdentification (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ );
+
+/**
+ 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 SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS There is a EMMC card.
+ @retval Others There is not a EMMC card.
+
+**/
+EFI_STATUS
+SdCardIdentification (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ 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] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] BusTiming BusTiming at which the frequency change is done.
+ @param[in] FirstTimeSetup Flag to indicate whether the clock is being setup for the first time.
+ @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+SdMmcHcClockSupply (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN SD_MMC_BUS_MODE BusTiming,
+ IN BOOLEAN FirstTimeSetup,
+ IN UINT64 ClockFreq
+ );
+
+/**
+ Software reset the specified SD/MMC host controller.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA 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
+SdMmcHcReset (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ );
+
+/**
+ Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value
+ at initialization.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The host controller is initialized successfully.
+ @retval Others The host controller isn't initialized successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitHost (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf new file mode 100644 index 000000000..453ecde7f --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf @@ -0,0 +1,70 @@ +## @file
+# SdMmcPciHcDxe driver is used to manage those host controllers which comply with SD
+# Host Controller Simplified Specification version 3.0 plus the 64-bit System Addressing
+# support in SD Host Controller Simplified Specification version 4.20.
+#
+# 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 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SdMmcPciHcDxe
+ MODULE_UNI_FILE = SdMmcPciHcDxe.uni
+ FILE_GUID = 8E325979-3FE1-4927-AAE2-8F5C4BD2AF0D
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeSdMmcPciHcDxe
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gSdMmcPciHcDxeDriverBinding
+# COMPONENT_NAME = gSdMmcPciHcDxeComponentName
+# COMPONENT_NAME2 = gSdMmcPciHcDxeComponentName2
+#
+#
+
+[Sources]
+ SdMmcPciHcDxe.h
+ SdMmcPciHcDxe.c
+ EmmcDevice.c
+ SdDevice.c
+ SdMmcPciHci.h
+ SdMmcPciHci.c
+ ComponentName.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Protocols]
+ gEdkiiSdMmcOverrideProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiSdMmcPassThruProtocolGuid ## BY_START
+
+# [Event]
+# EVENT_TYPE_PERIODIC_TIMER ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SdMmcPciHcDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.uni b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.uni new file mode 100644 index 000000000..962e19c2f --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.uni @@ -0,0 +1,19 @@ +// /** @file
+// SdMmcPciHcDxe driver is used to manage those host controllers which comply with SD
+// Host Controller Simplified Specification version 3.0 plus the 64-bit System Addressing
+// support in SD Host Controller Simplified Specification version 4.20.
+//
+// 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 - 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "SD/MMC Pci Host Controller driver to manage SD/MMC host controllers"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver follows the UEFI driver model and produces SD/MMC Pass Thru protocol for upper layer bus driver."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxeExtra.uni new file mode 100644 index 000000000..8dfbd86ae --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxeExtra.uni @@ -0,0 +1,14 @@ +// /** @file
+// SdMmcPciHcDxe Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"SD/MMC Pci Host Controller Driver"
+
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c new file mode 100644 index 000000000..6548ef71d --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c @@ -0,0 +1,2838 @@ +/** @file
+ This driver is used to manage SD/MMC PCI host controllers which are compliance
+ with SD Host Controller Simplified Specification version 3.00 plus the 64-bit
+ System Addressing support in SD Host Controller Simplified Specification version
+ 4.20.
+
+ It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.
+
+ Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
+ Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SdMmcPciHcDxe.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 SD_MMC_HC_SLOT_CAP *Capability
+ )
+{
+ //
+ // Dump Capability Data
+ //
+ DEBUG ((DEBUG_INFO, " == Slot [%d] Capability is 0x%x ==\n", Slot, Capability));
+ DEBUG ((DEBUG_INFO, " Timeout Clk Freq %d%a\n", Capability->TimeoutFreq, (Capability->TimeoutUnit) ? "MHz" : "KHz"));
+ DEBUG ((DEBUG_INFO, " Base Clk Freq %dMHz\n", Capability->BaseClkFreq));
+ DEBUG ((DEBUG_INFO, " Max Blk Len %dbytes\n", 512 * (1 << Capability->MaxBlkLen)));
+ DEBUG ((DEBUG_INFO, " 8-bit Support %a\n", Capability->BusWidth8 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " ADMA2 Support %a\n", Capability->Adma2 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " HighSpeed Support %a\n", Capability->HighSpeed ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " SDMA Support %a\n", Capability->Sdma ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Suspend/Resume %a\n", Capability->SuspRes ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Voltage 3.3 %a\n", Capability->Voltage33 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Voltage 3.0 %a\n", Capability->Voltage30 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Voltage 1.8 %a\n", Capability->Voltage18 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " V4 64-bit Sys Bus %a\n", Capability->SysBus64V4 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " V3 64-bit Sys Bus %a\n", Capability->SysBus64V3 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Async Interrupt %a\n", Capability->AsyncInt ? "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"));
+ DEBUG ((DEBUG_INFO, " Driver Type A %a\n", Capability->DriverTypeA ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Driver Type C %a\n", Capability->DriverTypeC ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Driver Type D %a\n", Capability->DriverTypeD ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Driver Type 4 %a\n", Capability->DriverType4 ? "TRUE" : "FALSE"));
+ if (Capability->TimerCount == 0) {
+ DEBUG ((DEBUG_INFO, " Retuning TimerCnt Disabled\n", 2 * (Capability->TimerCount - 1)));
+ } else {
+ DEBUG ((DEBUG_INFO, " Retuning TimerCnt %dseconds\n", 2 * (Capability->TimerCount - 1)));
+ }
+ DEBUG ((DEBUG_INFO, " SDR50 Tuning %a\n", Capability->TuningSDR50 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Retuning Mode Mode %d\n", Capability->RetuningMod + 1));
+ DEBUG ((DEBUG_INFO, " Clock Multiplier M = %d\n", Capability->ClkMultiplier + 1));
+ DEBUG ((DEBUG_INFO, " HS 400 %a\n", Capability->Hs400 ? "TRUE" : "FALSE"));
+ return;
+}
+
+/**
+ 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
+SdMmcHcGetSlotInfo (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ OUT UINT8 *FirstBar,
+ OUT UINT8 *SlotNum
+ )
+{
+ EFI_STATUS Status;
+ SD_MMC_HC_SLOT_INFO SlotInfo;
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ SD_MMC_HC_SLOT_OFFSET,
+ sizeof (SlotInfo),
+ &SlotInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *FirstBar = SlotInfo.FirstBar;
+ *SlotNum = SlotInfo.SlotNum + 1;
+ ASSERT ((*FirstBar + *SlotNum) < SD_MMC_HC_MAX_SLOT);
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+SdMmcHcRwMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN BOOLEAN Read,
+ IN UINT8 Count,
+ IN OUT VOID *Data
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;
+
+ if ((PciIo == NULL) || (Data == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (Count) {
+ case 1:
+ Width = EfiPciIoWidthUint8;
+ break;
+ case 2:
+ Width = EfiPciIoWidthUint16;
+ Count = 1;
+ break;
+ case 4:
+ Width = EfiPciIoWidthUint32;
+ Count = 1;
+ break;
+ case 8:
+ Width = EfiPciIoWidthUint32;
+ Count = 2;
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Read) {
+ Status = PciIo->Mem.Read (
+ PciIo,
+ Width,
+ BarIndex,
+ (UINT64) Offset,
+ Count,
+ Data
+ );
+ } else {
+ Status = PciIo->Mem.Write (
+ PciIo,
+ Width,
+ BarIndex,
+ (UINT64) Offset,
+ Count,
+ Data
+ );
+ }
+
+ return Status;
+}
+
+/**
+ 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
+SdMmcHcOrMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN VOID *OrData
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ UINT64 Or;
+
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Count == 1) {
+ Or = *(UINT8*) OrData;
+ } else if (Count == 2) {
+ Or = *(UINT16*) OrData;
+ } else if (Count == 4) {
+ Or = *(UINT32*) OrData;
+ } else if (Count == 8) {
+ Or = *(UINT64*) OrData;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Data |= Or;
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, FALSE, Count, &Data);
+
+ return Status;
+}
+
+/**
+ 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
+SdMmcHcAndMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN VOID *AndData
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ UINT64 And;
+
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Count == 1) {
+ And = *(UINT8*) AndData;
+ } else if (Count == 2) {
+ And = *(UINT16*) AndData;
+ } else if (Count == 4) {
+ And = *(UINT32*) AndData;
+ } else if (Count == 8) {
+ And = *(UINT64*) AndData;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Data &= And;
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, FALSE, Count, &Data);
+
+ return Status;
+}
+
+/**
+ 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.
+
+ @retval EFI_NOT_READY The MMIO register hasn't set to the expected value.
+ @retval EFI_SUCCESS The MMIO register has expected value.
+ @retval Others The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMmcHcCheckMmioSet (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN UINT64 MaskValue,
+ IN UINT64 TestValue
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Value;
+
+ //
+ // Access PCI MMIO space to see if the value is the tested one.
+ //
+ Value = 0;
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Value);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Value &= MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_READY;
+}
+
+/**
+ 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
+SdMmcHcWaitMmioSet (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN UINT64 MaskValue,
+ IN UINT64 TestValue,
+ IN UINT64 Timeout
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN InfiniteWait;
+
+ if (Timeout == 0) {
+ InfiniteWait = TRUE;
+ } else {
+ InfiniteWait = FALSE;
+ }
+
+ while (InfiniteWait || (Timeout > 0)) {
+ Status = SdMmcHcCheckMmioSet (
+ PciIo,
+ BarIndex,
+ Offset,
+ Count,
+ MaskValue,
+ TestValue
+ );
+ if (Status != EFI_NOT_READY) {
+ return Status;
+ }
+
+ //
+ // Stall for 1 microsecond.
+ //
+ gBS->Stall (1);
+
+ Timeout--;
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Get the controller version information 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] Version The buffer to store the version information.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdMmcHcGetControllerVersion (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT UINT16 *Version
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (UINT16), Version);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *Version &= 0xFF;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Software reset the specified SD/MMC host controller and enable all interrupts.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA 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
+SdMmcHcReset (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT8 SwReset;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ //
+ // Notify the SD/MMC override protocol that we are about to reset
+ // the SD/MMC host controller.
+ //
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ Private->ControllerHandle,
+ Slot,
+ EdkiiSdMmcResetPre,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN,
+ "%a: SD/MMC pre reset notifier callback failed - %r\n",
+ __FUNCTION__, Status));
+ return Status;
+ }
+ }
+
+ PciIo = Private->PciIo;
+ SwReset = BIT0;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_SW_RST, sizeof (SwReset), &SwReset);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "SdMmcHcReset: write SW Reset for All fails: %r\n", Status));
+ return Status;
+ }
+
+ Status = SdMmcHcWaitMmioSet (
+ PciIo,
+ Slot,
+ SD_MMC_HC_SW_RST,
+ sizeof (SwReset),
+ BIT0,
+ 0x00,
+ SD_MMC_HC_GENERIC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SdMmcHcReset: reset done with %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Enable all interrupt after reset all.
+ //
+ Status = SdMmcHcEnableInterrupt (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SdMmcHcReset: SdMmcHcEnableInterrupt done with %r\n",
+ Status));
+ return Status;
+ }
+
+ //
+ // Notify the SD/MMC override protocol that we have just reset
+ // the SD/MMC host controller.
+ //
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ Private->ControllerHandle,
+ Slot,
+ EdkiiSdMmcResetPost,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN,
+ "%a: SD/MMC post reset notifier callback failed - %r\n",
+ __FUNCTION__, Status));
+ }
+ }
+
+ return Status;
+}
+
+/**
+ 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
+SdMmcHcEnableInterrupt (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT16 IntStatus;
+
+ //
+ // Enable all bits in Error Interrupt Status Enable Register
+ //
+ IntStatus = 0xFFFF;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_ERR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Enable all bits in Normal Interrupt Status Enable Register
+ //
+ IntStatus = 0xFFFF;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);
+
+ return Status;
+}
+
+/**
+ 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
+SdMmcHcGetCapability (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT SD_MMC_HC_SLOT_CAP *Capability
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Cap;
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CAP, TRUE, sizeof (Cap), &Cap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (Capability, &Cap, sizeof (Cap));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+SdMmcHcGetMaxCurrent (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT UINT64 *MaxCurrent
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_MAX_CURRENT_CAP, TRUE, sizeof (UINT64), MaxCurrent);
+
+ 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] 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
+SdMmcHcCardDetect (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT BOOLEAN *MediaPresent
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Data;
+ UINT32 PresentState;
+
+ //
+ // Check Present State Register to see if there is a card presented.
+ //
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((PresentState & BIT16) != 0) {
+ *MediaPresent = TRUE;
+ } else {
+ *MediaPresent = FALSE;
+ }
+
+ //
+ // Check Normal Interrupt Status Register
+ //
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS, TRUE, sizeof (Data), &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((Data & (BIT6 | BIT7)) != 0) {
+ //
+ // Clear BIT6 and BIT7 by writing 1 to these two bits if set.
+ //
+ Data &= BIT6 | BIT7;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (Data), &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_MEDIA_CHANGED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+SdMmcHcStopClock (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT32 PresentState;
+ UINT16 ClockCtrl;
+
+ //
+ // Ensure no SD transactions are occurring on the SD Bus by
+ // waiting for Command Inhibit (DAT) and Command Inhibit (CMD)
+ // in the Present State register to be 0.
+ //
+ Status = SdMmcHcWaitMmioSet (
+ PciIo,
+ Slot,
+ SD_MMC_HC_PRESENT_STATE,
+ sizeof (PresentState),
+ BIT0 | BIT1,
+ 0,
+ SD_MMC_HC_GENERIC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Set SD Clock Enable in the Clock Control register to 0
+ //
+ ClockCtrl = (UINT16)~BIT2;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
+
+ return Status;
+}
+
+/**
+ Start the SD clock.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number.
+
+ @retval EFI_SUCCESS Succeeded to start the SD clock.
+ @retval Others Failed to start the SD clock.
+**/
+EFI_STATUS
+SdMmcHcStartSdClock (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ )
+{
+ UINT16 ClockCtrl;
+
+ //
+ // Set SD Clock Enable in the Clock Control register to 1
+ //
+ ClockCtrl = BIT2;
+ return SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
+}
+
+/**
+ SD/MMC card clock supply.
+
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] BusTiming BusTiming at which the frequency change is done.
+ @param[in] FirstTimeSetup Flag to indicate whether the clock is being setup for the first time.
+ @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+ @retval Others The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+SdMmcHcClockSupply (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN SD_MMC_BUS_MODE BusTiming,
+ IN BOOLEAN FirstTimeSetup,
+ IN UINT64 ClockFreq
+ )
+{
+ EFI_STATUS Status;
+ UINT32 SettingFreq;
+ UINT32 Divisor;
+ UINT32 Remainder;
+ UINT16 ClockCtrl;
+ UINT32 BaseClkFreq;
+ UINT16 ControllerVer;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ PciIo = Private->PciIo;
+ BaseClkFreq = Private->BaseClkFreq[Slot];
+ ControllerVer = Private->ControllerVersion[Slot];
+
+ if (BaseClkFreq == 0 || ClockFreq == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ClockFreq > (BaseClkFreq * 1000)) {
+ ClockFreq = BaseClkFreq * 1000;
+ }
+
+ //
+ // Calculate the divisor of base frequency.
+ //
+ Divisor = 0;
+ SettingFreq = BaseClkFreq * 1000;
+ while (ClockFreq < SettingFreq) {
+ Divisor++;
+
+ SettingFreq = (BaseClkFreq * 1000) / (2 * Divisor);
+ Remainder = (BaseClkFreq * 1000) % (2 * Divisor);
+ if ((ClockFreq == SettingFreq) && (Remainder == 0)) {
+ break;
+ }
+ if ((ClockFreq == SettingFreq) && (Remainder != 0)) {
+ SettingFreq ++;
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq));
+
+ //
+ // Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register.
+ //
+ if ((ControllerVer >= SD_MMC_HC_CTRL_VER_300) &&
+ (ControllerVer <= SD_MMC_HC_CTRL_VER_420)) {
+ ASSERT (Divisor <= 0x3FF);
+ ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2);
+ } else if ((ControllerVer == SD_MMC_HC_CTRL_VER_100) ||
+ (ControllerVer == SD_MMC_HC_CTRL_VER_200)) {
+ //
+ // Only the most significant bit can be used as divisor.
+ //
+ if (((Divisor - 1) & Divisor) != 0) {
+ Divisor = 1 << (HighBitSet32 (Divisor) + 1);
+ }
+ ASSERT (Divisor <= 0x80);
+ ClockCtrl = (Divisor & 0xFF) << 8;
+ } else {
+ DEBUG ((DEBUG_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Stop bus clock at first
+ //
+ Status = SdMmcHcStopClock (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Supply clock frequency with specified divisor
+ //
+ ClockCtrl |= BIT0;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n"));
+ return Status;
+ }
+
+ //
+ // Wait Internal Clock Stable in the Clock Control register to be 1
+ //
+ Status = SdMmcHcWaitMmioSet (
+ PciIo,
+ Slot,
+ SD_MMC_HC_CLOCK_CTRL,
+ sizeof (ClockCtrl),
+ BIT1,
+ BIT1,
+ SD_MMC_HC_GENERIC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcHcStartSdClock (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // We don't notify the platform on first time setup to avoid changing
+ // legacy behavior. During first time setup we also don't know what type
+ // of the card slot it is and which enum value of BusTiming applies.
+ //
+ if (!FirstTimeSetup && mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ Private->ControllerHandle,
+ Slot,
+ EdkiiSdMmcSwitchClockFreqPost,
+ &BusTiming
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: SD/MMC switch clock freq post notifier callback failed - %r\n",
+ __FUNCTION__,
+ Status
+ ));
+ return Status;
+ }
+ }
+
+ Private->Slot[Slot].CurrentFreq = ClockFreq;
+
+ return Status;
+}
+
+/**
+ 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
+SdMmcHcPowerControl (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN UINT8 PowerCtrl
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Clr SD Bus Power
+ //
+ PowerCtrl &= (UINT8)~BIT0;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register
+ //
+ PowerCtrl |= BIT0;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);
+
+ return Status;
+}
+
+/**
+ 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
+SdMmcHcSetBusWidth (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN UINT16 BusWidth
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl1;
+
+ if (BusWidth == 1) {
+ HostCtrl1 = (UINT8)~(BIT5 | BIT1);
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ } else if (BusWidth == 4) {
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ HostCtrl1 |= BIT1;
+ HostCtrl1 &= (UINT8)~BIT5;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);
+ } else if (BusWidth == 8) {
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ HostCtrl1 &= (UINT8)~BIT1;
+ HostCtrl1 |= BIT5;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);
+ } else {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
+
+/**
+ Configure V4 controller enhancements 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.
+ @param[in] ControllerVer The version of host controller.
+
+ @retval EFI_SUCCESS The clock is supplied successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitV4Enhancements (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP Capability,
+ IN UINT16 ControllerVer
+ )
+{
+ EFI_STATUS Status;
+ UINT16 HostCtrl2;
+
+ //
+ // Check if controller version V4 or higher
+ //
+ if (ControllerVer >= SD_MMC_HC_CTRL_VER_400) {
+ HostCtrl2 = SD_MMC_HC_V4_EN;
+ //
+ // Check if controller version V4.0
+ //
+ if (ControllerVer == SD_MMC_HC_CTRL_VER_400) {
+ //
+ // Check if 64bit support is available
+ //
+ if (Capability.SysBus64V3 != 0) {
+ HostCtrl2 |= SD_MMC_HC_64_ADDR_EN;
+ DEBUG ((DEBUG_INFO, "Enabled V4 64 bit system bus support\n"));
+ }
+ }
+ //
+ // Check if controller version V4.10 or higher
+ //
+ else if (ControllerVer >= SD_MMC_HC_CTRL_VER_410) {
+ //
+ // Check if 64bit support is available
+ //
+ if (Capability.SysBus64V4 != 0) {
+ HostCtrl2 |= SD_MMC_HC_64_ADDR_EN;
+ DEBUG ((DEBUG_INFO, "Enabled V4 64 bit system bus support\n"));
+ }
+ HostCtrl2 |= SD_MMC_HC_26_DATA_LEN_ADMA_EN;
+ DEBUG ((DEBUG_INFO, "Enabled V4 26 bit data length ADMA support\n"));
+ }
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+SdMmcHcInitPowerVoltage (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP Capability
+ )
+{
+ EFI_STATUS Status;
+ UINT8 MaxVoltage;
+ UINT8 HostCtrl2;
+
+ //
+ // Calculate supported maximum voltage according to SD Bus Voltage Select
+ //
+ if (Capability.Voltage33 != 0) {
+ //
+ // Support 3.3V
+ //
+ MaxVoltage = 0x0E;
+ } else if (Capability.Voltage30 != 0) {
+ //
+ // Support 3.0V
+ //
+ MaxVoltage = 0x0C;
+ } else if (Capability.Voltage18 != 0) {
+ //
+ // Support 1.8V
+ //
+ MaxVoltage = 0x0A;
+ HostCtrl2 = BIT3;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ gBS->Stall (5000);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register
+ //
+ Status = SdMmcHcPowerControl (PciIo, Slot, MaxVoltage);
+
+ return Status;
+}
+
+/**
+ 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
+SdMmcHcInitTimeoutCtrl (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Timeout;
+
+ Timeout = 0x0E;
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_TIMEOUT_CTRL, FALSE, sizeof (Timeout), &Timeout);
+
+ return Status;
+}
+
+/**
+ Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value
+ at initialization.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+
+ @retval EFI_SUCCESS The host controller is initialized successfully.
+ @retval Others The host controller isn't initialized successfully.
+
+**/
+EFI_STATUS
+SdMmcHcInitHost (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ SD_MMC_HC_SLOT_CAP Capability;
+
+ //
+ // Notify the SD/MMC override protocol that we are about to initialize
+ // the SD/MMC host controller.
+ //
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ Private->ControllerHandle,
+ Slot,
+ EdkiiSdMmcInitHostPre,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN,
+ "%a: SD/MMC pre init notifier callback failed - %r\n",
+ __FUNCTION__, Status));
+ return Status;
+ }
+ }
+
+ PciIo = Private->PciIo;
+ Capability = Private->Capability[Slot];
+
+ Status = SdMmcHcInitV4Enhancements (PciIo, Slot, Capability, Private->ControllerVersion[Slot]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Perform first time clock setup with 400 KHz frequency.
+ // We send the 0 as the BusTiming value because at this time
+ // we still do not know the slot type and which enum value will apply.
+ // Since it is a first time setup SdMmcHcClockSupply won't notify
+ // the platofrm driver anyway so it doesn't matter.
+ //
+ Status = SdMmcHcClockSupply (Private, Slot, 0, TRUE, 400);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcHcInitPowerVoltage (PciIo, Slot, Capability);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcHcInitTimeoutCtrl (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Notify the SD/MMC override protocol that we are have just initialized
+ // the SD/MMC host controller.
+ //
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ Private->ControllerHandle,
+ Slot,
+ EdkiiSdMmcInitHostPost,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN,
+ "%a: SD/MMC post init notifier callback failed - %r\n",
+ __FUNCTION__, Status));
+ }
+ }
+ return Status;
+}
+
+/**
+ Set SD Host Controler control 2 registry according to selected speed.
+
+ @param[in] ControllerHandle The handle of the controller.
+ @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] Timing The timing to select.
+
+ @retval EFI_SUCCESS The timing is set successfully.
+ @retval Others The timing isn't set successfully.
+**/
+EFI_STATUS
+SdMmcHcUhsSignaling (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN SD_MMC_BUS_MODE Timing
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl2;
+
+ HostCtrl2 = (UINT8)~SD_MMC_HC_CTRL_UHS_MASK;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ switch (Timing) {
+ case SdMmcUhsSdr12:
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR12;
+ break;
+ case SdMmcUhsSdr25:
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR25;
+ break;
+ case SdMmcUhsSdr50:
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR50;
+ break;
+ case SdMmcUhsSdr104:
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR104;
+ break;
+ case SdMmcUhsDdr50:
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_DDR50;
+ break;
+ case SdMmcMmcLegacy:
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_LEGACY;
+ break;
+ case SdMmcMmcHsSdr:
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS_SDR;
+ break;
+ case SdMmcMmcHsDdr:
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS_DDR;
+ break;
+ case SdMmcMmcHs200:
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS200;
+ break;
+ case SdMmcMmcHs400:
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS400;
+ break;
+ default:
+ HostCtrl2 = 0;
+ break;
+ }
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ ControllerHandle,
+ Slot,
+ EdkiiSdMmcUhsSignaling,
+ &Timing
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: SD/MMC uhs signaling notifier callback failed - %r\n",
+ __FUNCTION__,
+ Status
+ ));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set driver strength in host controller.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] SlotIndex The slot index of the card.
+ @param[in] DriverStrength DriverStrength to set in the controller.
+
+ @retval EFI_SUCCESS Driver strength programmed successfully.
+ @retval Others Failed to set driver strength.
+**/
+EFI_STATUS
+SdMmcSetDriverStrength (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 SlotIndex,
+ IN SD_DRIVER_STRENGTH_TYPE DriverStrength
+ )
+{
+ EFI_STATUS Status;
+ UINT16 HostCtrl2;
+
+ if (DriverStrength == SdDriverStrengthIgnore) {
+ return EFI_SUCCESS;
+ }
+
+ HostCtrl2 = (UINT16)~SD_MMC_HC_CTRL_DRIVER_STRENGTH_MASK;
+ Status = SdMmcHcAndMmio (PciIo, SlotIndex, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HostCtrl2 = (DriverStrength << 4) & SD_MMC_HC_CTRL_DRIVER_STRENGTH_MASK;
+ return SdMmcHcOrMmio (PciIo, SlotIndex, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+}
+
+/**
+ Turn on/off LED.
+
+ @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] On The boolean to turn on/off LED.
+
+ @retval EFI_SUCCESS The LED is turned on/off successfully.
+ @retval Others The LED isn't turned on/off successfully.
+
+**/
+EFI_STATUS
+SdMmcHcLedOnOff (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN BOOLEAN On
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl1;
+
+ if (On) {
+ HostCtrl1 = BIT0;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ } else {
+ HostCtrl1 = (UINT8)~BIT0;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ }
+
+ return Status;
+}
+
+/**
+ Build ADMA descriptor table for transfer.
+
+ Refer to SD Host Controller Simplified spec 4.2 Section 1.13 for details.
+
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+ @param[in] ControllerVer The version of host controller.
+
+ @retval EFI_SUCCESS The ADMA descriptor table is created successfully.
+ @retval Others The ADMA descriptor table isn't created successfully.
+
+**/
+EFI_STATUS
+BuildAdmaDescTable (
+ IN SD_MMC_HC_TRB *Trb,
+ IN UINT16 ControllerVer
+ )
+{
+ EFI_PHYSICAL_ADDRESS Data;
+ UINT64 DataLen;
+ UINT64 Entries;
+ UINT32 Index;
+ UINT64 Remaining;
+ UINT64 Address;
+ UINTN TableSize;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINTN Bytes;
+ UINT32 AdmaMaxDataPerLine;
+ UINT32 DescSize;
+ VOID *AdmaDesc;
+
+ AdmaMaxDataPerLine = ADMA_MAX_DATA_PER_LINE_16B;
+ DescSize = sizeof (SD_MMC_HC_ADMA_32_DESC_LINE);
+ AdmaDesc = NULL;
+
+ Data = Trb->DataPhy;
+ DataLen = Trb->DataLen;
+ PciIo = Trb->Private->PciIo;
+
+ //
+ // Check for valid ranges in 32bit ADMA Descriptor Table
+ //
+ if ((Trb->Mode == SdMmcAdma32bMode) &&
+ ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check address field alignment
+ //
+ if (Trb->Mode != SdMmcAdma32bMode) {
+ //
+ // Address field shall be set on 64-bit boundary (Lower 3-bit is always set to 0)
+ //
+ if ((Data & (BIT0 | BIT1 | BIT2)) != 0) {
+ DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 8 bytes boundary!\n", Data));
+ }
+ } else {
+ //
+ // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)
+ //
+ if ((Data & (BIT0 | BIT1)) != 0) {
+ DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));
+ }
+ }
+
+ //
+ // Configure 64b ADMA.
+ //
+ if (Trb->Mode == SdMmcAdma64bV3Mode) {
+ DescSize = sizeof (SD_MMC_HC_ADMA_64_V3_DESC_LINE);
+ }else if (Trb->Mode == SdMmcAdma64bV4Mode) {
+ DescSize = sizeof (SD_MMC_HC_ADMA_64_V4_DESC_LINE);
+ }
+ //
+ // Configure 26b data length.
+ //
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ AdmaMaxDataPerLine = ADMA_MAX_DATA_PER_LINE_26B;
+ }
+
+ Entries = DivU64x32 ((DataLen + AdmaMaxDataPerLine - 1), AdmaMaxDataPerLine);
+ TableSize = (UINTN)MultU64x32 (Entries, DescSize);
+ Trb->AdmaPages = (UINT32)EFI_SIZE_TO_PAGES (TableSize);
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (TableSize),
+ (VOID **)&AdmaDesc,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ZeroMem (AdmaDesc, TableSize);
+ Bytes = TableSize;
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ AdmaDesc,
+ &Bytes,
+ &Trb->AdmaDescPhy,
+ &Trb->AdmaMap
+ );
+
+ if (EFI_ERROR (Status) || (Bytes != TableSize)) {
+ //
+ // Map error or unable to map the whole RFis buffer into a contiguous region.
+ //
+ PciIo->FreeBuffer (
+ PciIo,
+ EFI_SIZE_TO_PAGES (TableSize),
+ AdmaDesc
+ );
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if ((Trb->Mode == SdMmcAdma32bMode) &&
+ (UINT64)(UINTN)Trb->AdmaDescPhy > 0x100000000ul) {
+ //
+ // The ADMA doesn't support 64bit addressing.
+ //
+ PciIo->Unmap (
+ PciIo,
+ Trb->AdmaMap
+ );
+ Trb->AdmaMap = NULL;
+
+ PciIo->FreeBuffer (
+ PciIo,
+ EFI_SIZE_TO_PAGES (TableSize),
+ AdmaDesc
+ );
+ return EFI_DEVICE_ERROR;
+ }
+
+ Remaining = DataLen;
+ Address = Data;
+ if (Trb->Mode == SdMmcAdma32bMode) {
+ Trb->Adma32Desc = AdmaDesc;
+ } else if (Trb->Mode == SdMmcAdma64bV3Mode) {
+ Trb->Adma64V3Desc = AdmaDesc;
+ } else {
+ Trb->Adma64V4Desc = AdmaDesc;
+ }
+
+ for (Index = 0; Index < Entries; Index++) {
+ if (Trb->Mode == SdMmcAdma32bMode) {
+ if (Remaining <= AdmaMaxDataPerLine) {
+ Trb->Adma32Desc[Index].Valid = 1;
+ Trb->Adma32Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma32Desc[Index].UpperLength = (UINT16)RShiftU64 (Remaining, 16);
+ }
+ Trb->Adma32Desc[Index].LowerLength = (UINT16)(Remaining & MAX_UINT16);
+ Trb->Adma32Desc[Index].Address = (UINT32)Address;
+ break;
+ } else {
+ Trb->Adma32Desc[Index].Valid = 1;
+ Trb->Adma32Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma32Desc[Index].UpperLength = 0;
+ }
+ Trb->Adma32Desc[Index].LowerLength = 0;
+ Trb->Adma32Desc[Index].Address = (UINT32)Address;
+ }
+ } else if (Trb->Mode == SdMmcAdma64bV3Mode) {
+ if (Remaining <= AdmaMaxDataPerLine) {
+ Trb->Adma64V3Desc[Index].Valid = 1;
+ Trb->Adma64V3Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma64V3Desc[Index].UpperLength = (UINT16)RShiftU64 (Remaining, 16);
+ }
+ Trb->Adma64V3Desc[Index].LowerLength = (UINT16)(Remaining & MAX_UINT16);
+ Trb->Adma64V3Desc[Index].LowerAddress = (UINT32)Address;
+ Trb->Adma64V3Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);
+ break;
+ } else {
+ Trb->Adma64V3Desc[Index].Valid = 1;
+ Trb->Adma64V3Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma64V3Desc[Index].UpperLength = 0;
+ }
+ Trb->Adma64V3Desc[Index].LowerLength = 0;
+ Trb->Adma64V3Desc[Index].LowerAddress = (UINT32)Address;
+ Trb->Adma64V3Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);
+ }
+ } else {
+ if (Remaining <= AdmaMaxDataPerLine) {
+ Trb->Adma64V4Desc[Index].Valid = 1;
+ Trb->Adma64V4Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma64V4Desc[Index].UpperLength = (UINT16)RShiftU64 (Remaining, 16);
+ }
+ Trb->Adma64V4Desc[Index].LowerLength = (UINT16)(Remaining & MAX_UINT16);
+ Trb->Adma64V4Desc[Index].LowerAddress = (UINT32)Address;
+ Trb->Adma64V4Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);
+ break;
+ } else {
+ Trb->Adma64V4Desc[Index].Valid = 1;
+ Trb->Adma64V4Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma64V4Desc[Index].UpperLength = 0;
+ }
+ Trb->Adma64V4Desc[Index].LowerLength = 0;
+ Trb->Adma64V4Desc[Index].LowerAddress = (UINT32)Address;
+ Trb->Adma64V4Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);
+ }
+ }
+
+ Remaining -= AdmaMaxDataPerLine;
+ Address += AdmaMaxDataPerLine;
+ }
+
+ //
+ // Set the last descriptor line as end of descriptor table
+ //
+ if (Trb->Mode == SdMmcAdma32bMode) {
+ Trb->Adma32Desc[Index].End = 1;
+ } else if (Trb->Mode == SdMmcAdma64bV3Mode) {
+ Trb->Adma64V3Desc[Index].End = 1;
+ } else {
+ Trb->Adma64V4Desc[Index].End = 1;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Prints the contents of the command packet to the debug port.
+
+ @param[in] DebugLevel Debug level at which the packet should be printed.
+ @param[in] Packet Pointer to packet to print.
+**/
+VOID
+SdMmcPrintPacket (
+ IN UINT32 DebugLevel,
+ IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet
+ )
+{
+ if (Packet == NULL) {
+ return;
+ }
+
+ DEBUG ((DebugLevel, "Printing EFI_SD_MMC_PASS_THRU_COMMAND_PACKET\n"));
+ if (Packet->SdMmcCmdBlk != NULL) {
+ DEBUG ((DebugLevel, "Command index: %d, argument: %X\n", Packet->SdMmcCmdBlk->CommandIndex, Packet->SdMmcCmdBlk->CommandArgument));
+ DEBUG ((DebugLevel, "Command type: %d, response type: %d\n", Packet->SdMmcCmdBlk->CommandType, Packet->SdMmcCmdBlk->ResponseType));
+ }
+ if (Packet->SdMmcStatusBlk != NULL) {
+ DEBUG ((DebugLevel, "Response 0: %X, 1: %X, 2: %X, 3: %X\n",
+ Packet->SdMmcStatusBlk->Resp0,
+ Packet->SdMmcStatusBlk->Resp1,
+ Packet->SdMmcStatusBlk->Resp2,
+ Packet->SdMmcStatusBlk->Resp3
+ ));
+ }
+ DEBUG ((DebugLevel, "Timeout: %ld\n", Packet->Timeout));
+ DEBUG ((DebugLevel, "InDataBuffer: %p\n", Packet->InDataBuffer));
+ DEBUG ((DebugLevel, "OutDataBuffer: %p\n", Packet->OutDataBuffer));
+ DEBUG ((DebugLevel, "InTransferLength: %d\n", Packet->InTransferLength));
+ DEBUG ((DebugLevel, "OutTransferLength: %d\n", Packet->OutTransferLength));
+ DEBUG ((DebugLevel, "TransactionStatus: %r\n", Packet->TransactionStatus));
+}
+
+/**
+ Prints the contents of the TRB to the debug port.
+
+ @param[in] DebugLevel Debug level at which the TRB should be printed.
+ @param[in] Trb Pointer to the TRB structure.
+**/
+VOID
+SdMmcPrintTrb (
+ IN UINT32 DebugLevel,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ if (Trb == NULL) {
+ return;
+ }
+
+ DEBUG ((DebugLevel, "Printing SD_MMC_HC_TRB\n"));
+ DEBUG ((DebugLevel, "Slot: %d\n", Trb->Slot));
+ DEBUG ((DebugLevel, "BlockSize: %d\n", Trb->BlockSize));
+ DEBUG ((DebugLevel, "Data: %p\n", Trb->Data));
+ DEBUG ((DebugLevel, "DataLen: %d\n", Trb->DataLen));
+ DEBUG ((DebugLevel, "Read: %d\n", Trb->Read));
+ DEBUG ((DebugLevel, "DataPhy: %lX\n", Trb->DataPhy));
+ DEBUG ((DebugLevel, "DataMap: %p\n", Trb->DataMap));
+ DEBUG ((DebugLevel, "Mode: %d\n", Trb->Mode));
+ DEBUG ((DebugLevel, "AdmaLengthMode: %d\n", Trb->AdmaLengthMode));
+ DEBUG ((DebugLevel, "Event: %p\n", Trb->Event));
+ DEBUG ((DebugLevel, "Started: %d\n", Trb->Started));
+ DEBUG ((DebugLevel, "CommandComplete: %d\n", Trb->CommandComplete));
+ DEBUG ((DebugLevel, "Timeout: %ld\n", Trb->Timeout));
+ DEBUG ((DebugLevel, "Retries: %d\n", Trb->Retries));
+ DEBUG ((DebugLevel, "PioModeTransferCompleted: %d\n", Trb->PioModeTransferCompleted));
+ DEBUG ((DebugLevel, "PioBlockIndex: %d\n", Trb->PioBlockIndex));
+ DEBUG ((DebugLevel, "Adma32Desc: %p\n", Trb->Adma32Desc));
+ DEBUG ((DebugLevel, "Adma64V3Desc: %p\n", Trb->Adma64V3Desc));
+ DEBUG ((DebugLevel, "Adma64V4Desc: %p\n", Trb->Adma64V4Desc));
+ DEBUG ((DebugLevel, "AdmaMap: %p\n", Trb->AdmaMap));
+ DEBUG ((DebugLevel, "AdmaPages: %X\n", Trb->AdmaPages));
+
+ SdMmcPrintPacket (DebugLevel, Trb->Packet);
+}
+
+/**
+ Sets up host memory to allow DMA transfer.
+
+ @param[in] Private A pointer to the SD_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.
+
+ @retval EFI_SUCCESS Memory has been mapped for DMA transfer.
+ @retval Others Memory has not been mapped.
+**/
+EFI_STATUS
+SdMmcSetupMemoryForDmaTransfer (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_PCI_IO_PROTOCOL_OPERATION Flag;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN MapLength;
+ EFI_STATUS Status;
+
+ if (Trb->Read) {
+ Flag = EfiPciIoOperationBusMasterWrite;
+ } else {
+ Flag = EfiPciIoOperationBusMasterRead;
+ }
+
+ PciIo = Private->PciIo;
+ if (Trb->Data != NULL && Trb->DataLen != 0) {
+ MapLength = Trb->DataLen;
+ Status = PciIo->Map (
+ PciIo,
+ Flag,
+ Trb->Data,
+ &MapLength,
+ &Trb->DataPhy,
+ &Trb->DataMap
+ );
+ if (EFI_ERROR (Status) || (Trb->DataLen != MapLength)) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+ }
+
+ if (Trb->Mode == SdMmcAdma32bMode ||
+ Trb->Mode == SdMmcAdma64bV3Mode ||
+ Trb->Mode == SdMmcAdma64bV4Mode) {
+ Status = BuildAdmaDescTable (Trb, Private->ControllerVersion[Slot]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a new TRB for the SD/MMC cmd request.
+
+ @param[in] Private A pointer to the SD_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.
+
+**/
+SD_MMC_HC_TRB *
+SdMmcCreateTrb (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
+ IN EFI_EVENT Event
+ )
+{
+ SD_MMC_HC_TRB *Trb;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ Trb = AllocateZeroPool (sizeof (SD_MMC_HC_TRB));
+ if (Trb == NULL) {
+ return NULL;
+ }
+
+ Trb->Signature = SD_MMC_HC_TRB_SIG;
+ Trb->Slot = Slot;
+ Trb->BlockSize = 0x200;
+ Trb->Packet = Packet;
+ Trb->Event = Event;
+ Trb->Started = FALSE;
+ Trb->CommandComplete = FALSE;
+ Trb->Timeout = Packet->Timeout;
+ Trb->Retries = SD_MMC_TRB_RETRIES;
+ Trb->PioModeTransferCompleted = FALSE;
+ Trb->PioBlockIndex = 0;
+ Trb->Private = Private;
+
+ if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {
+ Trb->Data = Packet->InDataBuffer;
+ Trb->DataLen = Packet->InTransferLength;
+ Trb->Read = TRUE;
+ } else if ((Packet->OutTransferLength != 0) && (Packet->OutDataBuffer != NULL)) {
+ Trb->Data = Packet->OutDataBuffer;
+ Trb->DataLen = Packet->OutTransferLength;
+ Trb->Read = FALSE;
+ } else if ((Packet->InTransferLength == 0) && (Packet->OutTransferLength == 0)) {
+ Trb->Data = NULL;
+ Trb->DataLen = 0;
+ } else {
+ goto Error;
+ }
+
+ if ((Trb->DataLen != 0) && (Trb->DataLen < Trb->BlockSize)) {
+ Trb->BlockSize = (UINT16)Trb->DataLen;
+ }
+
+ 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->DataLen == 0) {
+ Trb->Mode = SdMmcNoData;
+ } else if (Private->Capability[Slot].Adma2 != 0) {
+ Trb->Mode = SdMmcAdma32bMode;
+ Trb->AdmaLengthMode = SdMmcAdmaLen16b;
+ if ((Private->ControllerVersion[Slot] == SD_MMC_HC_CTRL_VER_300) &&
+ (Private->Capability[Slot].SysBus64V3 == 1)) {
+ Trb->Mode = SdMmcAdma64bV3Mode;
+ } else if (((Private->ControllerVersion[Slot] == SD_MMC_HC_CTRL_VER_400) &&
+ (Private->Capability[Slot].SysBus64V3 == 1)) ||
+ ((Private->ControllerVersion[Slot] >= SD_MMC_HC_CTRL_VER_410) &&
+ (Private->Capability[Slot].SysBus64V4 == 1))) {
+ Trb->Mode = SdMmcAdma64bV4Mode;
+ }
+ if (Private->ControllerVersion[Slot] >= SD_MMC_HC_CTRL_VER_410) {
+ Trb->AdmaLengthMode = SdMmcAdmaLen26b;
+ }
+ Status = SdMmcSetupMemoryForDmaTransfer (Private, Slot, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else if (Private->Capability[Slot].Sdma != 0) {
+ Trb->Mode = SdMmcSdmaMode;
+ Status = SdMmcSetupMemoryForDmaTransfer (Private, Slot, Trb);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ Trb->Mode = SdMmcPioMode;
+ }
+ }
+
+ if (Event != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Private->Queue, &Trb->TrbList);
+ gBS->RestoreTPL (OldTpl);
+ }
+
+ return Trb;
+
+Error:
+ SdMmcFreeTrb (Trb);
+ return NULL;
+}
+
+/**
+ Free the resource used by the TRB.
+
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+**/
+VOID
+SdMmcFreeTrb (
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ PciIo = Trb->Private->PciIo;
+
+ if (Trb->AdmaMap != NULL) {
+ PciIo->Unmap (
+ PciIo,
+ Trb->AdmaMap
+ );
+ }
+ if (Trb->Adma32Desc != NULL) {
+ PciIo->FreeBuffer (
+ PciIo,
+ Trb->AdmaPages,
+ Trb->Adma32Desc
+ );
+ }
+ if (Trb->Adma64V3Desc != NULL) {
+ PciIo->FreeBuffer (
+ PciIo,
+ Trb->AdmaPages,
+ Trb->Adma64V3Desc
+ );
+ }
+ if (Trb->Adma64V4Desc != NULL) {
+ PciIo->FreeBuffer (
+ PciIo,
+ Trb->AdmaPages,
+ Trb->Adma64V4Desc
+ );
+ }
+ if (Trb->DataMap != NULL) {
+ PciIo->Unmap (
+ PciIo,
+ Trb->DataMap
+ );
+ }
+ FreePool (Trb);
+ return;
+}
+
+/**
+ Check if the env is ready for execute specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_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
+SdMmcCheckTrbEnv (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 PresentState;
+
+ Packet = Trb->Packet;
+
+ if ((Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc) ||
+ (Packet->SdMmcCmdBlk->ResponseType == SdMmcResponseTypeR1b) ||
+ (Packet->SdMmcCmdBlk->ResponseType == SdMmcResponseTypeR5b)) {
+ //
+ // Wait Command Inhibit (CMD) and Command Inhibit (DAT) in
+ // the Present State register to be 0
+ //
+ PresentState = BIT0 | BIT1;
+ } else {
+ //
+ // Wait Command Inhibit (CMD) in the Present State register
+ // to be 0
+ //
+ PresentState = BIT0;
+ }
+
+ PciIo = Private->PciIo;
+ Status = SdMmcHcCheckMmioSet (
+ PciIo,
+ Trb->Slot,
+ SD_MMC_HC_PRESENT_STATE,
+ sizeof (PresentState),
+ PresentState,
+ 0
+ );
+
+ return Status;
+}
+
+/**
+ Wait for the env to be ready for execute specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_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
+SdMmcWaitTrbEnv (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_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 = SdMmcCheckTrbEnv (Private, Trb);
+ if (Status != EFI_NOT_READY) {
+ return Status;
+ }
+ //
+ // Stall for 1 microsecond.
+ //
+ gBS->Stall (1);
+
+ Timeout--;
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Execute the specified TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_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
+SdMmcExecTrb (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT16 Cmd;
+ UINT16 IntStatus;
+ UINT32 Argument;
+ UINT32 BlkCount;
+ UINT16 BlkSize;
+ UINT16 TransMode;
+ UINT8 HostCtrl1;
+ UINT64 SdmaAddr;
+ UINT64 AdmaAddr;
+ BOOLEAN AddressingMode64;
+
+ AddressingMode64 = FALSE;
+
+ Packet = Trb->Packet;
+ PciIo = Trb->Private->PciIo;
+ //
+ // Clear all bits in Error Interrupt Status Register
+ //
+ IntStatus = 0xFFFF;
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ERR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Clear all bits in Normal Interrupt Status Register excepts for Card Removal & Card Insertion bits.
+ //
+ IntStatus = 0xFF3F;
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_400) {
+ Status = SdMmcHcCheckMmioSet(PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL2, sizeof(UINT16),
+ SD_MMC_HC_64_ADDR_EN, SD_MMC_HC_64_ADDR_EN);
+ if (!EFI_ERROR (Status)) {
+ AddressingMode64 = TRUE;
+ }
+ }
+
+ //
+ // Set Host Control 1 register DMA Select field
+ //
+ if ((Trb->Mode == SdMmcAdma32bMode) ||
+ (Trb->Mode == SdMmcAdma64bV4Mode)) {
+ HostCtrl1 = BIT4;
+ Status = SdMmcHcOrMmio (PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else if (Trb->Mode == SdMmcAdma64bV3Mode) {
+ HostCtrl1 = BIT4|BIT3;
+ Status = SdMmcHcOrMmio (PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ SdMmcHcLedOnOff (PciIo, Trb->Slot, TRUE);
+
+ if (Trb->Mode == SdMmcSdmaMode) {
+ if ((!AddressingMode64) &&
+ ((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SdmaAddr = (UINT64)(UINTN)Trb->DataPhy;
+
+ if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_400) {
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (UINT64), &SdmaAddr);
+ } else {
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_SDMA_ADDR, FALSE, sizeof (UINT32), &SdmaAddr);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else if ((Trb->Mode == SdMmcAdma32bMode) ||
+ (Trb->Mode == SdMmcAdma64bV3Mode) ||
+ (Trb->Mode == SdMmcAdma64bV4Mode)) {
+ AdmaAddr = (UINT64)(UINTN)Trb->AdmaDescPhy;
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ BlkSize = Trb->BlockSize;
+ if (Trb->Mode == SdMmcSdmaMode) {
+ //
+ // Set SDMA boundary to be 512K bytes.
+ //
+ BlkSize |= 0x7000;
+ }
+
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_BLK_SIZE, FALSE, sizeof (BlkSize), &BlkSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BlkCount = 0;
+ if (Trb->Mode != SdMmcNoData) {
+ //
+ // Calcuate Block Count.
+ //
+ BlkCount = (Trb->DataLen / Trb->BlockSize);
+ }
+ if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_410) {
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_SDMA_ADDR, FALSE, sizeof (UINT32), &BlkCount);
+ } else {
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_BLK_COUNT, FALSE, sizeof (UINT16), &BlkCount);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Argument = Packet->SdMmcCmdBlk->CommandArgument;
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ARG1, FALSE, sizeof (Argument), &Argument);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ TransMode = 0;
+ if (Trb->Mode != SdMmcNoData) {
+ if (Trb->Mode != SdMmcPioMode) {
+ TransMode |= BIT0;
+ }
+ if (Trb->Read) {
+ TransMode |= BIT4;
+ }
+ if (BlkCount > 1) {
+ TransMode |= BIT5 | BIT1;
+ }
+ //
+ // Only SD memory card needs to use AUTO CMD12 feature.
+ //
+ if (Private->Slot[Trb->Slot].CardType == SdCardType) {
+ if (BlkCount > 1) {
+ TransMode |= BIT2;
+ }
+ }
+ }
+
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_TRANS_MOD, FALSE, sizeof (TransMode), &TransMode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Cmd = (UINT16)LShiftU64(Packet->SdMmcCmdBlk->CommandIndex, 8);
+ if (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc) {
+ Cmd |= BIT5;
+ }
+ //
+ // Convert ResponseType to value
+ //
+ if (Packet->SdMmcCmdBlk->CommandType != SdMmcCommandTypeBc) {
+ switch (Packet->SdMmcCmdBlk->ResponseType) {
+ case SdMmcResponseTypeR1:
+ case SdMmcResponseTypeR5:
+ case SdMmcResponseTypeR6:
+ case SdMmcResponseTypeR7:
+ Cmd |= (BIT1 | BIT3 | BIT4);
+ break;
+ case SdMmcResponseTypeR2:
+ Cmd |= (BIT0 | BIT3);
+ break;
+ case SdMmcResponseTypeR3:
+ case SdMmcResponseTypeR4:
+ Cmd |= BIT1;
+ break;
+ case SdMmcResponseTypeR1b:
+ case SdMmcResponseTypeR5b:
+ Cmd |= (BIT0 | BIT1 | BIT3 | BIT4);
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+ //
+ // Execute cmd
+ //
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd);
+ return Status;
+}
+
+/**
+ Performs SW reset based on passed error status mask.
+
+ @param[in] Private Pointer to driver private data.
+ @param[in] Slot Index of the slot to reset.
+ @param[in] ErrIntStatus Error interrupt status mask.
+
+ @retval EFI_SUCCESS Software reset performed successfully.
+ @retval Other Software reset failed.
+**/
+EFI_STATUS
+SdMmcSoftwareReset (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN UINT16 ErrIntStatus
+ )
+{
+ UINT8 SwReset;
+ EFI_STATUS Status;
+
+ SwReset = 0;
+ if ((ErrIntStatus & 0x0F) != 0) {
+ SwReset |= BIT1;
+ }
+ if ((ErrIntStatus & 0x70) != 0) {
+ SwReset |= BIT2;
+ }
+
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Slot,
+ SD_MMC_HC_SW_RST,
+ FALSE,
+ sizeof (SwReset),
+ &SwReset
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcHcWaitMmioSet (
+ Private->PciIo,
+ Slot,
+ SD_MMC_HC_SW_RST,
+ sizeof (SwReset),
+ 0xFF,
+ 0,
+ SD_MMC_HC_GENERIC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Checks the error status in error status register
+ and issues appropriate software reset as described in
+ SD specification section 3.10.
+
+ @param[in] Private Pointer to driver private data.
+ @param[in] Slot Index of the slot for device.
+ @param[in] IntStatus Normal interrupt status mask.
+
+ @retval EFI_CRC_ERROR CRC error happened during CMD execution.
+ @retval EFI_SUCCESS No error reported.
+ @retval Others Some other error happened.
+
+**/
+EFI_STATUS
+SdMmcCheckAndRecoverErrors (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN UINT16 IntStatus
+ )
+{
+ UINT16 ErrIntStatus;
+ EFI_STATUS Status;
+ EFI_STATUS ErrorStatus;
+
+ if ((IntStatus & BIT15) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Slot,
+ SD_MMC_HC_ERR_INT_STS,
+ TRUE,
+ sizeof (ErrIntStatus),
+ &ErrIntStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((DEBUG_ERROR, "Error reported by SDHCI\n"));
+ DEBUG ((DEBUG_ERROR, "Interrupt status = %X\n", IntStatus));
+ DEBUG ((DEBUG_ERROR, "Error interrupt status = %X\n", ErrIntStatus));
+
+ //
+ // If the data timeout error is reported
+ // but data transfer is signaled as completed we
+ // have to ignore data timeout. We also assume that no
+ // other error is present on the link since data transfer
+ // completed successfully. Error interrupt status
+ // register is going to be reset when the next command
+ // is started.
+ //
+ if (((ErrIntStatus & BIT4) != 0) && ((IntStatus & BIT1) != 0)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // We treat both CMD and DAT CRC errors and
+ // end bits errors as EFI_CRC_ERROR. This will
+ // let higher layer know that the error possibly
+ // happened due to random bus condition and the
+ // command can be retried.
+ //
+ if ((ErrIntStatus & (BIT1 | BIT2 | BIT5 | BIT6)) != 0) {
+ ErrorStatus = EFI_CRC_ERROR;
+ } else {
+ ErrorStatus = EFI_DEVICE_ERROR;
+ }
+
+ Status = SdMmcSoftwareReset (Private, Slot, ErrIntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return ErrorStatus;
+}
+
+/**
+ Reads the response data into the TRB buffer.
+ This function assumes that caller made sure that
+ command has completed.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS Response read successfully.
+ @retval Others Failed to get response.
+**/
+EFI_STATUS
+SdMmcGetResponse (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ UINT8 Index;
+ UINT32 Response[4];
+ EFI_STATUS Status;
+
+ Packet = Trb->Packet;
+
+ if (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeBc) {
+ return EFI_SUCCESS;
+ }
+
+ for (Index = 0; Index < 4; Index++) {
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_RESPONSE + Index * 4,
+ TRUE,
+ sizeof (UINT32),
+ &Response[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ CopyMem (Packet->SdMmcStatusBlk, Response, sizeof (Response));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Checks if the command completed. If the command
+ completed it gets the response and records the
+ command completion in the TRB.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+ @param[in] IntStatus Snapshot of the normal interrupt status register.
+
+ @retval EFI_SUCCESS Command completed successfully.
+ @retval EFI_NOT_READY Command completion still pending.
+ @retval Others Command failed to complete.
+**/
+EFI_STATUS
+SdMmcCheckCommandComplete (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb,
+ IN UINT16 IntStatus
+ )
+{
+ UINT16 Data16;
+ EFI_STATUS Status;
+
+ if ((IntStatus & BIT0) != 0) {
+ Data16 = BIT0;
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_NOR_INT_STS,
+ FALSE,
+ sizeof (Data16),
+ &Data16
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = SdMmcGetResponse (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Trb->CommandComplete = TRUE;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_READY;
+}
+
+/**
+ Transfers data from card using PIO method.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+ @param[in] IntStatus Snapshot of the normal interrupt status register.
+
+ @retval EFI_SUCCESS PIO transfer completed successfully.
+ @retval EFI_NOT_READY PIO transfer completion still pending.
+ @retval Others PIO transfer failed to complete.
+**/
+EFI_STATUS
+SdMmcTransferDataWithPio (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb,
+ IN UINT16 IntStatus
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Data16;
+ UINT32 BlockCount;
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;
+ UINTN Count;
+
+ BlockCount = (Trb->DataLen / Trb->BlockSize);
+ if (Trb->DataLen % Trb->BlockSize != 0) {
+ BlockCount += 1;
+ }
+
+ if (Trb->PioBlockIndex >= BlockCount) {
+ return EFI_SUCCESS;
+ }
+
+ switch (Trb->BlockSize % sizeof (UINT32)) {
+ case 0:
+ Width = EfiPciIoWidthFifoUint32;
+ Count = Trb->BlockSize / sizeof (UINT32);
+ break;
+ case 2:
+ Width = EfiPciIoWidthFifoUint16;
+ Count = Trb->BlockSize / sizeof (UINT16);
+ break;
+ case 1:
+ case 3:
+ default:
+ Width = EfiPciIoWidthFifoUint8;
+ Count = Trb->BlockSize;
+ break;
+ }
+
+ if (Trb->Read) {
+ if ((IntStatus & BIT5) == 0) {
+ return EFI_NOT_READY;
+ }
+ Data16 = BIT5;
+ SdMmcHcRwMmio (Private->PciIo, Trb->Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (Data16), &Data16);
+
+ Status = Private->PciIo->Mem.Read (
+ Private->PciIo,
+ Width,
+ Trb->Slot,
+ SD_MMC_HC_BUF_DAT_PORT,
+ Count,
+ (VOID*)((UINT8*)Trb->Data + (Trb->BlockSize * Trb->PioBlockIndex))
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Trb->PioBlockIndex++;
+ } else {
+ if ((IntStatus & BIT4) == 0) {
+ return EFI_NOT_READY;
+ }
+ Data16 = BIT4;
+ SdMmcHcRwMmio (Private->PciIo, Trb->Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (Data16), &Data16);
+
+ Status = Private->PciIo->Mem.Write (
+ Private->PciIo,
+ Width,
+ Trb->Slot,
+ SD_MMC_HC_BUF_DAT_PORT,
+ Count,
+ (VOID*)((UINT8*)Trb->Data + (Trb->BlockSize * Trb->PioBlockIndex))
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Trb->PioBlockIndex++;
+ }
+
+ if (Trb->PioBlockIndex >= BlockCount) {
+ Trb->PioModeTransferCompleted = TRUE;
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_READY;
+ }
+}
+
+/**
+ Update the SDMA address on the SDMA buffer boundary interrupt.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS Updated SDMA buffer address.
+ @retval Others Failed to update SDMA buffer address.
+**/
+EFI_STATUS
+SdMmcUpdateSdmaAddress (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ UINT64 SdmaAddr;
+ EFI_STATUS Status;
+
+ SdmaAddr = SD_MMC_SDMA_ROUND_UP ((UINTN)Trb->DataPhy, SD_MMC_SDMA_BOUNDARY);
+
+ if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_400) {
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_ADMA_SYS_ADDR,
+ FALSE,
+ sizeof (UINT64),
+ &SdmaAddr
+ );
+ } else {
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_SDMA_ADDR,
+ FALSE,
+ sizeof (UINT32),
+ &SdmaAddr
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Trb->DataPhy = (UINT64)(UINTN)SdmaAddr;
+ return EFI_SUCCESS;
+}
+
+/**
+ Checks if the data transfer completed and performs any actions
+ neccessary to continue the data transfer such as SDMA system
+ address fixup or PIO data transfer.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+ @param[in] IntStatus Snapshot of the normal interrupt status register.
+
+ @retval EFI_SUCCESS Data transfer completed successfully.
+ @retval EFI_NOT_READY Data transfer completion still pending.
+ @retval Others Data transfer failed to complete.
+**/
+EFI_STATUS
+SdMmcCheckDataTransfer (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb,
+ IN UINT16 IntStatus
+ )
+{
+ UINT16 Data16;
+ EFI_STATUS Status;
+
+ if ((IntStatus & BIT1) != 0) {
+ Data16 = BIT1;
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_NOR_INT_STS,
+ FALSE,
+ sizeof (Data16),
+ &Data16
+ );
+ return Status;
+ }
+
+ if (Trb->Mode == SdMmcPioMode && !Trb->PioModeTransferCompleted) {
+ Status = SdMmcTransferDataWithPio (Private, Trb, IntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if ((Trb->Mode == SdMmcSdmaMode) && ((IntStatus & BIT3) != 0)) {
+ Data16 = BIT3;
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_NOR_INT_STS,
+ FALSE,
+ sizeof (Data16),
+ &Data16
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = SdMmcUpdateSdmaAddress (Private, Trb);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_NOT_READY;
+}
+
+/**
+ Check the TRB execution result.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_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
+SdMmcCheckTrbResult (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_MMC_HC_TRB *Trb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+ UINT16 IntStatus;
+
+ Packet = Trb->Packet;
+ //
+ // Check Trb execution result by reading Normal Interrupt Status register.
+ //
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_NOR_INT_STS,
+ TRUE,
+ sizeof (IntStatus),
+ &IntStatus
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Check if there are any errors reported by host controller
+ // and if neccessary recover the controller before next command is executed.
+ //
+ Status = SdMmcCheckAndRecoverErrors (Private, Trb->Slot, IntStatus);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Tuning commands are the only ones that do not generate command
+ // complete interrupt. Process them here before entering the code
+ // that waits for command completion.
+ //
+ 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))) {
+ Status = SdMmcTransferDataWithPio (Private, Trb, IntStatus);
+ goto Done;
+ }
+
+ if (!Trb->CommandComplete) {
+ Status = SdMmcCheckCommandComplete (Private, Trb, IntStatus);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ if (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc ||
+ Packet->SdMmcCmdBlk->ResponseType == SdMmcResponseTypeR1b ||
+ Packet->SdMmcCmdBlk->ResponseType == SdMmcResponseTypeR5b) {
+ Status = SdMmcCheckDataTransfer (Private, Trb, IntStatus);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+ if (Status != EFI_NOT_READY) {
+ SdMmcHcLedOnOff (Private->PciIo, Trb->Slot, FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "TRB failed with %r\n", Status));
+ SdMmcPrintTrb (DEBUG_ERROR, Trb);
+ } else {
+ DEBUG ((DEBUG_VERBOSE, "TRB success\n"));
+ SdMmcPrintTrb (DEBUG_VERBOSE, Trb);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Wait for the TRB execution result.
+
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+
+ @retval EFI_SUCCESS The TRB is executed successfully.
+ @retval Others Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+SdMmcWaitTrbResult (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN SD_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 = SdMmcCheckTrbResult (Private, Trb);
+ if (Status != EFI_NOT_READY) {
+ return Status;
+ }
+ //
+ // Stall for 1 microsecond.
+ //
+ gBS->Stall (1);
+
+ Timeout--;
+ }
+
+ return EFI_TIMEOUT;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h new file mode 100644 index 000000000..16229a846 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h @@ -0,0 +1,610 @@ +/** @file
+
+ Provides some data structure definitions used by the SD/MMC host controller driver.
+
+Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SD_MMC_PCI_HCI_H_
+#define _SD_MMC_PCI_HCI_H_
+
+//
+// SD Host Controller SlotInfo Register Offset
+//
+#define SD_MMC_HC_SLOT_OFFSET 0x40
+
+#define SD_MMC_HC_MAX_SLOT 6
+
+//
+// SD Host Controller MMIO Register Offset
+//
+#define SD_MMC_HC_SDMA_ADDR 0x00
+#define SD_MMC_HC_ARG2 0x00
+#define SD_MMC_HC_BLK_SIZE 0x04
+#define SD_MMC_HC_BLK_COUNT 0x06
+#define SD_MMC_HC_ARG1 0x08
+#define SD_MMC_HC_TRANS_MOD 0x0C
+#define SD_MMC_HC_COMMAND 0x0E
+#define SD_MMC_HC_RESPONSE 0x10
+#define SD_MMC_HC_BUF_DAT_PORT 0x20
+#define SD_MMC_HC_PRESENT_STATE 0x24
+#define SD_MMC_HC_HOST_CTRL1 0x28
+#define SD_MMC_HC_POWER_CTRL 0x29
+#define SD_MMC_HC_BLK_GAP_CTRL 0x2A
+#define SD_MMC_HC_WAKEUP_CTRL 0x2B
+#define SD_MMC_HC_CLOCK_CTRL 0x2C
+#define SD_MMC_HC_TIMEOUT_CTRL 0x2E
+#define SD_MMC_HC_SW_RST 0x2F
+#define SD_MMC_HC_NOR_INT_STS 0x30
+#define SD_MMC_HC_ERR_INT_STS 0x32
+#define SD_MMC_HC_NOR_INT_STS_EN 0x34
+#define SD_MMC_HC_ERR_INT_STS_EN 0x36
+#define SD_MMC_HC_NOR_INT_SIG_EN 0x38
+#define SD_MMC_HC_ERR_INT_SIG_EN 0x3A
+#define SD_MMC_HC_AUTO_CMD_ERR_STS 0x3C
+#define SD_MMC_HC_HOST_CTRL2 0x3E
+#define SD_MMC_HC_CAP 0x40
+#define SD_MMC_HC_MAX_CURRENT_CAP 0x48
+#define SD_MMC_HC_FORCE_EVT_AUTO_CMD 0x50
+#define SD_MMC_HC_FORCE_EVT_ERR_INT 0x52
+#define SD_MMC_HC_ADMA_ERR_STS 0x54
+#define SD_MMC_HC_ADMA_SYS_ADDR 0x58
+#define SD_MMC_HC_PRESET_VAL 0x60
+#define SD_MMC_HC_SHARED_BUS_CTRL 0xE0
+#define SD_MMC_HC_SLOT_INT_STS 0xFC
+#define SD_MMC_HC_CTRL_VER 0xFE
+
+//
+// SD Host Controller bits to HOST_CTRL2 register
+//
+#define SD_MMC_HC_CTRL_UHS_MASK 0x0007
+#define SD_MMC_HC_CTRL_UHS_SDR12 0x0000
+#define SD_MMC_HC_CTRL_UHS_SDR25 0x0001
+#define SD_MMC_HC_CTRL_UHS_SDR50 0x0002
+#define SD_MMC_HC_CTRL_UHS_SDR104 0x0003
+#define SD_MMC_HC_CTRL_UHS_DDR50 0x0004
+#define SD_MMC_HC_CTRL_MMC_LEGACY 0x0000
+#define SD_MMC_HC_CTRL_MMC_HS_SDR 0x0001
+#define SD_MMC_HC_CTRL_MMC_HS_DDR 0x0004
+#define SD_MMC_HC_CTRL_MMC_HS200 0x0003
+#define SD_MMC_HC_CTRL_MMC_HS400 0x0005
+
+#define SD_MMC_HC_CTRL_DRIVER_STRENGTH_MASK 0x0030
+
+//
+// The transfer modes supported by SD Host Controller
+//
+typedef enum {
+ SdMmcNoData,
+ SdMmcPioMode,
+ SdMmcSdmaMode,
+ SdMmcAdma32bMode,
+ SdMmcAdma64bV3Mode,
+ SdMmcAdma64bV4Mode
+} SD_MMC_HC_TRANSFER_MODE;
+
+//
+// The ADMA transfer lengths supported by SD Host Controller
+//
+typedef enum {
+ SdMmcAdmaLen16b,
+ SdMmcAdmaLen26b
+} SD_MMC_HC_ADMA_LENGTH_MODE;
+
+//
+// The maximum data length of each descriptor line
+//
+#define ADMA_MAX_DATA_PER_LINE_16B SIZE_64KB
+#define ADMA_MAX_DATA_PER_LINE_26B SIZE_64MB
+
+//
+// ADMA descriptor for 32b addressing.
+//
+typedef struct {
+ UINT32 Valid:1;
+ UINT32 End:1;
+ UINT32 Int:1;
+ UINT32 Reserved:1;
+ UINT32 Act:2;
+ UINT32 UpperLength:10;
+ UINT32 LowerLength:16;
+ UINT32 Address;
+} SD_MMC_HC_ADMA_32_DESC_LINE;
+
+//
+// ADMA descriptor for 64b addressing.
+//
+typedef struct {
+ UINT32 Valid:1;
+ UINT32 End:1;
+ UINT32 Int:1;
+ UINT32 Reserved:1;
+ UINT32 Act:2;
+ UINT32 UpperLength:10;
+ UINT32 LowerLength:16;
+ UINT32 LowerAddress;
+ UINT32 UpperAddress;
+} SD_MMC_HC_ADMA_64_V3_DESC_LINE;
+
+typedef struct {
+ UINT32 Valid:1;
+ UINT32 End:1;
+ UINT32 Int:1;
+ UINT32 Reserved:1;
+ UINT32 Act:2;
+ UINT32 UpperLength:10;
+ UINT32 LowerLength:16;
+ UINT32 LowerAddress;
+ UINT32 UpperAddress;
+ UINT32 Reserved1;
+} SD_MMC_HC_ADMA_64_V4_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
+} SD_MMC_HC_SLOT_INFO;
+
+typedef struct {
+ UINT32 TimeoutFreq:6; // bit 0:5
+ UINT32 Reserved:1; // bit 6
+ UINT32 TimeoutUnit:1; // bit 7
+ UINT32 BaseClkFreq:8; // bit 8:15
+ UINT32 MaxBlkLen:2; // bit 16:17
+ UINT32 BusWidth8:1; // bit 18
+ UINT32 Adma2:1; // bit 19
+ UINT32 Reserved2:1; // bit 20
+ UINT32 HighSpeed:1; // bit 21
+ UINT32 Sdma:1; // bit 22
+ UINT32 SuspRes:1; // bit 23
+ UINT32 Voltage33:1; // bit 24
+ UINT32 Voltage30:1; // bit 25
+ UINT32 Voltage18:1; // bit 26
+ UINT32 SysBus64V4:1; // bit 27
+ UINT32 SysBus64V3:1; // bit 28
+ UINT32 AsyncInt:1; // bit 29
+ UINT32 SlotType:2; // bit 30:31
+ UINT32 Sdr50:1; // bit 32
+ UINT32 Sdr104:1; // bit 33
+ UINT32 Ddr50:1; // bit 34
+ UINT32 Reserved3:1; // bit 35
+ UINT32 DriverTypeA:1; // bit 36
+ UINT32 DriverTypeC:1; // bit 37
+ UINT32 DriverTypeD:1; // bit 38
+ UINT32 DriverType4:1; // bit 39
+ UINT32 TimerCount:4; // bit 40:43
+ UINT32 Reserved4:1; // bit 44
+ UINT32 TuningSDR50:1; // bit 45
+ UINT32 RetuningMod:2; // bit 46:47
+ UINT32 ClkMultiplier:8; // bit 48:55
+ UINT32 Reserved5:7; // bit 56:62
+ UINT32 Hs400:1; // bit 63
+} SD_MMC_HC_SLOT_CAP;
+
+//
+// SD Host controller version
+//
+#define SD_MMC_HC_CTRL_VER_100 0x00
+#define SD_MMC_HC_CTRL_VER_200 0x01
+#define SD_MMC_HC_CTRL_VER_300 0x02
+#define SD_MMC_HC_CTRL_VER_400 0x03
+#define SD_MMC_HC_CTRL_VER_410 0x04
+#define SD_MMC_HC_CTRL_VER_420 0x05
+
+//
+// SD Host controller V4 enhancements
+//
+#define SD_MMC_HC_V4_EN BIT12
+#define SD_MMC_HC_64_ADDR_EN BIT13
+#define SD_MMC_HC_26_DATA_LEN_ADMA_EN BIT10
+
+/**
+ 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 SD_MMC_HC_SLOT_CAP *Capability
+ );
+
+/**
+ 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
+SdMmcHcGetSlotInfo (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ OUT UINT8 *FirstBar,
+ OUT UINT8 *SlotNum
+ );
+
+/**
+ 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
+SdMmcHcRwMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN BOOLEAN Read,
+ IN UINT8 Count,
+ IN OUT VOID *Data
+ );
+
+/**
+ 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
+SdMmcHcOrMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN VOID *OrData
+ );
+
+/**
+ 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
+SdMmcHcAndMmio (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN VOID *AndData
+ );
+
+/**
+ 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
+SdMmcHcWaitMmioSet (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 BarIndex,
+ IN UINT32 Offset,
+ IN UINT8 Count,
+ IN UINT64 MaskValue,
+ IN UINT64 TestValue,
+ IN UINT64 Timeout
+ );
+
+/**
+ Get the controller version information 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] Version The buffer to store the version information.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdMmcHcGetControllerVersion (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT UINT16 *Version
+ );
+
+/**
+ 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
+SdMmcHcEnableInterrupt (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ );
+
+/**
+ 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
+SdMmcHcGetCapability (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT SD_MMC_HC_SLOT_CAP *Capability
+ );
+
+/**
+ 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
+SdMmcHcGetMaxCurrent (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT UINT64 *MaxCurrent
+ );
+
+/**
+ 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
+SdMmcHcCardDetect (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT BOOLEAN *MediaPresent
+ );
+
+/**
+ 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
+SdMmcHcStopClock (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ );
+
+/**
+ Start the SD clock.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number.
+
+ @retval EFI_SUCCESS Succeeded to start the SD clock.
+ @retval Others Failed to start the SD clock.
+**/
+EFI_STATUS
+SdMmcHcStartSdClock (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ );
+
+/**
+ 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
+SdMmcHcPowerControl (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN UINT8 PowerCtrl
+ );
+
+/**
+ 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
+SdMmcHcSetBusWidth (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN UINT16 BusWidth
+ );
+
+/**
+ 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
+SdMmcHcInitPowerVoltage (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN SD_MMC_HC_SLOT_CAP Capability
+ );
+
+/**
+ 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
+SdMmcHcInitTimeoutCtrl (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ );
+
+/**
+ Set SD Host Controller control 2 registry according to selected speed.
+
+ @param[in] ControllerHandle The handle of the controller.
+ @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] Timing The timing to select.
+
+ @retval EFI_SUCCESS The timing is set successfully.
+ @retval Others The timing isn't set successfully.
+**/
+EFI_STATUS
+SdMmcHcUhsSignaling (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN SD_MMC_BUS_MODE Timing
+ );
+
+/**
+ Set driver strength in host controller.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] SlotIndex The slot index of the card.
+ @param[in] DriverStrength DriverStrength to set in the controller.
+
+ @retval EFI_SUCCESS Driver strength programmed successfully.
+ @retval Others Failed to set driver strength.
+**/
+EFI_STATUS
+SdMmcSetDriverStrength (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 SlotIndex,
+ IN SD_DRIVER_STRENGTH_TYPE DriverStrength
+ );
+
+#endif
|