--- /dev/null
+/** @file\r
+ UEFI Component Name(2) protocol implementation for SD/MMC host controller driver.\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdMmcPciHcDxe.h"\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSdMmcPciHcComponentName = {\r
+ SdMmcPciHcComponentNameGetDriverName,\r
+ SdMmcPciHcComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSdMmcPciHcComponentName2 = {\r
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SdMmcPciHcComponentNameGetDriverName,\r
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SdMmcPciHcComponentNameGetControllerName,\r
+ "en"\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdMmcPciHcDriverNameTable[] = {\r
+ { "eng;en", L"Edkii Sd/Mmc Host Controller Driver" },\r
+ { NULL , NULL }\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdMmcPciHcControllerNameTable[] = {\r
+ { "eng;en", L"Edkii Sd/Mmc Host Controller" },\r
+ { NULL , NULL }\r
+};\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+{\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ mSdMmcPciHcDriverNameTable,\r
+ DriverName,\r
+ (BOOLEAN)(This == &gSdMmcPciHcComponentName)\r
+ );\r
+}\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle, OPTIONAL\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (Language == NULL || ControllerName == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // This is a device driver, so ChildHandle must be NULL.\r
+ //\r
+ if (ChildHandle != NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Make sure this driver is currently managing ControllerHandle\r
+ //\r
+ Status = EfiTestManagedDevice (\r
+ ControllerHandle,\r
+ gSdMmcPciHcDriverBinding.DriverBindingHandle,\r
+ &gEfiPciIoProtocolGuid\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ mSdMmcPciHcControllerNameTable,\r
+ ControllerName,\r
+ (BOOLEAN)(This == &gSdMmcPciHcComponentName)\r
+ );\r
+}\r
--- /dev/null
+/** @file\r
+ This file provides some helper functions which are specific for EMMC device.\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdMmcPciHcDxe.h"\r
+\r
+/**\r
+ Send command GO_IDLE_STATE (CMD0 with argument of 0x00000000) to the device to\r
+ make it go to Idle State.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The EMMC device is reset correctly.\r
+ @retval Others The device reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcReset (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc;\r
+ SdMmcCmdBlk.ResponseType = 0;\r
+ SdMmcCmdBlk.CommandArgument = 0;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_OP_COND to the EMMC device to get the data of the OCR register.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in, out] Argument On input, the argument of SEND_OP_COND is to send to the device.\r
+ On output, the argument is the value of OCR register.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetOcr (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN OUT UINT32 *Argument\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;\r
+ SdMmcCmdBlk.CommandArgument = *Argument;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+ //\r
+ *Argument = SdMmcStatusBlk.Resp0;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Broadcast command ALL_SEND_CID to the bus to ask all the EMMC devices to send the\r
+ data of their CID registers.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetAllCid (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+ SdMmcCmdBlk.CommandArgument = 0;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SET_RELATIVE_ADDR to the EMMC device to assign a Relative device\r
+ Address (RCA).\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSetRca (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_CSD to the EMMC device to get the data of the CSD register.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address of selected device.\r
+ @param[out] Csd The buffer to store the content of the CSD register.\r
+ Note the caller should ignore the lowest byte of this\r
+ buffer as the content of this byte is meaningless even\r
+ if the operation succeeds.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetCsd (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca,\r
+ OUT EMMC_CSD *Csd\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+ //\r
+ CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SELECT_DESELECT_CARD to the EMMC device to select/deselect it.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address of selected device.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSelect (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_EXT_CSD to the EMMC device to get the data of the EXT_CSD register.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[out] ExtCsd The buffer to store the content of the EXT_CSD register.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetExtCsd (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ OUT EMMC_EXT_CSD *ExtCsd\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ SdMmcCmdBlk.CommandArgument = 0x00000000;\r
+\r
+ Packet.InDataBuffer = ExtCsd;\r
+ Packet.InTransferLength = sizeof (EMMC_EXT_CSD);\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SWITCH to the EMMC device to switch the mode of operation of the\r
+ selected Device or modifies the EXT_CSD registers.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Access The access mode of SWTICH command.\r
+ @param[in] Index The offset of the field to be access.\r
+ @param[in] Value The value to be set to the specified field of EXT_CSD register.\r
+ @param[in] CmdSet The value of CmdSet field of EXT_CSD register.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSwitch (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT8 Access,\r
+ IN UINT8 Index,\r
+ IN UINT8 Value,\r
+ IN UINT8 CmdSet\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = EMMC_SWITCH;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
+ SdMmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | (Value << 8) | CmdSet;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_STATUS to the addressed EMMC device to get its status register.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address of addressed device.\r
+ @param[out] DevStatus The returned device status.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSendStatus (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca,\r
+ OUT UINT32 *DevStatus\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ *DevStatus = SdMmcStatusBlk.Resp0;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_TUNING_BLOCK to the EMMC device for HS200 optimal sampling point\r
+ detection.\r
+\r
+ It may be sent up to 40 times until the host finishes the tuning procedure.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] BusWidth The bus width to work.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSendTuningBlk (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT8 BusWidth\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+ UINT8 TuningBlock[128];\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ SdMmcCmdBlk.CommandArgument = 0;\r
+\r
+ Packet.InDataBuffer = TuningBlock;\r
+ if (BusWidth == 8) {\r
+ Packet.InTransferLength = sizeof (TuningBlock);\r
+ } else {\r
+ Packet.InTransferLength = 64;\r
+ }\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Tunning the clock to get HS200 optimal sampling point.\r
+\r
+ Command SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the\r
+ tuning procedure.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+ Simplified Spec 3.0 Figure 2-29 for details.\r
+\r
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] BusWidth The bus width to work.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcTuningClkForHs200 (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT8 BusWidth\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 HostCtrl2;\r
+ UINT8 Retry;\r
+\r
+ //\r
+ // Notify the host that the sampling clock tuning procedure starts.\r
+ //\r
+ HostCtrl2 = BIT6;\r
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.\r
+ //\r
+ Retry = 0;\r
+ do {\r
+ Status = EmmcSendTuningBlk (PassThru, Slot, BusWidth);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcTuningClkForHs200: Send tuning block fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
+ break;\r
+ }\r
+ } while (++Retry < 40);\r
+\r
+ if (Retry == 40) {\r
+ Status = EFI_TIMEOUT;\r
+ DEBUG ((EFI_D_ERROR, "EmmcTuningClkForHs200: Send tuning block exceeds 40 times\n"));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Switch the bus width to specified width.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9 and SD Host Controller\r
+ Simplified Spec 3.0 Figure 3-7 for details.\r
+\r
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+ @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise\r
+ use single data rate data simpling method.\r
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSwitchBusWidth (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca,\r
+ IN BOOLEAN IsDdr,\r
+ IN UINT8 BusWidth\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Access;\r
+ UINT8 Index;\r
+ UINT8 Value;\r
+ UINT8 CmdSet;\r
+ UINT32 DevStatus;\r
+\r
+ //\r
+ // Write Byte, the Value field is written into the byte pointed by Index.\r
+ //\r
+ Access = 0x03;\r
+ Index = OFFSET_OF (EMMC_EXT_CSD, BusWidth);\r
+ if (BusWidth == 4) {\r
+ Value = 1;\r
+ } else if (BusWidth == 8) {\r
+ Value = 2;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (IsDdr) {\r
+ Value += 4;\r
+ }\r
+\r
+ CmdSet = 0;\r
+ Status = EmmcSwitch (PassThru, Slot, Access, Index, Value, CmdSet);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcSwitchBusWidth: Switch to bus width %d fails with %r\n", BusWidth, Status));\r
+ return Status;\r
+ }\r
+\r
+ Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcSwitchBusWidth: Send status fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Check the switch operation is really successful or not.\r
+ //\r
+ if ((DevStatus & BIT7) != 0) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcSwitchBusWidth: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Switch the clock frequency to the specified value.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6 and SD Host Controller\r
+ Simplified Spec 3.0 Figure 3-3 for details.\r
+\r
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+ @param[in] HsTiming The value to be written to HS_TIMING field of EXT_CSD register.\r
+ @param[in] ClockFreq The max clock frequency to be set, the unit is MHz.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSwitchClockFreq (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca,\r
+ IN UINT8 HsTiming,\r
+ IN UINT32 ClockFreq\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Access;\r
+ UINT8 Index;\r
+ UINT8 Value;\r
+ UINT8 CmdSet;\r
+ UINT32 DevStatus;\r
+ SD_MMC_HC_PRIVATE_DATA *Private;\r
+\r
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
+ //\r
+ // Write Byte, the Value field is written into the byte pointed by Index.\r
+ //\r
+ Access = 0x03;\r
+ Index = OFFSET_OF (EMMC_EXT_CSD, HsTiming);\r
+ Value = HsTiming;\r
+ CmdSet = 0;\r
+\r
+ Status = EmmcSwitch (PassThru, Slot, Access, Index, Value, CmdSet);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcSwitchClockFreq: Switch to hstiming %d fails with %r\n", HsTiming, Status));\r
+ return Status;\r
+ }\r
+\r
+ Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcSwitchClockFreq: Send status fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Check the switch operation is really successful or not.\r
+ //\r
+ if ((DevStatus & BIT7) != 0) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcSwitchClockFreq: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Convert the clock freq unit from MHz to KHz.\r
+ //\r
+ Status = SdMmcHcClockSupply (PciIo, Slot, ClockFreq * 1000, Private->Capability[Slot]);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Switch to the High Speed timing according to request.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+ Simplified Spec 3.0 Figure 2-29 for details.\r
+\r
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+ @param[in] ClockFreq The max clock frequency to be set.\r
+ @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise\r
+ use single data rate data simpling method.\r
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSwitchToHighSpeed (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca,\r
+ IN UINT32 ClockFreq,\r
+ IN BOOLEAN IsDdr,\r
+ IN UINT8 BusWidth\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 HsTiming;\r
+ UINT8 HostCtrl1;\r
+ UINT8 HostCtrl2;\r
+\r
+ Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, IsDdr, BusWidth);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set to Hight Speed timing\r
+ //\r
+ HostCtrl1 = BIT2;\r
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Clean UHS Mode Select field of Host Control 2 reigster before update\r
+ //\r
+ HostCtrl2 = (UINT8)~0x7;\r
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set UHS Mode Select field of Host Control 2 reigster to SDR12/25/50\r
+ //\r
+ if (IsDdr) {\r
+ HostCtrl2 = BIT2;\r
+ } else if (ClockFreq == 52) {\r
+ HostCtrl2 = BIT0;\r
+ } else {\r
+ HostCtrl2 = 0;\r
+ }\r
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ HsTiming = 1;\r
+ Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, ClockFreq);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Switch to the HS200 timing according to request.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+ Simplified Spec 3.0 Figure 2-29 for details.\r
+\r
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+ @param[in] ClockFreq The max clock frequency to be set.\r
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSwitchToHS200 (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca,\r
+ IN UINT32 ClockFreq,\r
+ IN UINT8 BusWidth\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 HsTiming;\r
+ UINT8 HostCtrl2;\r
+ UINT16 ClockCtrl;\r
+\r
+ if ((BusWidth != 4) && (BusWidth != 8)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, FALSE, BusWidth);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set to HS200/SDR104 timing\r
+ //\r
+ //\r
+ // Stop bus clock at first\r
+ //\r
+ Status = SdMmcHcStopClock (PciIo, Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Clean UHS Mode Select field of Host Control 2 reigster before update\r
+ //\r
+ HostCtrl2 = (UINT8)~0x7;\r
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set UHS Mode Select field of Host Control 2 reigster to SDR104\r
+ //\r
+ HostCtrl2 = BIT0 | BIT1;\r
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Wait Internal Clock Stable in the Clock Control register to be 1 before set SD Clock Enable bit\r
+ //\r
+ Status = SdMmcHcWaitMmioSet (\r
+ PciIo,\r
+ Slot,\r
+ SD_MMC_HC_CLOCK_CTRL,\r
+ sizeof (ClockCtrl),\r
+ BIT1,\r
+ BIT1,\r
+ SD_MMC_HC_GENERIC_TIMEOUT\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set SD Clock Enable in the Clock Control register to 1\r
+ //\r
+ ClockCtrl = BIT2;\r
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+\r
+ HsTiming = 2;\r
+ Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, ClockFreq);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = EmmcTuningClkForHs200 (PciIo, PassThru, Slot, BusWidth);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Switch to the HS400 timing according to request.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+ Simplified Spec 3.0 Figure 2-29 for details.\r
+\r
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+ @param[in] ClockFreq The max clock frequency to be set.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSwitchToHS400 (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca,\r
+ IN UINT32 ClockFreq\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 HsTiming;\r
+ UINT8 HostCtrl2;\r
+\r
+ Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, ClockFreq, 8);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set to Hight Speed timing and set the clock frequency to a value less than 52MHz.\r
+ //\r
+ HsTiming = 1;\r
+ Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, 52);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // HS400 mode must use 8 data lines.\r
+ //\r
+ Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, TRUE, 8);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Clean UHS Mode Select field of Host Control 2 reigster before update\r
+ //\r
+ HostCtrl2 = (UINT8)~0x7;\r
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set UHS Mode Select field of Host Control 2 reigster to HS400\r
+ //\r
+ HostCtrl2 = BIT0 | BIT2;\r
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ HsTiming = 3;\r
+ Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, ClockFreq);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Switch the high speed timing according to request.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+ Simplified Spec 3.0 Figure 2-29 for details.\r
+\r
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSetBusMode (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_CSD Csd;\r
+ EMMC_EXT_CSD ExtCsd;\r
+ UINT8 HsTiming;\r
+ BOOLEAN IsDdr;\r
+ UINT32 ClockFreq;\r
+ UINT8 BusWidth;\r
+ SD_MMC_HC_PRIVATE_DATA *Private;\r
+\r
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
+\r
+ Status = EmmcGetCsd (PassThru, Slot, Rca, &Csd);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcSetBusMode: GetCsd fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ Status = EmmcSelect (PassThru, Slot, Rca);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcSetBusMode: Select fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ ASSERT (Private->Capability[Slot].BaseClkFreq != 0);\r
+ //\r
+ // Check if the Host Controller support 8bits bus width.\r
+ //\r
+ if (Private->Capability[Slot].BusWidth8 != 0) {\r
+ BusWidth = 8;\r
+ } else {\r
+ BusWidth = 4;\r
+ }\r
+ //\r
+ // Get Deivce_Type from EXT_CSD register.\r
+ //\r
+ Status = EmmcGetExtCsd (PassThru, Slot, &ExtCsd);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcSetBusMode: GetExtCsd fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Calculate supported bus speed/bus width/clock frequency.\r
+ //\r
+ HsTiming = 0;\r
+ IsDdr = FALSE;\r
+ ClockFreq = 0;\r
+ if (((ExtCsd.DeviceType & (BIT4 | BIT5)) != 0) && (Private->Capability[Slot].Sdr104 != 0)) {\r
+ HsTiming = 2;\r
+ IsDdr = FALSE;\r
+ ClockFreq = 200;\r
+ } else if (((ExtCsd.DeviceType & (BIT2 | BIT3)) != 0) && (Private->Capability[Slot].Ddr50 != 0)) {\r
+ HsTiming = 1;\r
+ IsDdr = TRUE;\r
+ ClockFreq = 52;\r
+ } else if (((ExtCsd.DeviceType & BIT1) != 0) && (Private->Capability[Slot].HighSpeed != 0)) {\r
+ HsTiming = 1;\r
+ IsDdr = FALSE;\r
+ ClockFreq = 52;\r
+ } else if (((ExtCsd.DeviceType & BIT0) != 0) && (Private->Capability[Slot].HighSpeed != 0)) {\r
+ HsTiming = 1;\r
+ IsDdr = FALSE;\r
+ ClockFreq = 26;\r
+ }\r
+ //\r
+ // Check if both of the device and the host controller support HS400 DDR mode.\r
+ //\r
+ if (((ExtCsd.DeviceType & (BIT6 | BIT7)) != 0) && (Private->Capability[Slot].Hs400 != 0)) {\r
+ //\r
+ // The host controller supports 8bits bus.\r
+ //\r
+ ASSERT (BusWidth == 8);\r
+ HsTiming = 3;\r
+ IsDdr = TRUE;\r
+ ClockFreq = 200;\r
+ }\r
+\r
+ if ((ClockFreq == 0) || (HsTiming == 0)) {\r
+ //\r
+ // Continue using default setting.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "EmmcSetBusMode: HsTiming %d ClockFreq %d BusWidth %d Ddr %a\n", HsTiming, ClockFreq, BusWidth, IsDdr ? "TRUE":"FALSE"));\r
+\r
+ if (HsTiming == 3) {\r
+ //\r
+ // Execute HS400 timing switch procedure\r
+ //\r
+ Status = EmmcSwitchToHS400 (PciIo, PassThru, Slot, Rca, ClockFreq);\r
+ } else if (HsTiming == 2) {\r
+ //\r
+ // Execute HS200 timing switch procedure\r
+ //\r
+ Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, ClockFreq, BusWidth);\r
+ } else {\r
+ //\r
+ // Execute High Speed timing switch procedure\r
+ //\r
+ Status = EmmcSwitchToHighSpeed (PciIo, PassThru, Slot, Rca, ClockFreq, BusWidth, IsDdr);\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "EmmcSetBusMode: Switch to %a %r\n", (HsTiming == 3) ? "HS400" : ((HsTiming == 2) ? "HS200" : "HighSpeed"), Status));\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Execute EMMC device identification procedure.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS There is a EMMC card.\r
+ @retval Others There is not a EMMC card.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcIdentification (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN UINT8 Slot\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ UINT32 Ocr;\r
+ UINT16 Rca;\r
+\r
+ PciIo = Private->PciIo;\r
+ PassThru = &Private->PassThru;\r
+\r
+ Status = EmmcReset (PassThru, Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_VERBOSE, "EmmcIdentification: Executing Cmd0 fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ Ocr = 0;\r
+ do {\r
+ Status = EmmcGetOcr (PassThru, Slot, &Ocr);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_VERBOSE, "EmmcIdentification: Executing Cmd1 fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ Ocr |= BIT30;\r
+ } while ((Ocr & BIT31) == 0);\r
+\r
+ Status = EmmcGetAllCid (PassThru, Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_VERBOSE, "EmmcIdentification: Executing Cmd2 fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Slot starts from 0 and valid RCA starts from 1.\r
+ // Here we takes a simple formula to calculate the RCA.\r
+ // Don't support multiple devices on the slot, that is\r
+ // shared bus slot feature.\r
+ //\r
+ Rca = Slot + 1;\r
+ Status = EmmcSetRca (PassThru, Slot, Rca);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcIdentification: Executing Cmd3 fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Enter Data Tranfer Mode.\r
+ //\r
+ DEBUG ((EFI_D_INFO, "EmmcIdentification: Found a EMMC device at slot [%d], RCA [%d]\n", Slot, Rca));\r
+ Private->Slot[Slot].CardType = EmmcCardType;\r
+\r
+ Status = EmmcSetBusMode (PciIo, PassThru, Slot, Rca);\r
+\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ This file provides some helper functions which are specific for SD card device.\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdMmcPciHcDxe.h"\r
+\r
+/**\r
+ Send command GO_IDLE_STATE to the device to make it go to Idle State.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The SD device is reset correctly.\r
+ @retval Others The device reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardReset (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_GO_IDLE_STATE;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_IF_COND to the device to inquiry the SD Memory Card interface\r
+ condition.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] SupplyVoltage The supplied voltage by the host.\r
+ @param[in] CheckPattern The check pattern to be sent to the device.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardVoltageCheck (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT8 SupplyVoltage,\r
+ IN UINT8 CheckPattern\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SEND_IF_COND;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR7;\r
+ SdMmcCmdBlk.CommandArgument = (SupplyVoltage << 8) | CheckPattern;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ if (SdMmcStatusBlk.Resp0 != SdMmcCmdBlk.CommandArgument) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SDIO_SEND_OP_COND to the device to see whether it is SDIO device.\r
+\r
+ Refer to SDIO Simplified Spec 3 Section 3.2 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] VoltageWindow The supply voltage window.\r
+ @param[in] S18R The boolean to show if it should switch to 1.8v.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdioSendOpCond (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT32 VoltageWindow,\r
+ IN BOOLEAN S18R\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+ UINT32 Switch;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SDIO_SEND_OP_COND;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR4;\r
+\r
+ Switch = S18R ? BIT24 : 0;\r
+\r
+ SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SD_SEND_OP_COND to the device to see whether it is SDIO device.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address of addressed device.\r
+ @param[in] VoltageWindow The supply voltage window.\r
+ @param[in] S18R The boolean to show if it should switch to 1.8v.\r
+ @param[in] Xpc The boolean to show if it should provide 0.36w power control.\r
+ @param[in] Hcs The boolean to show if it support host capacity info.\r
+ @param[out] Ocr The buffer to store returned OCR register value.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSendOpCond (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca,\r
+ IN UINT32 VoltageWindow,\r
+ IN BOOLEAN S18R,\r
+ IN BOOLEAN Xpc,\r
+ IN BOOLEAN Hcs,\r
+ OUT UINT32 *Ocr\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+ UINT32 Switch;\r
+ UINT32 MaxPower;\r
+ UINT32 HostCapacity;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_APP_CMD;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SEND_OP_COND;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;\r
+\r
+ Switch = S18R ? BIT24 : 0;\r
+ MaxPower = Xpc ? BIT28 : 0;\r
+ HostCapacity = Hcs ? BIT30 : 0;\r
+\r
+ SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch | MaxPower | HostCapacity;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+ //\r
+ *Ocr = SdMmcStatusBlk.Resp0;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Broadcast command ALL_SEND_CID to the bus to ask all the SD devices to send the\r
+ data of their CID registers.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardAllSendCid (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_ALL_SEND_CID;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SET_RELATIVE_ADDR to the SD device to assign a Relative device\r
+ Address (RCA).\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[out] Rca The relative device address to assign.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSetRca (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ OUT UINT16 *Rca\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_CSD to the SD device to get the data of the CSD register.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address of selected device.\r
+ @param[out] Csd The buffer to store the content of the CSD register.\r
+ Note the caller should ignore the lowest byte of this\r
+ buffer as the content of this byte is meaningless even\r
+ if the operation succeeds.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardGetCsd (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca,\r
+ OUT SD_CSD *Csd\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SEND_CSD;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+ //\r
+ CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_CSD to the SD device to get the data of the CSD register.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address of selected device.\r
+ @param[out] Scr The buffer to store the content of the SCR register.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardGetScr (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca,\r
+ OUT SD_SCR *Scr\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_APP_CMD;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SEND_SCR;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+\r
+ Packet.InDataBuffer = Scr;\r
+ Packet.InTransferLength = sizeof (SD_SCR);\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SELECT_DESELECT_CARD to the SD device to select/deselect it.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address of selected device.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSelect (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command VOLTAGE_SWITCH to the SD device to switch the voltage of the device.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardVoltageSwitch (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_VOLTAGE_SWITCH;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ SdMmcCmdBlk.CommandArgument = 0;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SET_BUS_WIDTH to the SD device to set the bus width.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address of addressed device.\r
+ @param[in] BusWidth The bus width to be set, it could be 1 or 4.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSetBusWidth (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca,\r
+ IN UINT8 BusWidth\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+ UINT8 Value;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_APP_CMD;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SET_BUS_WIDTH;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+\r
+ if (BusWidth == 1) {\r
+ Value = 0;\r
+ } else if (BusWidth == 4) {\r
+ Value = 2;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ SdMmcCmdBlk.CommandArgument = Value & 0x3;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SWITCH_FUNC to the SD device to check switchable function or switch card function.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] AccessMode The value for access mode group.\r
+ @param[in] CommandSystem The value for command set group.\r
+ @param[in] DriveStrength The value for drive length group.\r
+ @param[in] PowerLimit The value for power limit group.\r
+ @param[in] Mode Switch or check function.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSwitch (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT8 AccessMode,\r
+ IN UINT8 CommandSystem,\r
+ IN UINT8 DriveStrength,\r
+ IN UINT8 PowerLimit,\r
+ IN BOOLEAN Mode\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+ UINT32 ModeValue;\r
+ UINT8 Data[64];\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SWITCH_FUNC;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+\r
+ ModeValue = Mode ? BIT31 : 0;\r
+ SdMmcCmdBlk.CommandArgument = (AccessMode & 0xF) | ((PowerLimit & 0xF) << 4) | \\r
+ ((DriveStrength & 0xF) << 8) | ((DriveStrength & 0xF) << 12) | \\r
+ ModeValue;\r
+\r
+ Packet.InDataBuffer = Data;\r
+ Packet.InTransferLength = sizeof (Data);\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_STATUS to the addressed SD device to get its status register.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address of addressed device.\r
+ @param[out] DevStatus The returned device status.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSendStatus (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca,\r
+ OUT UINT32 *DevStatus\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ *DevStatus = SdMmcStatusBlk.Resp0;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_TUNING_BLOCK to the SD device for HS200 optimal sampling point\r
+ detection.\r
+\r
+ It may be sent up to 40 times until the host finishes the tuning procedure.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSendTuningBlk (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot\r
+ )\r
+{\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+ UINT8 TuningBlock[64];\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SEND_TUNING_BLOCK;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ SdMmcCmdBlk.CommandArgument = 0;\r
+\r
+ Packet.InDataBuffer = TuningBlock;\r
+ Packet.InTransferLength = sizeof (TuningBlock);\r
+\r
+ Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Tunning the sampling point of SDR104 or SDR50 bus speed mode.\r
+\r
+ Command SD_SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the\r
+ tuning procedure.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and\r
+ SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.\r
+\r
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardTuningClock (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 HostCtrl2;\r
+ UINT8 Retry;\r
+\r
+ //\r
+ // Notify the host that the sampling clock tuning procedure starts.\r
+ //\r
+ HostCtrl2 = BIT6;\r
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.\r
+ //\r
+ Retry = 0;\r
+ do {\r
+ Status = SdCardSendTuningBlk (PassThru, Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdCardSendTuningBlk: Send tuning block fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
+ break;\r
+ }\r
+ } while (++Retry < 40);\r
+\r
+ if (Retry == 40) {\r
+ Status = EFI_TIMEOUT;\r
+ DEBUG ((EFI_D_ERROR, "SdCardTuningClock: Send tuning block exceeds 40 times\n"));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Switch the bus width to specified width.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and\r
+ SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.\r
+\r
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSwitchBusWidth (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca,\r
+ IN UINT8 BusWidth\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 DevStatus;\r
+\r
+ Status = SdCardSetBusWidth (PassThru, Slot, Rca, BusWidth);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdCardSwitchBusWidth: Switch to bus width %d fails with %r\n", BusWidth, Status));\r
+ return Status;\r
+ }\r
+\r
+ Status = SdCardSendStatus (PassThru, Slot, Rca, &DevStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdCardSwitchBusWidth: Send status fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Check the switch operation is really successful or not.\r
+ //\r
+ if ((DevStatus >> 16) != 0) {\r
+ DEBUG ((EFI_D_ERROR, "SdCardSwitchBusWidth: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Switch the high speed timing according to request.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and\r
+ SD Host Controller Simplified Spec 3.0 section Figure 2-29 for details.\r
+\r
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+ @param[in] S18A The boolean to show if it's a UHS-I SD card.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSetBusMode (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca,\r
+ IN BOOLEAN S18A\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_MMC_HC_SLOT_CAP *Capability;\r
+ UINT32 ClockFreq;\r
+ UINT8 BusWidth;\r
+ UINT8 AccessMode;\r
+ UINT8 HostCtrl1;\r
+ UINT8 HostCtrl2;\r
+ SD_MMC_HC_PRIVATE_DATA *Private;\r
+\r
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
+\r
+ Capability = &Private->Capability[Slot];\r
+\r
+ Status = SdCardSelect (PassThru, Slot, Rca);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ BusWidth = 4;\r
+\r
+ Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca, BusWidth);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Calculate supported bus speed/bus width/clock frequency.\r
+ //\r
+ ClockFreq = 0;\r
+ if (S18A && (Capability->Sdr104 != 0)) {\r
+ ClockFreq = 208;\r
+ AccessMode = 3;\r
+ } else if (S18A && (Capability->Sdr50 != 0)) {\r
+ ClockFreq = 100;\r
+ AccessMode = 2;\r
+ } else if (S18A && (Capability->Ddr50 != 0)) {\r
+ ClockFreq = 50;\r
+ AccessMode = 4;\r
+ } else {\r
+ ClockFreq = 50;\r
+ AccessMode = 1;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "SdCardSetBusMode: AccessMode %d ClockFreq %d BusWidth %d\n", AccessMode, ClockFreq, BusWidth));\r
+\r
+ Status = SdCardSwitch (PassThru, Slot, AccessMode, 0, 0, 0, TRUE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Set to Hight Speed timing\r
+ //\r
+ if (AccessMode == 1) {\r
+ HostCtrl1 = BIT2;\r
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ HostCtrl2 = (UINT8)~0x7;\r
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ HostCtrl2 = AccessMode;\r
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = SdMmcHcClockSupply (PciIo, Slot, ClockFreq * 1000, *Capability);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((AccessMode == 3) || ((AccessMode == 2) && (Capability->TuningSDR50 != 0))) {\r
+ Status = SdCardTuningClock (PciIo, PassThru, Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Execute SD device identification procedure.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 3.6 for details.\r
+\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS There is a SD card.\r
+ @retval Others There is not a SD card.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardIdentification (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN UINT8 Slot\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ UINT32 Ocr;\r
+ UINT16 Rca;\r
+ BOOLEAN Xpc;\r
+ BOOLEAN S18r;\r
+ UINT64 MaxCurrent;\r
+ UINT16 ControllerVer;\r
+ UINT8 PowerCtrl;\r
+ UINT32 PresentState;\r
+ UINT8 HostCtrl2;\r
+\r
+ PciIo = Private->PciIo;\r
+ PassThru = &Private->PassThru;\r
+ //\r
+ // 1. Send Cmd0 to the device\r
+ //\r
+ Status = SdCardReset (PassThru, Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "SdCardIdentification: Executing Cmd0 fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // 2. Send Cmd8 to the device\r
+ //\r
+ Status = SdCardVoltageCheck (PassThru, Slot, 0x1, 0xFF);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "SdCardIdentification: Executing Cmd8 fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // 3. Send SDIO Cmd5 to the device to the SDIO device OCR register.\r
+ //\r
+ Status = SdioSendOpCond (PassThru, Slot, 0, FALSE);\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "SdCardIdentification: Found SDIO device, ignore it as we don't support\n"));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // 4. Send Acmd41 with voltage window 0 to the device\r
+ //\r
+ Status = SdCardSendOpCond (PassThru, Slot, 0, 0, FALSE, FALSE, FALSE, &Ocr);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "SdCardIdentification: Executing SdCardSendOpCond fails with %r\n", Status));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (Private->Capability[Slot].Voltage33 != 0) {\r
+ //\r
+ // Support 3.3V\r
+ //\r
+ MaxCurrent = ((UINT32)Private->MaxCurrent[Slot] & 0xFF) * 4;\r
+ } else if (Private->Capability[Slot].Voltage30 != 0) {\r
+ //\r
+ // Support 3.0V\r
+ //\r
+ MaxCurrent = (((UINT32)Private->MaxCurrent[Slot] >> 8) & 0xFF) * 4;\r
+ } else if (Private->Capability[Slot].Voltage18 != 0) {\r
+ //\r
+ // Support 1.8V\r
+ //\r
+ MaxCurrent = (((UINT32)Private->MaxCurrent[Slot] >> 16) & 0xFF) * 4;\r
+ } else {\r
+ ASSERT (FALSE);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (MaxCurrent >= 150) {\r
+ Xpc = TRUE;\r
+ } else {\r
+ Xpc = FALSE;\r
+ }\r
+\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((ControllerVer & 0xFF) == 2) {\r
+ S18r = TRUE;\r
+ } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {\r
+ S18r = FALSE;\r
+ } else {\r
+ ASSERT (FALSE);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // 5. Repeatly send Acmd41 with supply voltage window to the device.\r
+ // Note here we only support the cards complied with SD physical\r
+ // layer simplified spec version 2.0 and version 3.0 and above.\r
+ //\r
+ do {\r
+ Status = SdCardSendOpCond (PassThru, Slot, 0, Ocr, S18r, Xpc, TRUE, &Ocr);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdCardIdentification: SdCardSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n", Status, Ocr, S18r, Xpc));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ } while ((Ocr & BIT31) == 0);\r
+\r
+ //\r
+ // 6. If the S18A bit is set and the Host Controller supports 1.8V signaling\r
+ // (One of support bits is set to 1: SDR50, SDR104 or DDR50 in the\r
+ // Capabilities register), switch its voltage to 1.8V.\r
+ //\r
+ if ((Private->Capability[Slot].Sdr50 != 0 ||\r
+ Private->Capability[Slot].Sdr104 != 0 ||\r
+ Private->Capability[Slot].Ddr50 != 0) &&\r
+ ((Ocr & BIT24) != 0)) {\r
+ Status = SdCardVoltageSwitch (PassThru, Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdCardIdentification: Executing SdCardVoltageSwitch fails with %r\n", Status));\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Error;\r
+ } else {\r
+ Status = SdMmcHcStopClock (PciIo, Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Error;\r
+ }\r
+\r
+ SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
+ if (((PresentState >> 20) & 0xF) != 0) {\r
+ DEBUG ((EFI_D_ERROR, "SdCardIdentification: SwitchVoltage fails with PresentState = 0x%x\n", PresentState));\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Error;\r
+ }\r
+ HostCtrl2 = BIT3;\r
+ SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+\r
+ gBS->Stall (5000);\r
+\r
+ SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);\r
+ if ((HostCtrl2 & BIT3) == 0) {\r
+ DEBUG ((EFI_D_ERROR, "SdCardIdentification: SwitchVoltage fails with HostCtrl2 = 0x%x\n", HostCtrl2));\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Error;\r
+ }\r
+\r
+ SdMmcHcInitClockFreq (PciIo, Slot, Private->Capability[Slot]);\r
+\r
+ gBS->Stall (1);\r
+\r
+ SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
+ if (((PresentState >> 20) & 0xF) != 0xF) {\r
+ DEBUG ((EFI_D_ERROR, "SdCardIdentification: SwitchVoltage fails with PresentState = 0x%x, It should be 0xF\n", PresentState));\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Error;\r
+ }\r
+ }\r
+ DEBUG ((EFI_D_INFO, "SdCardIdentification: Switch to 1.8v signal voltage success\n"));\r
+ }\r
+\r
+ Status = SdCardAllSendCid (PassThru, Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdCardIdentification: Executing SdCardAllSendCid fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ Status = SdCardSetRca (PassThru, Slot, &Rca);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdCardIdentification: Executing SdCardSetRca fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Enter Data Tranfer Mode.\r
+ //\r
+ DEBUG ((EFI_D_INFO, "SdCardIdentification: Found a SD device at slot [%d]\n", Slot));\r
+ Private->Slot[Slot].CardType = SdCardType;\r
+\r
+ Status = SdCardSetBusMode (PciIo, PassThru, Slot, Rca, ((Ocr & BIT24) != 0));\r
+\r
+ return Status;\r
+\r
+Error:\r
+ //\r
+ // Set SD Bus Power = 0\r
+ //\r
+ PowerCtrl = (UINT8)~BIT0;\r
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, sizeof (PowerCtrl), &PowerCtrl);\r
+ return EFI_DEVICE_ERROR;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ This driver is used to manage SD/MMC PCI host controllers which are compliance\r
+ with SD Host Controller Simplified Specification version 3.00.\r
+\r
+ It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdMmcPciHcDxe.h"\r
+\r
+//\r
+// Driver Global Variables\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gSdMmcPciHcDriverBinding = {\r
+ SdMmcPciHcDriverBindingSupported,\r
+ SdMmcPciHcDriverBindingStart,\r
+ SdMmcPciHcDriverBindingStop,\r
+ 0x10,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+//\r
+// Template for SD/MMC host controller private data.\r
+//\r
+SD_MMC_HC_PRIVATE_DATA gSdMmcPciHcTemplate = {\r
+ SD_MMC_HC_PRIVATE_SIGNATURE, // Signature\r
+ NULL, // ControllerHandle\r
+ NULL, // PciIo\r
+ { // PassThru\r
+ sizeof (UINT32),\r
+ SdMmcPassThruPassThru,\r
+ SdMmcPassThruGetNextSlot,\r
+ SdMmcPassThruBuildDevicePath,\r
+ SdMmcPassThruGetSlotNumber,\r
+ SdMmcPassThruResetDevice\r
+ },\r
+ 0, // PciAttributes\r
+ 0, // PreviousSlot\r
+ NULL, // TimerEvent\r
+ NULL, // ConnectEvent\r
+ // Queue\r
+ INITIALIZE_LIST_HEAD_VARIABLE (gSdMmcPciHcTemplate.Queue),\r
+ { // Slot\r
+ {0, UnknownSlot, 0, 0}, {0, UnknownSlot, 0, 0}, {0, UnknownSlot, 0, 0},\r
+ {0, UnknownSlot, 0, 0}, {0, UnknownSlot, 0, 0}, {0, UnknownSlot, 0, 0}\r
+ },\r
+ { // Capability\r
+ {0},\r
+ },\r
+ { // MaxCurrent\r
+ 0,\r
+ },\r
+ 0 // ControllerVersion\r
+};\r
+\r
+SD_DEVICE_PATH mSdDpTemplate = {\r
+ {\r
+ MESSAGING_DEVICE_PATH,\r
+ MSG_SD_DP,\r
+ {\r
+ (UINT8) (sizeof (SD_DEVICE_PATH)),\r
+ (UINT8) ((sizeof (SD_DEVICE_PATH)) >> 8)\r
+ }\r
+ },\r
+ 0\r
+};\r
+\r
+EMMC_DEVICE_PATH mEmmcDpTemplate = {\r
+ {\r
+ MESSAGING_DEVICE_PATH,\r
+ MSG_EMMC_DP,\r
+ {\r
+ (UINT8) (sizeof (EMMC_DEVICE_PATH)),\r
+ (UINT8) ((sizeof (EMMC_DEVICE_PATH)) >> 8)\r
+ }\r
+ },\r
+ 0\r
+};\r
+\r
+//\r
+// Prioritized function list to detect card type.\r
+// User could add other card detection logic here.\r
+//\r
+CARD_TYPE_DETECT_ROUTINE mCardTypeDetectRoutineTable[] = {\r
+ EmmcIdentification,\r
+ SdCardIdentification,\r
+ NULL\r
+};\r
+\r
+/**\r
+ The entry point for SD host controller driver, used to install this driver on the ImageHandle.\r
+\r
+ @param[in] ImageHandle The firmware allocated handle for this driver image.\r
+ @param[in] SystemTable Pointer to the EFI system table.\r
+\r
+ @retval EFI_SUCCESS Driver loaded.\r
+ @retval other Driver not loaded.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSdMmcPciHcDxe (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = EfiLibInstallDriverBindingComponentName2 (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gSdMmcPciHcDriverBinding,\r
+ ImageHandle,\r
+ &gSdMmcPciHcComponentName,\r
+ &gSdMmcPciHcComponentName2\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Call back function when the timer event is signaled.\r
+\r
+ @param[in] Event The Event this notify function registered to.\r
+ @param[in] Context Pointer to the context data registered to the\r
+ Event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ProcessAsyncTaskList (\r
+ IN EFI_EVENT Event,\r
+ IN VOID* Context\r
+ )\r
+{\r
+ SD_MMC_HC_PRIVATE_DATA *Private;\r
+ LIST_ENTRY *Link;\r
+ SD_MMC_HC_TRB *Trb;\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
+ BOOLEAN InfiniteWait;\r
+ EFI_EVENT TrbEvent;\r
+\r
+ Private = (SD_MMC_HC_PRIVATE_DATA*)Context;\r
+\r
+ //\r
+ // Check if the first entry in the async I/O queue is done or not.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ Trb = NULL;\r
+ Link = GetFirstNode (&Private->Queue);\r
+ if (!IsNull (&Private->Queue, Link)) {\r
+ Trb = SD_MMC_HC_TRB_FROM_THIS (Link);\r
+ if (Private->Slot[Trb->Slot].MediaPresent == FALSE) {\r
+ Status = EFI_NO_MEDIA;\r
+ goto Done;\r
+ }\r
+ if (!Trb->Started) {\r
+ //\r
+ // Check whether the cmd/data line is ready for transfer.\r
+ //\r
+ Status = SdMmcCheckTrbEnv (Private, Trb);\r
+ if (!EFI_ERROR (Status)) {\r
+ Trb->Started = TRUE;\r
+ Status = SdMmcExecTrb (Private, Trb);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ } else {\r
+ goto Done;\r
+ }\r
+ }\r
+ Status = SdMmcCheckTrbResult (Private, Trb);\r
+ }\r
+\r
+Done:\r
+ if ((Trb != NULL) && (Status == EFI_NOT_READY)) {\r
+ Packet = Trb->Packet;\r
+ if (Packet->Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
+ if ((!InfiniteWait) && (Trb->Timeout-- == 0)) {\r
+ RemoveEntryList (Link);\r
+ Trb->Packet->TransactionStatus = EFI_TIMEOUT;\r
+ TrbEvent = Trb->Event;\r
+ SdMmcFreeTrb (Trb);\r
+ DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT\n", TrbEvent));\r
+ gBS->SignalEvent (TrbEvent);\r
+ return;\r
+ }\r
+ }\r
+ if ((Trb != NULL) && (Status != EFI_NOT_READY)) {\r
+ RemoveEntryList (Link);\r
+ Trb->Packet->TransactionStatus = Status;\r
+ TrbEvent = Trb->Event;\r
+ SdMmcFreeTrb (Trb);\r
+ DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p with %r\n", TrbEvent, Status));\r
+ gBS->SignalEvent (TrbEvent);\r
+ }\r
+ return;\r
+}\r
+\r
+/**\r
+ Sd removable device enumeration callback function when the timer event is signaled.\r
+\r
+ @param[in] Event The Event this notify function registered to.\r
+ @param[in] Context Pointer to the context data registered to the\r
+ Event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SdMmcPciHcEnumerateDevice (\r
+ IN EFI_EVENT Event,\r
+ IN VOID* Context\r
+ )\r
+{\r
+ SD_MMC_HC_PRIVATE_DATA *Private;\r
+ EFI_STATUS Status;\r
+ UINT8 Slot;\r
+ BOOLEAN MediaPresent;\r
+ UINT32 RoutineNum;\r
+ CARD_TYPE_DETECT_ROUTINE *Routine;\r
+ UINTN Index;\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *NextLink;\r
+ SD_MMC_HC_TRB *Trb;\r
+\r
+ Private = (SD_MMC_HC_PRIVATE_DATA*)Context;\r
+\r
+ for (Slot = 0; Slot < SD_MMC_HC_MAX_SLOT; Slot++) {\r
+ if ((Private->Slot[Slot].Enable) && (Private->Slot[Slot].SlotType == RemovableSlot)) {\r
+ Status = SdMmcHcCardDetect (Private->PciIo, Slot, &MediaPresent);\r
+ if ((Status == EFI_MEDIA_CHANGED) && (MediaPresent == FALSE)) {\r
+ DEBUG ((EFI_D_INFO, "SdMmcPciHcEnumerateDevice: device disconnected at slot %d of pci %p\n", Slot, Private->PciIo));\r
+ Private->Slot[Slot].MediaPresent = FALSE;\r
+ //\r
+ // Signal all async task events at the slot with EFI_NO_MEDIA status.\r
+ //\r
+ for (Link = GetFirstNode (&Private->Queue);\r
+ !IsNull (&Private->Queue, Link);\r
+ Link = NextLink) {\r
+ NextLink = GetNextNode (&Private->Queue, Link);\r
+ Trb = SD_MMC_HC_TRB_FROM_THIS (Link);\r
+ if (Trb->Slot == Slot) {\r
+ RemoveEntryList (Link);\r
+ Trb->Packet->TransactionStatus = EFI_NO_MEDIA;\r
+ gBS->SignalEvent (Trb->Event);\r
+ SdMmcFreeTrb (Trb);\r
+ }\r
+ }\r
+ //\r
+ // Notify the upper layer the connect state change through ReinstallProtocolInterface.\r
+ //\r
+ gBS->ReinstallProtocolInterface (\r
+ Private->ControllerHandle,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ &Private->PassThru,\r
+ &Private->PassThru\r
+ );\r
+ }\r
+ if ((Status == EFI_MEDIA_CHANGED) && (MediaPresent == TRUE)) {\r
+ DEBUG ((EFI_D_INFO, "SdMmcPciHcEnumerateDevice: device connected at slot %d of pci %p\n", Slot, Private->PciIo));\r
+ //\r
+ // Reinitialize slot and restart identification process for the new attached device\r
+ //\r
+ Status = SdMmcHcInitHost (Private->PciIo, Slot, Private->Capability[Slot]);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ Private->Slot[Slot].MediaPresent = TRUE;\r
+ RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE);\r
+ for (Index = 0; Index < RoutineNum; Index++) {\r
+ Routine = &mCardTypeDetectRoutineTable[Index];\r
+ if (*Routine != NULL) {\r
+ Status = (*Routine) (Private, Slot);\r
+ if (!EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Notify the upper layer the connect state change through ReinstallProtocolInterface.\r
+ //\r
+ gBS->ReinstallProtocolInterface (\r
+ Private->ControllerHandle,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ &Private->PassThru,\r
+ &Private->PassThru\r
+ );\r
+ }\r
+ }\r
+ }\r
+\r
+ return;\r
+}\r
+/**\r
+ Tests to see if this driver supports a given controller. If a child device is provided,\r
+ it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+ This function checks to see if the driver specified by This supports the device specified by\r
+ ControllerHandle. Drivers will typically use the device path attached to\r
+ ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+ ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+ may be called many times during platform initialization. In order to reduce boot times, the tests\r
+ performed by this function must be very small, and take as little time as possible to execute. This\r
+ function must not change the state of any hardware devices, and this function must be aware that the\r
+ device specified by ControllerHandle may already be managed by the same driver or a\r
+ different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+ to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to test. This handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For bus drivers, if this parameter is not NULL, then\r
+ the bus driver must determine if the bus controller specified\r
+ by ControllerHandle and the child controller specified\r
+ by RemainingDevicePath are both supported by this\r
+ bus driver.\r
+\r
+ @retval EFI_SUCCESS The device specified by ControllerHandle and\r
+ RemainingDevicePath is supported by the driver specified by This.\r
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by the driver\r
+ specified by This.\r
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by a different\r
+ driver or an application that requires exclusive access.\r
+ Currently not implemented.\r
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ PCI_TYPE00 PciData;\r
+\r
+ PciIo = NULL;\r
+ ParentDevicePath = NULL;\r
+\r
+ //\r
+ // SdPciHcDxe is a device driver, and should ingore the\r
+ // "RemainingDevicePath" according to EFI spec.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID *) &ParentDevicePath,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // EFI_ALREADY_STARTED is also an error.\r
+ //\r
+ return Status;\r
+ }\r
+ //\r
+ // Close the protocol because we don't use it here.\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ //\r
+ // Now test the EfiPciIoProtocol.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &PciIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Now further check the PCI header: Base class (offset 0x08) and\r
+ // Sub Class (offset 0x05). This controller should be an SD/MMC PCI\r
+ // Host Controller.\r
+ //\r
+ Status = PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ sizeof (PciData),\r
+ &PciData\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Since we already got the PciData, we can close protocol to avoid to carry it\r
+ // on for multiple exit points.\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ //\r
+ // Examine SD PCI Host Controller PCI Configuration table fields.\r
+ //\r
+ if ((PciData.Hdr.ClassCode[2] == PCI_CLASS_SYSTEM_PERIPHERAL) &&\r
+ (PciData.Hdr.ClassCode[1] == PCI_SUBCLASS_SD_HOST_CONTROLLER) &&\r
+ ((PciData.Hdr.ClassCode[0] == 0x00) || (PciData.Hdr.ClassCode[0] == 0x01))) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Starts a device controller or a bus controller.\r
+\r
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+ As a result, much of the error checking on the parameters to Start() has been moved into this\r
+ common boot service. It is legal to call Start() from other locations,\r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE.\r
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+ EFI_DEVICE_PATH_PROTOCOL.\r
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to start. This handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For a bus driver, if this parameter is NULL, then handles\r
+ for all the children of Controller are created by this driver.\r
+ If this parameter is not NULL and the first Device Path Node is\r
+ not the End of Device Path Node, then only the handle for the\r
+ child device specified by the first Device Path Node of\r
+ RemainingDevicePath is created by this driver.\r
+ If the first Device Path Node of RemainingDevicePath is\r
+ the End of Device Path Node, no child handle is created by this\r
+ driver.\r
+\r
+ @retval EFI_SUCCESS The device was started.\r
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval Others The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_MMC_HC_PRIVATE_DATA *Private;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT64 Supports;\r
+ UINT64 PciAttributes;\r
+ UINT8 SlotNum;\r
+ UINT8 FirstBar;\r
+ UINT8 Slot;\r
+ UINT8 Index;\r
+ CARD_TYPE_DETECT_ROUTINE *Routine;\r
+ UINT32 RoutineNum;\r
+ BOOLEAN MediaPresent;\r
+\r
+ DEBUG ((EFI_D_INFO, "SdMmcPciHcDriverBindingStart: Start\n"));\r
+\r
+ //\r
+ // Open PCI I/O Protocol and save pointer to open protocol\r
+ // in private data area.\r
+ //\r
+ PciIo = NULL;\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &PciIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Enable the SD Host Controller MMIO space\r
+ //\r
+ Private = NULL;\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationGet,\r
+ 0,\r
+ &PciAttributes\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationSupported,\r
+ 0,\r
+ &Supports\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationEnable,\r
+ Supports,\r
+ NULL\r
+ );\r
+ } else {\r
+ goto Done;\r
+ }\r
+\r
+ Private = AllocateCopyPool (sizeof (SD_MMC_HC_PRIVATE_DATA), &gSdMmcPciHcTemplate);\r
+ if (Private == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ Private->ControllerHandle = Controller;\r
+ Private->PciIo = PciIo;\r
+ Private->PciAttributes = PciAttributes;\r
+ InitializeListHead (&Private->Queue);\r
+\r
+ //\r
+ // Get SD/MMC Pci Host Controller Slot info\r
+ //\r
+ Status = SdMmcHcGetSlotInfo (PciIo, &FirstBar, &SlotNum);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ for (Slot = FirstBar; Slot < (FirstBar + SlotNum); Slot++) {\r
+ Private->Slot[Slot].Enable = TRUE;\r
+\r
+ Status = SdMmcHcGetCapability (PciIo, Slot, &Private->Capability[Slot]);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ DumpCapabilityReg (Slot, &Private->Capability[Slot]);\r
+\r
+ Status = SdMmcHcGetMaxCurrent (PciIo, Slot, &Private->MaxCurrent[Slot]);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ Private->Slot[Slot].SlotType = Private->Capability[Slot].SlotType;\r
+ if ((Private->Slot[Slot].SlotType != RemovableSlot) && (Private->Slot[Slot].SlotType != EmbeddedSlot)) {\r
+ DEBUG ((EFI_D_INFO, "SdMmcPciHcDxe doesn't support the slot type [%d]!!!\n", Private->Slot[Slot].SlotType));\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Reset the specified slot of the SD/MMC Pci Host Controller\r
+ //\r
+ Status = SdMmcHcReset (PciIo, Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ //\r
+ // Check whether there is a SD/MMC card attached\r
+ //\r
+ Status = SdMmcHcCardDetect (PciIo, Slot, &MediaPresent);\r
+ if ((Status == EFI_MEDIA_CHANGED) && (MediaPresent == FALSE)) {\r
+ DEBUG ((EFI_D_ERROR, "SdMmcHcCardDetect: No device attached in Slot[%d]!!!\n", Slot));\r
+ continue;\r
+ }\r
+\r
+ Status = SdMmcHcInitHost (PciIo, Slot, Private->Capability[Slot]);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ Private->Slot[Slot].MediaPresent = TRUE;\r
+ RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE);\r
+ for (Index = 0; Index < RoutineNum; Index++) {\r
+ Routine = &mCardTypeDetectRoutineTable[Index];\r
+ if (*Routine != NULL) {\r
+ Status = (*Routine) (Private, Slot);\r
+ if (!EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Start the asynchronous I/O monitor\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ ProcessAsyncTaskList,\r
+ Private,\r
+ &Private->TimerEvent\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = gBS->SetTimer (Private->TimerEvent, TimerPeriodic, SD_MMC_HC_ASYNC_TIMER);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Start the Sd removable device connection enumeration\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ SdMmcPciHcEnumerateDevice,\r
+ Private,\r
+ &Private->ConnectEvent\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = gBS->SetTimer (Private->ConnectEvent, TimerPeriodic, SD_MMC_HC_ENUM_TIMER);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ &(Private->PassThru),\r
+ NULL\r
+ );\r
+\r
+ DEBUG ((EFI_D_INFO, "SdMmcPciHcDriverBindingStart: %r End on %x\n", Status, Controller));\r
+\r
+Done:\r
+ if (EFI_ERROR (Status)) {\r
+ if ((Private != NULL) && (Private->PciAttributes != 0)) {\r
+ //\r
+ // Restore original PCI attributes\r
+ //\r
+ PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationSet,\r
+ Private->PciAttributes,\r
+ NULL\r
+ );\r
+ }\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ if ((Private != NULL) && (Private->TimerEvent != NULL)) {\r
+ gBS->CloseEvent (Private->TimerEvent);\r
+ }\r
+\r
+ if ((Private != NULL) && (Private->ConnectEvent != NULL)) {\r
+ gBS->CloseEvent (Private->ConnectEvent);\r
+ }\r
+\r
+ if (Private != NULL) {\r
+ FreePool (Private);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Stops a device controller or a bus controller.\r
+\r
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+ As a result, much of the error checking on the parameters to Stop() has been moved\r
+ into this common boot service. It is legal to call Stop() from other locations,\r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+ same driver's Start() function.\r
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+ Start() function, and the Start() function must have called OpenProtocol() on\r
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must\r
+ support a bus specific I/O protocol for the driver\r
+ to use to stop the device.\r
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+ if NumberOfChildren is 0.\r
+\r
+ @retval EFI_SUCCESS The device was stopped.\r
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ SD_MMC_HC_PRIVATE_DATA *Private;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *NextLink;\r
+ SD_MMC_HC_TRB *Trb;\r
+\r
+ DEBUG ((EFI_D_INFO, "SdMmcPciHcDriverBindingStop: Start\n"));\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ (VOID**) &PassThru,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
+ //\r
+ // Close Non-Blocking timer and free Task list.\r
+ //\r
+ if (Private->TimerEvent != NULL) {\r
+ gBS->CloseEvent (Private->TimerEvent);\r
+ Private->TimerEvent = NULL;\r
+ }\r
+ if (Private->ConnectEvent != NULL) {\r
+ gBS->CloseEvent (Private->ConnectEvent);\r
+ Private->ConnectEvent = NULL;\r
+ }\r
+ //\r
+ // As the timer is closed, there is no needs to use TPL lock to\r
+ // protect the critical region "queue".\r
+ //\r
+ for (Link = GetFirstNode (&Private->Queue);\r
+ !IsNull (&Private->Queue, Link);\r
+ Link = NextLink) {\r
+ NextLink = GetNextNode (&Private->Queue, Link);\r
+ RemoveEntryList (Link);\r
+ Trb = SD_MMC_HC_TRB_FROM_THIS (Link);\r
+ Trb->Packet->TransactionStatus = EFI_ABORTED;\r
+ gBS->SignalEvent (Trb->Event);\r
+ SdMmcFreeTrb (Trb);\r
+ }\r
+\r
+ //\r
+ // Uninstall Block I/O protocol from the device handle\r
+ //\r
+ Status = gBS->UninstallProtocolInterface (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ &(Private->PassThru)\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ //\r
+ // Restore original PCI attributes\r
+ //\r
+ PciIo = Private->PciIo;\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationSet,\r
+ Private->PciAttributes,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ FreePool (Private);\r
+\r
+ DEBUG ((EFI_D_INFO, "SdMmcPciHcDriverBindingStop: End with %r\n", Status));\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Sends SD command to an SD card that is attached to the SD controller.\r
+\r
+ The PassThru() function sends the SD command specified by Packet to the SD card\r
+ specified by Slot.\r
+\r
+ If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.\r
+\r
+ If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.\r
+\r
+ If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER\r
+ is returned.\r
+\r
+ If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,\r
+ EFI_INVALID_PARAMETER is returned.\r
+\r
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in,out] Packet A pointer to the SD command data structure.\r
+ @param[in] Event If Event is NULL, blocking I/O is performed. If Event is\r
+ not NULL, then nonblocking I/O is performed, and Event\r
+ will be signaled when the Packet completes.\r
+\r
+ @retval EFI_SUCCESS The SD Command Packet was sent by the host.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD\r
+ command Packet.\r
+ @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.\r
+ @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and\r
+ OutDataBuffer are NULL.\r
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.\r
+ @retval EFI_UNSUPPORTED The command described by the SD Command Packet is not\r
+ supported by the host controller.\r
+ @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the\r
+ limit supported by SD card ( i.e. if the number of bytes\r
+ exceed the Last LBA).\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruPassThru (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,\r
+ IN UINT8 Slot,\r
+ IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,\r
+ IN EFI_EVENT Event OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_MMC_HC_PRIVATE_DATA *Private;\r
+ SD_MMC_HC_TRB *Trb;\r
+ EFI_TPL OldTpl;\r
+\r
+ if ((This == NULL) || (Packet == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Packet->SdMmcCmdBlk == NULL) || (Packet->SdMmcStatusBlk == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);\r
+\r
+ if (!Private->Slot[Slot].Enable) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!Private->Slot[Slot].MediaPresent) {\r
+ return EFI_NO_MEDIA;\r
+ }\r
+\r
+ Trb = SdMmcCreateTrb (Private, Slot, Packet, Event);\r
+ if (Trb == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Immediately return for async I/O.\r
+ //\r
+ if (Event != NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Wait async I/O list is empty before execute sync I/O operation.\r
+ //\r
+ while (TRUE) {\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ if (IsListEmpty (&Private->Queue)) {\r
+ gBS->RestoreTPL (OldTpl);\r
+ break;\r
+ }\r
+ gBS->RestoreTPL (OldTpl);\r
+ }\r
+\r
+ Status = SdMmcWaitTrbEnv (Private, Trb);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = SdMmcExecTrb (Private, Trb);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = SdMmcWaitTrbResult (Private, Trb);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+Done:\r
+ if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) {\r
+ FreePages (Trb->AdmaDesc, Trb->AdmaPages);\r
+ }\r
+\r
+ if (Trb != NULL) {\r
+ FreePool (Trb);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Used to retrieve next slot numbers supported by the SD controller. The function\r
+ returns information about all available slots (populated or not-populated).\r
+\r
+ The GetNextSlot() function retrieves the next slot number on an SD controller.\r
+ If on input Slot is 0xFF, then the slot number of the first slot on the SD controller\r
+ is returned.\r
+\r
+ If Slot is a slot number that was returned on a previous call to GetNextSlot(), then\r
+ the slot number of the next slot on the SD controller is returned.\r
+\r
+ If Slot is not 0xFF and Slot was not returned on a previous call to GetNextSlot(),\r
+ EFI_INVALID_PARAMETER is returned.\r
+\r
+ If Slot is the slot number of the last slot on the SD controller, then EFI_NOT_FOUND\r
+ is returned.\r
+\r
+ @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in,out] Slot On input, a pointer to a slot number on the SD controller.\r
+ On output, a pointer to the next slot number on the SD controller.\r
+ An input value of 0xFF retrieves the first slot number on the SD\r
+ controller.\r
+\r
+ @retval EFI_SUCCESS The next slot number on the SD controller was returned in Slot.\r
+ @retval EFI_NOT_FOUND There are no more slots on this SD controller.\r
+ @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a previous call\r
+ to GetNextSlot().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruGetNextSlot (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,\r
+ IN OUT UINT8 *Slot\r
+ )\r
+{\r
+ SD_MMC_HC_PRIVATE_DATA *Private;\r
+ UINT8 Index;\r
+\r
+ if ((This == NULL) || (Slot == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);\r
+\r
+ if (*Slot == 0xFF) {\r
+ for (Index = 0; Index < SD_MMC_HC_MAX_SLOT; Index++) {\r
+ if (Private->Slot[Index].Enable) {\r
+ *Slot = Index;\r
+ Private->PreviousSlot = Index;\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ return EFI_NOT_FOUND;\r
+ } else if (*Slot == Private->PreviousSlot) {\r
+ for (Index = *Slot + 1; Index < SD_MMC_HC_MAX_SLOT; Index++) {\r
+ if (Private->Slot[Index].Enable) {\r
+ *Slot = Index;\r
+ Private->PreviousSlot = Index;\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ return EFI_NOT_FOUND;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+}\r
+\r
+/**\r
+ Used to allocate and build a device path node for an SD card on the SD controller.\r
+\r
+ The BuildDevicePath() function allocates and builds a single device node for the SD\r
+ card specified by Slot.\r
+\r
+ If the SD card specified by Slot is not present on the SD controller, then EFI_NOT_FOUND\r
+ is returned.\r
+\r
+ If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.\r
+\r
+ If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES\r
+ is returned.\r
+\r
+ Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of\r
+ DevicePath are initialized to describe the SD card specified by Slot, and EFI_SUCCESS is\r
+ returned.\r
+\r
+ @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot Specifies the slot number of the SD card for which a device\r
+ path node is to be allocated and built.\r
+ @param[in,out] DevicePath A pointer to a single device path node that describes the SD\r
+ card specified by Slot. This function is responsible for\r
+ allocating the buffer DevicePath with the boot service\r
+ AllocatePool(). It is the caller's responsibility to free\r
+ DevicePath when the caller is finished with DevicePath.\r
+\r
+ @retval EFI_SUCCESS The device path node that describes the SD card specified by\r
+ Slot was allocated and returned in DevicePath.\r
+ @retval EFI_NOT_FOUND The SD card specified by Slot does not exist on the SD controller.\r
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruBuildDevicePath (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,\r
+ IN UINT8 Slot,\r
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
+ )\r
+{\r
+ SD_MMC_HC_PRIVATE_DATA *Private;\r
+ SD_DEVICE_PATH *SdNode;\r
+ EMMC_DEVICE_PATH *EmmcNode;\r
+\r
+ if ((This == NULL) || (DevicePath == NULL) || (Slot >= SD_MMC_HC_MAX_SLOT)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);\r
+\r
+ if ((!Private->Slot[Slot].Enable) || (!Private->Slot[Slot].MediaPresent)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (Private->Slot[Slot].CardType == SdCardType) {\r
+ SdNode = AllocateCopyPool (sizeof (SD_DEVICE_PATH), &mSdDpTemplate);\r
+ if (SdNode == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ SdNode->SlotNumber = Slot;\r
+\r
+ *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) SdNode;\r
+ } else if (Private->Slot[Slot].CardType == EmmcCardType) {\r
+ EmmcNode = AllocateCopyPool (sizeof (EMMC_DEVICE_PATH), &mEmmcDpTemplate);\r
+ if (EmmcNode == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ EmmcNode->SlotNumber = Slot;\r
+\r
+ *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) EmmcNode;\r
+ } else {\r
+ //\r
+ // Currently we only support SD and EMMC two device nodes.\r
+ //\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function retrieves an SD card slot number based on the input device path.\r
+\r
+ The GetSlotNumber() function retrieves slot number for the SD card specified by\r
+ the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is returned.\r
+\r
+ If DevicePath is not a device path node type that the SD Pass Thru driver supports,\r
+ EFI_UNSUPPORTED is returned.\r
+\r
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] DevicePath A pointer to the device path node that describes a SD\r
+ card on the SD controller.\r
+ @param[out] Slot On return, points to the slot number of an SD card on\r
+ the SD controller.\r
+\r
+ @retval EFI_SUCCESS SD card slot number is returned in Slot.\r
+ @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.\r
+ @retval EFI_UNSUPPORTED DevicePath is not a device path node type that the SD\r
+ Pass Thru driver supports.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruGetSlotNumber (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ OUT UINT8 *Slot\r
+ )\r
+{\r
+ SD_MMC_HC_PRIVATE_DATA *Private;\r
+ SD_DEVICE_PATH *SdNode;\r
+ EMMC_DEVICE_PATH *EmmcNode;\r
+ UINT8 SlotNumber;\r
+\r
+ if ((This == NULL) || (DevicePath == NULL) || (Slot == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);\r
+\r
+ //\r
+ // Check whether the DevicePath belongs to SD_DEVICE_PATH or EMMC_DEVICE_PATH\r
+ //\r
+ if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||\r
+ ((DevicePath->SubType != MSG_SD_DP) &&\r
+ (DevicePath->SubType != MSG_EMMC_DP)) ||\r
+ (DevicePathNodeLength(DevicePath) != sizeof(SD_DEVICE_PATH)) ||\r
+ (DevicePathNodeLength(DevicePath) != sizeof(EMMC_DEVICE_PATH))) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (DevicePath->SubType == MSG_SD_DP) {\r
+ SdNode = (SD_DEVICE_PATH *) DevicePath;\r
+ SlotNumber = SdNode->SlotNumber;\r
+ } else {\r
+ EmmcNode = (EMMC_DEVICE_PATH *) DevicePath;\r
+ SlotNumber = EmmcNode->SlotNumber;\r
+ }\r
+\r
+ if (SlotNumber >= SD_MMC_HC_MAX_SLOT) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (Private->Slot[SlotNumber].Enable) {\r
+ *Slot = SlotNumber;\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+}\r
+\r
+/**\r
+ Resets an SD card that is connected to the SD controller.\r
+\r
+ The ResetDevice() function resets the SD card specified by Slot.\r
+\r
+ If this SD controller does not support a device reset operation, EFI_UNSUPPORTED is\r
+ returned.\r
+\r
+ If Slot is not in a valid slot number for this SD controller, EFI_INVALID_PARAMETER\r
+ is returned.\r
+\r
+ If the device reset operation is completed, EFI_SUCCESS is returned.\r
+\r
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot Specifies the slot number of the SD card to be reset.\r
+\r
+ @retval EFI_SUCCESS The SD card specified by Slot was reset.\r
+ @retval EFI_UNSUPPORTED The SD controller does not support a device reset operation.\r
+ @retval EFI_INVALID_PARAMETER Slot number is invalid.\r
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.\r
+ @retval EFI_DEVICE_ERROR The reset command failed due to a device error\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruResetDevice (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,\r
+ IN UINT8 Slot\r
+ )\r
+{\r
+ SD_MMC_HC_PRIVATE_DATA *Private;\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *NextLink;\r
+ SD_MMC_HC_TRB *Trb;\r
+ EFI_TPL OldTpl;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);\r
+\r
+ if (!Private->Slot[Slot].Enable) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!Private->Slot[Slot].MediaPresent) {\r
+ return EFI_NO_MEDIA;\r
+ }\r
+ //\r
+ // Free all async I/O requests in the queue\r
+ //\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ for (Link = GetFirstNode (&Private->Queue);\r
+ !IsNull (&Private->Queue, Link);\r
+ Link = NextLink) {\r
+ NextLink = GetNextNode (&Private->Queue, Link);\r
+ RemoveEntryList (Link);\r
+ Trb = SD_MMC_HC_TRB_FROM_THIS (Link);\r
+ Trb->Packet->TransactionStatus = EFI_ABORTED;\r
+ gBS->SignalEvent (Trb->Event);\r
+ SdMmcFreeTrb (Trb);\r
+ }\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+\r
+ Provides some data structure definitions used by the SD/MMC host controller driver.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_MMC_PCI_HC_DXE_H_\r
+#define _SD_MMC_PCI_HC_DXE_H_\r
+\r
+#include <Uefi.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+#include <IndustryStandard/Emmc.h>\r
+#include <IndustryStandard/Sd.h>\r
+\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/DevicePathLib.h>\r
+\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/DriverBinding.h>\r
+#include <Protocol/ComponentName.h>\r
+#include <Protocol/ComponentName2.h>\r
+#include <Protocol/SdMmcPassThru.h>\r
+\r
+#include "SdMmcPciHci.h"\r
+\r
+extern EFI_COMPONENT_NAME_PROTOCOL gSdMmcPciHcComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL gSdMmcPciHcComponentName2;\r
+extern EFI_DRIVER_BINDING_PROTOCOL gSdMmcPciHcDriverBinding;\r
+\r
+#define SD_MMC_HC_PRIVATE_SIGNATURE SIGNATURE_32 ('s', 'd', 't', 'f')\r
+\r
+#define SD_MMC_HC_PRIVATE_FROM_THIS(a) \\r
+ CR(a, SD_MMC_HC_PRIVATE_DATA, PassThru, SD_MMC_HC_PRIVATE_SIGNATURE)\r
+\r
+//\r
+// Generic time out value, 1 microsecond as unit.\r
+//\r
+#define SD_MMC_HC_GENERIC_TIMEOUT 1 * 1000 * 1000\r
+\r
+//\r
+// SD/MMC async transfer timer interval, set by experience.\r
+// The unit is 100us, takes 1ms as interval.\r
+//\r
+#define SD_MMC_HC_ASYNC_TIMER EFI_TIMER_PERIOD_MILLISECONDS(1)\r
+//\r
+// SD/MMC removable device enumeration timer interval, set by experience.\r
+// The unit is 100us, takes 100ms as interval.\r
+//\r
+#define SD_MMC_HC_ENUM_TIMER EFI_TIMER_PERIOD_MILLISECONDS(100)\r
+\r
+typedef enum {\r
+ UnknownCardType,\r
+ SdCardType,\r
+ SdioCardType,\r
+ MmcCardType,\r
+ EmmcCardType\r
+} SD_MMC_CARD_TYPE;\r
+\r
+typedef enum {\r
+ RemovableSlot,\r
+ EmbeddedSlot,\r
+ SharedBusSlot,\r
+ UnknownSlot\r
+} EFI_SD_MMC_SLOT_TYPE;\r
+\r
+typedef struct {\r
+ BOOLEAN Enable;\r
+ EFI_SD_MMC_SLOT_TYPE SlotType;\r
+ BOOLEAN MediaPresent;\r
+ SD_MMC_CARD_TYPE CardType;\r
+} SD_MMC_HC_SLOT;\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+\r
+ EFI_HANDLE ControllerHandle;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL PassThru;\r
+\r
+ UINT64 PciAttributes;\r
+ //\r
+ // The field is used to record the previous slot in GetNextSlot().\r
+ //\r
+ UINT8 PreviousSlot;\r
+ //\r
+ // For Non-blocking operation.\r
+ //\r
+ EFI_EVENT TimerEvent;\r
+ //\r
+ // For Sd removable device enumeration.\r
+ //\r
+ EFI_EVENT ConnectEvent;\r
+ LIST_ENTRY Queue;\r
+\r
+ SD_MMC_HC_SLOT Slot[SD_MMC_HC_MAX_SLOT];\r
+ SD_MMC_HC_SLOT_CAP Capability[SD_MMC_HC_MAX_SLOT];\r
+ UINT64 MaxCurrent[SD_MMC_HC_MAX_SLOT];\r
+\r
+ UINT32 ControllerVersion;\r
+} SD_MMC_HC_PRIVATE_DATA;\r
+\r
+#define SD_MMC_HC_TRB_SIG SIGNATURE_32 ('T', 'R', 'B', 'T')\r
+\r
+//\r
+// TRB (Transfer Request Block) contains information for the cmd request.\r
+//\r
+typedef struct {\r
+ UINT32 Signature;\r
+ LIST_ENTRY TrbList;\r
+\r
+ UINT8 Slot;\r
+ UINT16 BlockSize;\r
+\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
+ VOID *Data;\r
+ UINT32 DataLen;\r
+ BOOLEAN Read;\r
+ EFI_PHYSICAL_ADDRESS DataPhy;\r
+ VOID *DataMap;\r
+ SD_MMC_HC_TRANSFER_MODE Mode;\r
+\r
+ EFI_EVENT Event;\r
+ BOOLEAN Started;\r
+ UINT64 Timeout;\r
+\r
+ SD_MMC_HC_ADMA_DESC_LINE *AdmaDesc;\r
+ EFI_PHYSICAL_ADDRESS AdmaDescPhy;\r
+ VOID *AdmaMap;\r
+ UINT32 AdmaPages;\r
+\r
+ SD_MMC_HC_PRIVATE_DATA *Private;\r
+} SD_MMC_HC_TRB;\r
+\r
+#define SD_MMC_HC_TRB_FROM_THIS(a) \\r
+ CR(a, SD_MMC_HC_TRB, TrbList, SD_MMC_HC_TRB_SIG)\r
+\r
+//\r
+// Task for Non-blocking mode.\r
+//\r
+typedef struct {\r
+ UINT32 Signature;\r
+ LIST_ENTRY Link;\r
+\r
+ UINT8 Slot;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
+ BOOLEAN IsStart;\r
+ EFI_EVENT Event;\r
+ UINT64 RetryTimes;\r
+ BOOLEAN InfiniteWait;\r
+ VOID *Map;\r
+ VOID *MapAddress;\r
+} SD_MMC_HC_QUEUE;\r
+\r
+//\r
+// Prototypes\r
+//\r
+/**\r
+ Execute card identification procedure.\r
+\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The card is identified correctly.\r
+ @retval Others The card can't be identified.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(*CARD_TYPE_DETECT_ROUTINE) (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN UINT8 Slot\r
+ );\r
+\r
+/**\r
+ Sends SD command to an SD card that is attached to the SD controller.\r
+\r
+ The PassThru() function sends the SD command specified by Packet to the SD card\r
+ specified by Slot.\r
+\r
+ If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.\r
+\r
+ If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.\r
+\r
+ If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER\r
+ is returned.\r
+\r
+ If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,\r
+ EFI_INVALID_PARAMETER is returned.\r
+\r
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in,out] Packet A pointer to the SD command data structure.\r
+ @param[in] Event If Event is NULL, blocking I/O is performed. If Event is\r
+ not NULL, then nonblocking I/O is performed, and Event\r
+ will be signaled when the Packet completes.\r
+\r
+ @retval EFI_SUCCESS The SD Command Packet was sent by the host.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD\r
+ command Packet.\r
+ @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.\r
+ @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and\r
+ OutDataBuffer are NULL.\r
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.\r
+ @retval EFI_UNSUPPORTED The command described by the SD Command Packet is not\r
+ supported by the host controller.\r
+ @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the\r
+ limit supported by SD card ( i.e. if the number of bytes\r
+ exceed the Last LBA).\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruPassThru (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,\r
+ IN UINT8 Slot,\r
+ IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,\r
+ IN EFI_EVENT Event OPTIONAL\r
+ );\r
+\r
+/**\r
+ Used to retrieve next slot numbers supported by the SD controller. The function\r
+ returns information about all available slots (populated or not-populated).\r
+\r
+ The GetNextSlot() function retrieves the next slot number on an SD controller.\r
+ If on input Slot is 0xFF, then the slot number of the first slot on the SD controller\r
+ is returned.\r
+\r
+ If Slot is a slot number that was returned on a previous call to GetNextSlot(), then\r
+ the slot number of the next slot on the SD controller is returned.\r
+\r
+ If Slot is not 0xFF and Slot was not returned on a previous call to GetNextSlot(),\r
+ EFI_INVALID_PARAMETER is returned.\r
+\r
+ If Slot is the slot number of the last slot on the SD controller, then EFI_NOT_FOUND\r
+ is returned.\r
+\r
+ @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in,out] Slot On input, a pointer to a slot number on the SD controller.\r
+ On output, a pointer to the next slot number on the SD controller.\r
+ An input value of 0xFF retrieves the first slot number on the SD\r
+ controller.\r
+\r
+ @retval EFI_SUCCESS The next slot number on the SD controller was returned in Slot.\r
+ @retval EFI_NOT_FOUND There are no more slots on this SD controller.\r
+ @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a previous call\r
+ to GetNextSlot().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruGetNextSlot (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,\r
+ IN OUT UINT8 *Slot\r
+ );\r
+\r
+/**\r
+ Used to allocate and build a device path node for an SD card on the SD controller.\r
+\r
+ The BuildDevicePath() function allocates and builds a single device node for the SD\r
+ card specified by Slot.\r
+\r
+ If the SD card specified by Slot is not present on the SD controller, then EFI_NOT_FOUND\r
+ is returned.\r
+\r
+ If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.\r
+\r
+ If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES\r
+ is returned.\r
+\r
+ Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of\r
+ DevicePath are initialized to describe the SD card specified by Slot, and EFI_SUCCESS is\r
+ returned.\r
+\r
+ @param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot Specifies the slot number of the SD card for which a device\r
+ path node is to be allocated and built.\r
+ @param[in,out] DevicePath A pointer to a single device path node that describes the SD\r
+ card specified by Slot. This function is responsible for\r
+ allocating the buffer DevicePath with the boot service\r
+ AllocatePool(). It is the caller's responsibility to free\r
+ DevicePath when the caller is finished with DevicePath.\r
+\r
+ @retval EFI_SUCCESS The device path node that describes the SD card specified by\r
+ Slot was allocated and returned in DevicePath.\r
+ @retval EFI_NOT_FOUND The SD card specified by Slot does not exist on the SD controller.\r
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruBuildDevicePath (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,\r
+ IN UINT8 Slot,\r
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
+ );\r
+\r
+/**\r
+ This function retrieves an SD card slot number based on the input device path.\r
+\r
+ The GetSlotNumber() function retrieves slot number for the SD card specified by\r
+ the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is returned.\r
+\r
+ If DevicePath is not a device path node type that the SD Pass Thru driver supports,\r
+ EFI_UNSUPPORTED is returned.\r
+\r
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] DevicePath A pointer to the device path node that describes a SD\r
+ card on the SD controller.\r
+ @param[out] Slot On return, points to the slot number of an SD card on\r
+ the SD controller.\r
+\r
+ @retval EFI_SUCCESS SD card slot number is returned in Slot.\r
+ @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.\r
+ @retval EFI_UNSUPPORTED DevicePath is not a device path node type that the SD\r
+ Pass Thru driver supports.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruGetSlotNumber (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ OUT UINT8 *Slot\r
+ );\r
+\r
+/**\r
+ Resets an SD card that is connected to the SD controller.\r
+\r
+ The ResetDevice() function resets the SD card specified by Slot.\r
+\r
+ If this SD controller does not support a device reset operation, EFI_UNSUPPORTED is\r
+ returned.\r
+\r
+ If Slot is not in a valid slot number for this SD controller, EFI_INVALID_PARAMETER\r
+ is returned.\r
+\r
+ If the device reset operation is completed, EFI_SUCCESS is returned.\r
+\r
+ @param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot Specifies the slot number of the SD card to be reset.\r
+\r
+ @retval EFI_SUCCESS The SD card specified by Slot was reset.\r
+ @retval EFI_UNSUPPORTED The SD controller does not support a device reset operation.\r
+ @retval EFI_INVALID_PARAMETER Slot number is invalid.\r
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.\r
+ @retval EFI_DEVICE_ERROR The reset command failed due to a device error\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruResetDevice (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,\r
+ IN UINT8 Slot\r
+ );\r
+\r
+//\r
+// Driver model protocol interfaces\r
+//\r
+/**\r
+ Tests to see if this driver supports a given controller. If a child device is provided,\r
+ it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+ This function checks to see if the driver specified by This supports the device specified by\r
+ ControllerHandle. Drivers will typically use the device path attached to\r
+ ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+ ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+ may be called many times during platform initialization. In order to reduce boot times, the tests\r
+ performed by this function must be very small, and take as little time as possible to execute. This\r
+ function must not change the state of any hardware devices, and this function must be aware that the\r
+ device specified by ControllerHandle may already be managed by the same driver or a\r
+ different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+ to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to test. This handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For bus drivers, if this parameter is not NULL, then\r
+ the bus driver must determine if the bus controller specified\r
+ by ControllerHandle and the child controller specified\r
+ by RemainingDevicePath are both supported by this\r
+ bus driver.\r
+\r
+ @retval EFI_SUCCESS The device specified by ControllerHandle and\r
+ RemainingDevicePath is supported by the driver specified by This.\r
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by the driver\r
+ specified by This.\r
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by a different\r
+ driver or an application that requires exclusive access.\r
+ Currently not implemented.\r
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Starts a device controller or a bus controller.\r
+\r
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+ As a result, much of the error checking on the parameters to Start() has been moved into this\r
+ common boot service. It is legal to call Start() from other locations,\r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE.\r
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+ EFI_DEVICE_PATH_PROTOCOL.\r
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to start. This handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For a bus driver, if this parameter is NULL, then handles\r
+ for all the children of Controller are created by this driver.\r
+ If this parameter is not NULL and the first Device Path Node is\r
+ not the End of Device Path Node, then only the handle for the\r
+ child device specified by the first Device Path Node of\r
+ RemainingDevicePath is created by this driver.\r
+ If the first Device Path Node of RemainingDevicePath is\r
+ the End of Device Path Node, no child handle is created by this\r
+ driver.\r
+\r
+ @retval EFI_SUCCESS The device was started.\r
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval Others The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Stops a device controller or a bus controller.\r
+\r
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+ As a result, much of the error checking on the parameters to Stop() has been moved\r
+ into this common boot service. It is legal to call Stop() from other locations,\r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+ same driver's Start() function.\r
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+ Start() function, and the Start() function must have called OpenProtocol() on\r
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must\r
+ support a bus specific I/O protocol for the driver\r
+ to use to stop the device.\r
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+ if NumberOfChildren is 0.\r
+\r
+ @retval EFI_SUCCESS The device was stopped.\r
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ );\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle, OPTIONAL\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ );\r
+\r
+/**\r
+ Create a new TRB for the SD/MMC cmd request.\r
+\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Packet A pointer to the SD command data structure.\r
+ @param[in] Event If Event is NULL, blocking I/O is performed. If Event is\r
+ not NULL, then nonblocking I/O is performed, and Event\r
+ will be signaled when the Packet completes.\r
+\r
+ @return Created Trb or NULL.\r
+\r
+**/\r
+SD_MMC_HC_TRB *\r
+SdMmcCreateTrb (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN UINT8 Slot,\r
+ IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,\r
+ IN EFI_EVENT Event\r
+ );\r
+\r
+/**\r
+ Free the resource used by the TRB.\r
+\r
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+**/\r
+VOID\r
+SdMmcFreeTrb (\r
+ IN SD_MMC_HC_TRB *Trb\r
+ );\r
+\r
+/**\r
+ Check if the env is ready for execute specified TRB.\r
+\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The env is ready for TRB execution.\r
+ @retval EFI_NOT_READY The env is not ready for TRB execution.\r
+ @retval Others Some erros happen.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcCheckTrbEnv (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN SD_MMC_HC_TRB *Trb\r
+ );\r
+\r
+/**\r
+ Wait for the env to be ready for execute specified TRB.\r
+\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The env is ready for TRB execution.\r
+ @retval EFI_TIMEOUT The env is not ready for TRB execution in time.\r
+ @retval Others Some erros happen.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcWaitTrbEnv (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN SD_MMC_HC_TRB *Trb\r
+ );\r
+\r
+/**\r
+ Execute the specified TRB.\r
+\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The TRB is sent to host controller successfully.\r
+ @retval Others Some erros happen when sending this request to the host controller.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcExecTrb (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN SD_MMC_HC_TRB *Trb\r
+ );\r
+\r
+/**\r
+ Check the TRB execution result.\r
+\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The TRB is executed successfully.\r
+ @retval EFI_NOT_READY The TRB is not completed for execution.\r
+ @retval Others Some erros happen when executing this request.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcCheckTrbResult (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN SD_MMC_HC_TRB *Trb\r
+ );\r
+\r
+/**\r
+ Wait for the TRB execution result.\r
+\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The TRB is executed successfully.\r
+ @retval Others Some erros happen when executing this request.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcWaitTrbResult (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN SD_MMC_HC_TRB *Trb\r
+ );\r
+\r
+/**\r
+ Execute EMMC device identification procedure.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS There is a EMMC card.\r
+ @retval Others There is not a EMMC card.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcIdentification (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN UINT8 Slot\r
+ );\r
+\r
+/**\r
+ Execute EMMC device identification procedure.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS There is a EMMC card.\r
+ @retval Others There is not a EMMC card.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardIdentification (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN UINT8 Slot\r
+ );\r
+\r
+#endif\r
--- /dev/null
+## @file\r
+# SdMmcPciHcDxe driver is used to manage those host controllers which comply with SD\r
+# Host Controller Simplified Specifiction version 3.0.\r
+#\r
+# It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC/eMMC cmds\r
+# to specified devices from upper layer.\r
+#\r
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = SdMmcPciHcDxe\r
+ MODULE_UNI_FILE = SdMmcPciHcDxe.uni\r
+ FILE_GUID = 8E325979-3FE1-4927-AAE2-8F5C4BD2AF0D\r
+ MODULE_TYPE = UEFI_DRIVER\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = InitializeSdMmcPciHcDxe\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+# DRIVER_BINDING = gSdMmcPciHcDxeDriverBinding\r
+# COMPONENT_NAME = gSdMmcPciHcDxeComponentName\r
+# COMPONENT_NAME2 = gSdMmcPciHcDxeComponentName2\r
+#\r
+#\r
+\r
+[Sources]\r
+ SdMmcPciHcDxe.h\r
+ SdMmcPciHcDxe.c\r
+ EmmcDevice.c\r
+ SdDevice.c\r
+ SdMmcPciHci.h\r
+ SdMmcPciHci.c\r
+ ComponentName.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+ DevicePathLib\r
+ UefiBootServicesTableLib\r
+ UefiRuntimeServicesTableLib\r
+ MemoryAllocationLib\r
+ BaseMemoryLib\r
+ UefiLib\r
+ BaseLib\r
+ UefiDriverEntryPoint\r
+ DebugLib\r
+\r
+[Protocols]\r
+ gEfiDevicePathProtocolGuid ## TO_START\r
+ gEfiPciIoProtocolGuid ## TO_START\r
+ gEfiSdMmcPassThruProtocolGuid ## BY_START\r
+\r
+# [Event]\r
+# EVENT_TYPE_PERIODIC_TIMER ## SOMETIMES_CONSUMES\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+ SdMmcPciHcDxeExtra.uni\r
--- /dev/null
+// /** @file\r
+// SdMmcPciHcDxe driver is used to manage those host controllers which comply with SD\r
+// Host Controller Simplified Specifiction version 3.0.\r
+//\r
+// It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC/eMMC cmds\r
+// to specified devices from upper layer.\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "SD/MMC Pci Host Controller driver to manage SD/MMC host controllers"\r
+\r
+#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."\r
+\r
--- /dev/null
+// /** @file\r
+// SdMmcPciHcDxe Localized Strings and Content\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+#string STR_PROPERTIES_MODULE_NAME\r
+#language en-US\r
+"SD/MMC Pci Host Controller Driver"\r
+\r
+\r
--- /dev/null
+/** @file\r
+ This driver is used to manage SD/MMC PCI host controllers which are compliance\r
+ with SD Host Controller Simplified Specification version 3.00.\r
+\r
+ It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.\r
+\r
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdMmcPciHcDxe.h"\r
+\r
+/**\r
+ Dump the content of SD/MMC host controller's Capability Register.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Capability The buffer to store the capability data.\r
+\r
+**/\r
+VOID\r
+DumpCapabilityReg (\r
+ IN UINT8 Slot,\r
+ IN SD_MMC_HC_SLOT_CAP *Capability\r
+ )\r
+{\r
+ //\r
+ // Dump Capability Data\r
+ //\r
+ DEBUG ((EFI_D_INFO, " == Slot [%d] Capability is 0x%x ==\n", Slot, Capability));\r
+ DEBUG ((EFI_D_INFO, " Timeout Clk Freq %d%a\n", Capability->TimeoutFreq, (Capability->TimeoutUnit) ? "MHz" : "KHz"));\r
+ DEBUG ((EFI_D_INFO, " Base Clk Freq %dMHz\n", Capability->BaseClkFreq));\r
+ DEBUG ((EFI_D_INFO, " Max Blk Len %dbytes\n", 512 * (1 << Capability->MaxBlkLen)));\r
+ DEBUG ((EFI_D_INFO, " 8-bit Support %a\n", Capability->BusWidth8 ? "TRUE" : "FALSE"));\r
+ DEBUG ((EFI_D_INFO, " ADMA2 Support %a\n", Capability->Adma2 ? "TRUE" : "FALSE"));\r
+ DEBUG ((EFI_D_INFO, " HighSpeed Support %a\n", Capability->HighSpeed ? "TRUE" : "FALSE"));\r
+ DEBUG ((EFI_D_INFO, " SDMA Support %a\n", Capability->Sdma ? "TRUE" : "FALSE"));\r
+ DEBUG ((EFI_D_INFO, " Suspend/Resume %a\n", Capability->SuspRes ? "TRUE" : "FALSE"));\r
+ DEBUG ((EFI_D_INFO, " Voltage 3.3 %a\n", Capability->Voltage33 ? "TRUE" : "FALSE"));\r
+ DEBUG ((EFI_D_INFO, " Voltage 3.0 %a\n", Capability->Voltage30 ? "TRUE" : "FALSE"));\r
+ DEBUG ((EFI_D_INFO, " Voltage 1.8 %a\n", Capability->Voltage18 ? "TRUE" : "FALSE"));\r
+ DEBUG ((EFI_D_INFO, " 64-bit Sys Bus %a\n", Capability->SysBus64 ? "TRUE" : "FALSE"));\r
+ DEBUG ((EFI_D_INFO, " Async Interrupt %a\n", Capability->AsyncInt ? "TRUE" : "FALSE"));\r
+ DEBUG ((EFI_D_INFO, " SlotType "));\r
+ if (Capability->SlotType == 0x00) {\r
+ DEBUG ((EFI_D_INFO, "%a\n", "Removable Slot"));\r
+ } else if (Capability->SlotType == 0x01) {\r
+ DEBUG ((EFI_D_INFO, "%a\n", "Embedded Slot"));\r
+ } else if (Capability->SlotType == 0x02) {\r
+ DEBUG ((EFI_D_INFO, "%a\n", "Shared Bus Slot"));\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "%a\n", "Reserved"));\r
+ }\r
+ DEBUG ((EFI_D_INFO, " SDR50 Support %a\n", Capability->Sdr50 ? "TRUE" : "FALSE"));\r
+ DEBUG ((EFI_D_INFO, " SDR104 Support %a\n", Capability->Sdr104 ? "TRUE" : "FALSE"));\r
+ DEBUG ((EFI_D_INFO, " DDR50 Support %a\n", Capability->Ddr50 ? "TRUE" : "FALSE"));\r
+ DEBUG ((EFI_D_INFO, " Driver Type A %a\n", Capability->DriverTypeA ? "TRUE" : "FALSE"));\r
+ DEBUG ((EFI_D_INFO, " Driver Type C %a\n", Capability->DriverTypeC ? "TRUE" : "FALSE"));\r
+ DEBUG ((EFI_D_INFO, " Driver Type D %a\n", Capability->DriverTypeD ? "TRUE" : "FALSE"));\r
+ DEBUG ((EFI_D_INFO, " Driver Type 4 %a\n", Capability->DriverType4 ? "TRUE" : "FALSE"));\r
+ if (Capability->TimerCount == 0) {\r
+ DEBUG ((EFI_D_INFO, " Retuning TimerCnt Disabled\n", 2 * (Capability->TimerCount - 1)));\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, " Retuning TimerCnt %dseconds\n", 2 * (Capability->TimerCount - 1)));\r
+ }\r
+ DEBUG ((EFI_D_INFO, " SDR50 Tuning %a\n", Capability->TuningSDR50 ? "TRUE" : "FALSE"));\r
+ DEBUG ((EFI_D_INFO, " Retuning Mode Mode %d\n", Capability->RetuningMod + 1));\r
+ DEBUG ((EFI_D_INFO, " Clock Multiplier M = %d\n", Capability->ClkMultiplier + 1));\r
+ DEBUG ((EFI_D_INFO, " HS 400 %a\n", Capability->Hs400 ? "TRUE" : "FALSE"));\r
+ return;\r
+}\r
+\r
+/**\r
+ Read SlotInfo register from SD/MMC host controller pci config space.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[out] FirstBar The buffer to store the first BAR value.\r
+ @param[out] SlotNum The buffer to store the supported slot number.\r
+\r
+ @retval EFI_SUCCESS The operation succeeds.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcGetSlotInfo (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ OUT UINT8 *FirstBar,\r
+ OUT UINT8 *SlotNum\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_MMC_HC_SLOT_INFO SlotInfo;\r
+\r
+ Status = PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ SD_MMC_HC_SLOT_OFFSET,\r
+ sizeof (SlotInfo),\r
+ &SlotInfo\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ *FirstBar = SlotInfo.FirstBar;\r
+ *SlotNum = SlotInfo.SlotNum + 1;\r
+ ASSERT ((*FirstBar + *SlotNum) < SD_MMC_HC_MAX_SLOT);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read/Write specified SD/MMC host controller mmio register.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] BarIndex The BAR index of the standard PCI Configuration\r
+ header to use as the base address for the memory\r
+ operation to perform.\r
+ @param[in] Offset The offset within the selected BAR to start the\r
+ memory operation.\r
+ @param[in] Read A boolean to indicate it's read or write operation.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2 , 4 or 8 bytes.\r
+ @param[in, out] Data For read operations, the destination buffer to store\r
+ the results. For write operations, the source buffer\r
+ to write data from. The caller is responsible for\r
+ having ownership of the data buffer and ensuring its\r
+ size not less than Count bytes.\r
+\r
+ @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid.\r
+ @retval EFI_SUCCESS The read/write operation succeeds.\r
+ @retval Others The read/write operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcRwMmio (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 BarIndex,\r
+ IN UINT32 Offset,\r
+ IN BOOLEAN Read,\r
+ IN UINT8 Count,\r
+ IN OUT VOID *Data\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if ((PciIo == NULL) || (Data == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Read) {\r
+ Status = PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ BarIndex,\r
+ (UINT64) Offset,\r
+ Count,\r
+ Data\r
+ );\r
+ } else {\r
+ Status = PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ BarIndex,\r
+ (UINT64) Offset,\r
+ Count,\r
+ Data\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Do OR operation with the value of the specified SD/MMC host controller mmio register.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] BarIndex The BAR index of the standard PCI Configuration\r
+ header to use as the base address for the memory\r
+ operation to perform.\r
+ @param[in] Offset The offset within the selected BAR to start the\r
+ memory operation.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2 , 4 or 8 bytes.\r
+ @param[in] OrData The pointer to the data used to do OR operation.\r
+ The caller is responsible for having ownership of\r
+ the data buffer and ensuring its size not less than\r
+ Count bytes.\r
+\r
+ @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid.\r
+ @retval EFI_SUCCESS The OR operation succeeds.\r
+ @retval Others The OR operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcOrMmio (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 BarIndex,\r
+ IN UINT32 Offset,\r
+ IN UINT8 Count,\r
+ IN VOID *OrData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 Data;\r
+ UINT64 Or;\r
+\r
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Data);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Count == 1) {\r
+ Or = *(UINT8*) OrData;\r
+ } else if (Count == 2) {\r
+ Or = *(UINT16*) OrData;\r
+ } else if (Count == 4) {\r
+ Or = *(UINT32*) OrData;\r
+ } else if (Count == 8) {\r
+ Or = *(UINT64*) OrData;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Data |= Or;\r
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, FALSE, Count, &Data);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Do AND operation with the value of the specified SD/MMC host controller mmio register.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] BarIndex The BAR index of the standard PCI Configuration\r
+ header to use as the base address for the memory\r
+ operation to perform.\r
+ @param[in] Offset The offset within the selected BAR to start the\r
+ memory operation.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2 , 4 or 8 bytes.\r
+ @param[in] AndData The pointer to the data used to do AND operation.\r
+ The caller is responsible for having ownership of\r
+ the data buffer and ensuring its size not less than\r
+ Count bytes.\r
+\r
+ @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid.\r
+ @retval EFI_SUCCESS The AND operation succeeds.\r
+ @retval Others The AND operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcAndMmio (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 BarIndex,\r
+ IN UINT32 Offset,\r
+ IN UINT8 Count,\r
+ IN VOID *AndData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 Data;\r
+ UINT64 And;\r
+\r
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Data);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Count == 1) {\r
+ And = *(UINT8*) AndData;\r
+ } else if (Count == 2) {\r
+ And = *(UINT16*) AndData;\r
+ } else if (Count == 4) {\r
+ And = *(UINT32*) AndData;\r
+ } else if (Count == 8) {\r
+ And = *(UINT64*) AndData;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Data &= And;\r
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, FALSE, Count, &Data);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Wait for the value of the specified MMIO register set to the test value.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] BarIndex The BAR index of the standard PCI Configuration\r
+ header to use as the base address for the memory\r
+ operation to perform.\r
+ @param[in] Offset The offset within the selected BAR to start the\r
+ memory operation.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2, 4 or 8 bytes.\r
+ @param[in] MaskValue The mask value of memory.\r
+ @param[in] TestValue The test value of memory.\r
+\r
+ @retval EFI_NOT_READY The MMIO register hasn't set to the expected value.\r
+ @retval EFI_SUCCESS The MMIO register has expected value.\r
+ @retval Others The MMIO operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcCheckMmioSet (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 BarIndex,\r
+ IN UINT32 Offset,\r
+ IN UINT8 Count,\r
+ IN UINT64 MaskValue,\r
+ IN UINT64 TestValue\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 Value;\r
+\r
+ //\r
+ // Access PCI MMIO space to see if the value is the tested one.\r
+ //\r
+ Value = 0;\r
+ Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Value &= MaskValue;\r
+\r
+ if (Value == TestValue) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return EFI_NOT_READY;\r
+}\r
+\r
+/**\r
+ Wait for the value of the specified MMIO register set to the test value.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] BarIndex The BAR index of the standard PCI Configuration\r
+ header to use as the base address for the memory\r
+ operation to perform.\r
+ @param[in] Offset The offset within the selected BAR to start the\r
+ memory operation.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2, 4 or 8 bytes.\r
+ @param[in] MaskValue The mask value of memory.\r
+ @param[in] TestValue The test value of memory.\r
+ @param[in] Timeout The time out value for wait memory set, uses 1\r
+ microsecond as a unit.\r
+\r
+ @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout\r
+ range.\r
+ @retval EFI_SUCCESS The MMIO register has expected value.\r
+ @retval Others The MMIO operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcWaitMmioSet (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 BarIndex,\r
+ IN UINT32 Offset,\r
+ IN UINT8 Count,\r
+ IN UINT64 MaskValue,\r
+ IN UINT64 TestValue,\r
+ IN UINT64 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN InfiniteWait;\r
+\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
+\r
+ while (InfiniteWait || (Timeout > 0)) {\r
+ Status = SdMmcHcCheckMmioSet (\r
+ PciIo,\r
+ BarIndex,\r
+ Offset,\r
+ Count,\r
+ MaskValue,\r
+ TestValue\r
+ );\r
+ if (Status != EFI_NOT_READY) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Stall for 1 microsecond.\r
+ //\r
+ gBS->Stall (1);\r
+\r
+ Timeout--;\r
+ }\r
+\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+ Software reset the specified SD/MMC host controller and enable all interrupts.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The software reset executes successfully.\r
+ @retval Others The software reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcReset (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 SwReset;\r
+\r
+ SwReset = 0xFF;\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdMmcHcReset: write full 1 fails: %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ Status = SdMmcHcWaitMmioSet (\r
+ PciIo,\r
+ Slot,\r
+ SD_MMC_HC_SW_RST,\r
+ sizeof (SwReset),\r
+ 0xFF,\r
+ 0x00,\r
+ SD_MMC_HC_GENERIC_TIMEOUT\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "SdMmcHcReset: reset done with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Enable all interrupt after reset all.\r
+ //\r
+ Status = SdMmcHcEnableInterrupt (PciIo, Slot);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set all interrupt status bits in Normal and Error Interrupt Status Enable\r
+ register.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The operation executes successfully.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcEnableInterrupt (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 IntStatus;\r
+\r
+ //\r
+ // Enable all bits in Error Interrupt Status Enable Register\r
+ //\r
+ IntStatus = 0xFFFF;\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_ERR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Enable all bits in Normal Interrupt Status Enable Register\r
+ //\r
+ IntStatus = 0xFFFF;\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get the capability data from the specified slot.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[out] Capability The buffer to store the capability data.\r
+\r
+ @retval EFI_SUCCESS The operation executes successfully.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcGetCapability (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ OUT SD_MMC_HC_SLOT_CAP *Capability\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 Cap;\r
+\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CAP, TRUE, sizeof (Cap), &Cap);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ CopyMem (Capability, &Cap, sizeof (Cap));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get the maximum current capability data from the specified slot.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[out] MaxCurrent The buffer to store the maximum current capability data.\r
+\r
+ @retval EFI_SUCCESS The operation executes successfully.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcGetMaxCurrent (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ OUT UINT64 *MaxCurrent\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_MAX_CURRENT_CAP, TRUE, sizeof (UINT64), MaxCurrent);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller\r
+ slot.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[out] MediaPresent The pointer to the media present boolean value.\r
+\r
+ @retval EFI_SUCCESS There is no media change happened.\r
+ @retval EFI_MEDIA_CHANGED There is media change happened.\r
+ @retval Others The detection fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcCardDetect (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ OUT BOOLEAN *MediaPresent\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 Data;\r
+ UINT32 PresentState;\r
+\r
+ //\r
+ // Check Normal Interrupt Status Register\r
+ //\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS, TRUE, sizeof (Data), &Data);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((Data & (BIT6 | BIT7)) != 0) {\r
+ //\r
+ // Clear BIT6 and BIT7 by writing 1 to these two bits if set.\r
+ //\r
+ Data &= BIT6 | BIT7;\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (Data), &Data);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Check Present State Register to see if there is a card presented.\r
+ //\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((PresentState & BIT16) != 0) {\r
+ *MediaPresent = TRUE;\r
+ } else {\r
+ *MediaPresent = FALSE;\r
+ }\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Stop SD/MMC card clock.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS Succeed to stop SD/MMC clock.\r
+ @retval Others Fail to stop SD/MMC clock.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcStopClock (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 PresentState;\r
+ UINT16 ClockCtrl;\r
+\r
+ //\r
+ // Ensure no SD transactions are occurring on the SD Bus by\r
+ // waiting for Command Inhibit (DAT) and Command Inhibit (CMD)\r
+ // in the Present State register to be 0.\r
+ //\r
+ Status = SdMmcHcWaitMmioSet (\r
+ PciIo,\r
+ Slot,\r
+ SD_MMC_HC_PRESENT_STATE,\r
+ sizeof (PresentState),\r
+ BIT0 | BIT1,\r
+ 0,\r
+ SD_MMC_HC_GENERIC_TIMEOUT\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Set SD Clock Enable in the Clock Control register to 0\r
+ //\r
+ ClockCtrl = (UINT16)~BIT2;\r
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ SD/MMC card clock supply.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.\r
+ @param[in] Capability The capability of the slot.\r
+\r
+ @retval EFI_SUCCESS The clock is supplied successfully.\r
+ @retval Others The clock isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcClockSupply (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ IN UINT64 ClockFreq,\r
+ IN SD_MMC_HC_SLOT_CAP Capability\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 BaseClkFreq;\r
+ UINT32 SettingFreq;\r
+ UINT32 Divisor;\r
+ UINT32 Remainder;\r
+ UINT16 ControllerVer;\r
+ UINT16 ClockCtrl;\r
+\r
+ //\r
+ // Calculate a divisor for SD clock frequency\r
+ //\r
+ ASSERT (Capability.BaseClkFreq != 0);\r
+\r
+ BaseClkFreq = Capability.BaseClkFreq;\r
+ if ((ClockFreq > (BaseClkFreq * 1000)) || (ClockFreq == 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Calculate the divisor of base frequency.\r
+ //\r
+ Divisor = 0;\r
+ SettingFreq = BaseClkFreq * 1000;\r
+ while (ClockFreq < SettingFreq) {\r
+ Divisor++;\r
+\r
+ SettingFreq = (BaseClkFreq * 1000) / (2 * Divisor);\r
+ Remainder = (BaseClkFreq * 1000) % (2 * Divisor);\r
+ if ((ClockFreq == SettingFreq) && (Remainder == 0)) {\r
+ break;\r
+ }\r
+ if ((ClockFreq == SettingFreq) && (Remainder != 0)) {\r
+ SettingFreq ++;\r
+ }\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq));\r
+\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register.\r
+ //\r
+ if ((ControllerVer & 0xFF) == 2) {\r
+ ASSERT (Divisor <= 0x3FF);\r
+ ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2);\r
+ } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {\r
+ //\r
+ // Only the most significant bit can be used as divisor.\r
+ //\r
+ if (((Divisor - 1) & Divisor) != 0) {\r
+ Divisor = 1 << (HighBitSet32 (Divisor) + 1);\r
+ }\r
+ ASSERT (Divisor <= 0x80);\r
+ ClockCtrl = (Divisor & 0xFF) << 8;\r
+ } else {\r
+ DEBUG ((EFI_D_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Stop bus clock at first\r
+ //\r
+ Status = SdMmcHcStopClock (PciIo, Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Supply clock frequency with specified divisor\r
+ //\r
+ ClockCtrl |= BIT0;\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n"));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Wait Internal Clock Stable in the Clock Control register to be 1\r
+ //\r
+ Status = SdMmcHcWaitMmioSet (\r
+ PciIo,\r
+ Slot,\r
+ SD_MMC_HC_CLOCK_CTRL,\r
+ sizeof (ClockCtrl),\r
+ BIT1,\r
+ BIT1,\r
+ SD_MMC_HC_GENERIC_TIMEOUT\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Set SD Clock Enable in the Clock Control register to 1\r
+ //\r
+ ClockCtrl = BIT2;\r
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ SD/MMC bus power control.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] PowerCtrl The value setting to the power control register.\r
+\r
+ @retval TRUE There is a SD/MMC card attached.\r
+ @retval FALSE There is no a SD/MMC card attached.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcPowerControl (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ IN UINT8 PowerCtrl\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Clr SD Bus Power\r
+ //\r
+ PowerCtrl &= (UINT8)~BIT0;\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register\r
+ //\r
+ PowerCtrl |= BIT0;\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set the SD/MMC bus width.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] BusWidth The bus width used by the SD/MMC device, it must be 1, 4 or 8.\r
+\r
+ @retval EFI_SUCCESS The bus width is set successfully.\r
+ @retval Others The bus width isn't set successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcSetBusWidth (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ IN UINT16 BusWidth\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 HostCtrl1;\r
+\r
+ if (BusWidth == 1) {\r
+ HostCtrl1 = (UINT8)~(BIT5 | BIT1);\r
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ } else if (BusWidth == 4) {\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ HostCtrl1 |= BIT1;\r
+ HostCtrl1 &= (UINT8)~BIT5;\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);\r
+ } else if (BusWidth == 8) {\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ HostCtrl1 &= (UINT8)~BIT1;\r
+ HostCtrl1 |= BIT5;\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);\r
+ } else {\r
+ ASSERT (FALSE);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Supply SD/MMC card with lowest clock frequency at initialization.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Capability The capability of the slot.\r
+\r
+ @retval EFI_SUCCESS The clock is supplied successfully.\r
+ @retval Others The clock isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitClockFreq (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ IN SD_MMC_HC_SLOT_CAP Capability\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 InitFreq;\r
+\r
+ //\r
+ // Calculate a divisor for SD clock frequency\r
+ //\r
+ if (Capability.BaseClkFreq == 0) {\r
+ //\r
+ // Don't support get Base Clock Frequency information via another method\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Supply 400KHz clock frequency at initialization phase.\r
+ //\r
+ InitFreq = 400;\r
+ Status = SdMmcHcClockSupply (PciIo, Slot, InitFreq, Capability);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Supply SD/MMC card with maximum voltage at initialization.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Capability The capability of the slot.\r
+\r
+ @retval EFI_SUCCESS The voltage is supplied successfully.\r
+ @retval Others The voltage isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitPowerVoltage (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ IN SD_MMC_HC_SLOT_CAP Capability\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 MaxVoltage;\r
+ UINT8 HostCtrl2;\r
+\r
+ //\r
+ // Calculate supported maximum voltage according to SD Bus Voltage Select\r
+ //\r
+ if (Capability.Voltage33 != 0) {\r
+ //\r
+ // Support 3.3V\r
+ //\r
+ MaxVoltage = 0x0E;\r
+ } else if (Capability.Voltage30 != 0) {\r
+ //\r
+ // Support 3.0V\r
+ //\r
+ MaxVoltage = 0x0C;\r
+ } else if (Capability.Voltage18 != 0) {\r
+ //\r
+ // Support 1.8V\r
+ //\r
+ MaxVoltage = 0x0A;\r
+ HostCtrl2 = BIT3;\r
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ gBS->Stall (5000);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ } else {\r
+ ASSERT (FALSE);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register\r
+ //\r
+ Status = SdMmcHcPowerControl (PciIo, Slot, MaxVoltage);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Initialize the Timeout Control register with most conservative value at initialization.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The timeout control register is configured successfully.\r
+ @retval Others The timeout control register isn't configured successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitTimeoutCtrl (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Timeout;\r
+\r
+ Timeout = 0x0E;\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_TIMEOUT_CTRL, FALSE, sizeof (Timeout), &Timeout);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value\r
+ at initialization.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Capability The capability of the slot.\r
+\r
+ @retval EFI_SUCCESS The host controller is initialized successfully.\r
+ @retval Others The host controller isn't initialized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitHost (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ IN SD_MMC_HC_SLOT_CAP Capability\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = SdMmcHcInitClockFreq (PciIo, Slot, Capability);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = SdMmcHcInitPowerVoltage (PciIo, Slot, Capability);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = SdMmcHcInitTimeoutCtrl (PciIo, Slot);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Turn on/off LED.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] On The boolean to turn on/off LED.\r
+\r
+ @retval EFI_SUCCESS The LED is turned on/off successfully.\r
+ @retval Others The LED isn't turned on/off successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcLedOnOff (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ IN BOOLEAN On\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 HostCtrl1;\r
+\r
+ if (On) {\r
+ HostCtrl1 = BIT0;\r
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ } else {\r
+ HostCtrl1 = (UINT8)~BIT0;\r
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Build ADMA descriptor table for transfer.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details.\r
+\r
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The ADMA descriptor table is created successfully.\r
+ @retval Others The ADMA descriptor table isn't created successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+BuildAdmaDescTable (\r
+ IN SD_MMC_HC_TRB *Trb\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS Data;\r
+ UINT64 DataLen;\r
+ UINT64 Entries;\r
+ UINT32 Index;\r
+ UINT64 Remaining;\r
+ UINT32 Address;\r
+ UINTN TableSize;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_STATUS Status;\r
+ UINTN Bytes;\r
+\r
+ Data = Trb->DataPhy;\r
+ DataLen = Trb->DataLen;\r
+ PciIo = Trb->Private->PciIo;\r
+ //\r
+ // Only support 32bit ADMA Descriptor Table\r
+ //\r
+ if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)\r
+ // for 32-bit address descriptor table.\r
+ //\r
+ if ((Data & (BIT0 | BIT1)) != 0) {\r
+ DEBUG ((EFI_D_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));\r
+ }\r
+\r
+ Entries = DivU64x32 ((DataLen + ADMA_MAX_DATA_PER_LINE - 1), ADMA_MAX_DATA_PER_LINE);\r
+ TableSize = (UINTN)MultU64x32 (Entries, sizeof (SD_MMC_HC_ADMA_DESC_LINE));\r
+ Trb->AdmaPages = (UINT32)EFI_SIZE_TO_PAGES (TableSize);\r
+ Status = PciIo->AllocateBuffer (\r
+ PciIo,\r
+ AllocateAnyPages,\r
+ EfiBootServicesData,\r
+ EFI_SIZE_TO_PAGES (TableSize),\r
+ (VOID **)&Trb->AdmaDesc,\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ ZeroMem (Trb->AdmaDesc, TableSize);\r
+ Bytes = TableSize;\r
+ Status = PciIo->Map (\r
+ PciIo,\r
+ EfiPciIoOperationBusMasterCommonBuffer,\r
+ Trb->AdmaDesc,\r
+ &Bytes,\r
+ &Trb->AdmaDescPhy,\r
+ &Trb->AdmaMap\r
+ );\r
+\r
+ if (EFI_ERROR (Status) || (Bytes != TableSize)) {\r
+ //\r
+ // Map error or unable to map the whole RFis buffer into a contiguous region.\r
+ //\r
+ PciIo->FreeBuffer (\r
+ PciIo,\r
+ EFI_SIZE_TO_PAGES (TableSize),\r
+ Trb->AdmaDesc\r
+ );\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if ((UINT64)(UINTN)Trb->AdmaDescPhy > 0x100000000ul) {\r
+ //\r
+ // The ADMA doesn't support 64bit addressing.\r
+ //\r
+ PciIo->Unmap (\r
+ PciIo,\r
+ Trb->AdmaMap\r
+ );\r
+ PciIo->FreeBuffer (\r
+ PciIo,\r
+ EFI_SIZE_TO_PAGES (TableSize),\r
+ Trb->AdmaDesc\r
+ );\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Remaining = DataLen;\r
+ Address = (UINT32)Data;\r
+ for (Index = 0; Index < Entries; Index++) {\r
+ if (Remaining <= ADMA_MAX_DATA_PER_LINE) {\r
+ Trb->AdmaDesc[Index].Valid = 1;\r
+ Trb->AdmaDesc[Index].Act = 2;\r
+ Trb->AdmaDesc[Index].Length = (UINT16)Remaining;\r
+ Trb->AdmaDesc[Index].Address = Address;\r
+ break;\r
+ } else {\r
+ Trb->AdmaDesc[Index].Valid = 1;\r
+ Trb->AdmaDesc[Index].Act = 2;\r
+ Trb->AdmaDesc[Index].Length = 0;\r
+ Trb->AdmaDesc[Index].Address = Address;\r
+ }\r
+\r
+ Remaining -= ADMA_MAX_DATA_PER_LINE;\r
+ Address += ADMA_MAX_DATA_PER_LINE;\r
+ }\r
+\r
+ //\r
+ // Set the last descriptor line as end of descriptor table\r
+ //\r
+ Trb->AdmaDesc[Index].End = 1;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Create a new TRB for the SD/MMC cmd request.\r
+\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Packet A pointer to the SD command data structure.\r
+ @param[in] Event If Event is NULL, blocking I/O is performed. If Event is\r
+ not NULL, then nonblocking I/O is performed, and Event\r
+ will be signaled when the Packet completes.\r
+\r
+ @return Created Trb or NULL.\r
+\r
+**/\r
+SD_MMC_HC_TRB *\r
+SdMmcCreateTrb (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN UINT8 Slot,\r
+ IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,\r
+ IN EFI_EVENT Event\r
+ )\r
+{\r
+ SD_MMC_HC_TRB *Trb;\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
+ EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINTN MapLength;\r
+\r
+ Trb = AllocateZeroPool (sizeof (SD_MMC_HC_TRB));\r
+ if (Trb == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Trb->Signature = SD_MMC_HC_TRB_SIG;\r
+ Trb->Slot = Slot;\r
+ Trb->BlockSize = 0x200;\r
+ Trb->Packet = Packet;\r
+ Trb->Event = Event;\r
+ Trb->Started = FALSE;\r
+ Trb->Timeout = Packet->Timeout;\r
+ Trb->Private = Private;\r
+\r
+ if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {\r
+ Trb->Data = Packet->InDataBuffer;\r
+ Trb->DataLen = Packet->InTransferLength;\r
+ Trb->Read = TRUE;\r
+ } else if ((Packet->OutTransferLength != 0) && (Packet->OutDataBuffer != NULL)) {\r
+ Trb->Data = Packet->OutDataBuffer;\r
+ Trb->DataLen = Packet->OutTransferLength;\r
+ Trb->Read = FALSE;\r
+ } else if ((Packet->InTransferLength == 0) && (Packet->OutTransferLength == 0)) {\r
+ Trb->Data = NULL;\r
+ Trb->DataLen = 0;\r
+ } else {\r
+ goto Error;\r
+ }\r
+\r
+ if (Trb->Read) {\r
+ Flag = EfiPciIoOperationBusMasterWrite;\r
+ } else {\r
+ Flag = EfiPciIoOperationBusMasterRead;\r
+ }\r
+\r
+ PciIo = Private->PciIo;\r
+ if (Trb->DataLen != 0) {\r
+ MapLength = Trb->DataLen;\r
+ Status = PciIo->Map (\r
+ PciIo,\r
+ Flag,\r
+ Trb->Data,\r
+ &MapLength,\r
+ &Trb->DataPhy,\r
+ &Trb->DataMap\r
+ );\r
+ if (EFI_ERROR (Status) || (Trb->DataLen != MapLength)) {\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ goto Error;\r
+ }\r
+ }\r
+\r
+ if ((Trb->DataLen % Trb->BlockSize) != 0) {\r
+ if (Trb->DataLen < Trb->BlockSize) {\r
+ Trb->BlockSize = (UINT16)Trb->DataLen;\r
+ }\r
+ }\r
+\r
+ if (Trb->DataLen == 0) {\r
+ Trb->Mode = SdMmcNoData;\r
+ } else if (Private->Capability[Slot].Adma2 != 0) {\r
+ Trb->Mode = SdMmcAdmaMode;\r
+ Status = BuildAdmaDescTable (Trb);\r
+ if (EFI_ERROR (Status)) {\r
+ PciIo->Unmap (PciIo, Trb->DataMap);\r
+ goto Error;\r
+ }\r
+ } else if (Private->Capability[Slot].Sdma != 0) {\r
+ Trb->Mode = SdMmcSdmaMode;\r
+ } else {\r
+ Trb->Mode = SdMmcPioMode;\r
+ }\r
+\r
+ if (Event != NULL) {\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ InsertTailList (&Private->Queue, &Trb->TrbList);\r
+ gBS->RestoreTPL (OldTpl);\r
+ }\r
+\r
+ return Trb;\r
+\r
+Error:\r
+ SdMmcFreeTrb (Trb);\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Free the resource used by the TRB.\r
+\r
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+**/\r
+VOID\r
+SdMmcFreeTrb (\r
+ IN SD_MMC_HC_TRB *Trb\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+\r
+ PciIo = Trb->Private->PciIo;\r
+\r
+ if (Trb->AdmaMap != NULL) {\r
+ PciIo->Unmap (\r
+ PciIo,\r
+ Trb->AdmaMap\r
+ );\r
+ }\r
+ if (Trb->AdmaDesc != NULL) {\r
+ PciIo->FreeBuffer (\r
+ PciIo,\r
+ Trb->AdmaPages,\r
+ Trb->AdmaDesc\r
+ );\r
+ }\r
+ if (Trb->DataMap != NULL) {\r
+ PciIo->Unmap (\r
+ PciIo,\r
+ Trb->DataMap\r
+ );\r
+ }\r
+ FreePool (Trb);\r
+ return;\r
+}\r
+\r
+/**\r
+ Check if the env is ready for execute specified TRB.\r
+\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The env is ready for TRB execution.\r
+ @retval EFI_NOT_READY The env is not ready for TRB execution.\r
+ @retval Others Some erros happen.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcCheckTrbEnv (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN SD_MMC_HC_TRB *Trb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT32 PresentState;\r
+\r
+ Packet = Trb->Packet;\r
+\r
+ if ((Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc) ||\r
+ (Packet->SdMmcCmdBlk->ResponseType == SdMmcResponseTypeR1b) ||\r
+ (Packet->SdMmcCmdBlk->ResponseType == SdMmcResponseTypeR5b)) {\r
+ //\r
+ // Wait Command Inhibit (CMD) and Command Inhibit (DAT) in\r
+ // the Present State register to be 0\r
+ //\r
+ PresentState = BIT0 | BIT1;\r
+ //\r
+ // For Send Tuning Block cmd, just wait for Command Inhibit (CMD) to be 0\r
+ //\r
+ if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) &&\r
+ (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) ||\r
+ ((Private->Slot[Trb->Slot].CardType == SdCardType) &&\r
+ (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) {\r
+ PresentState = BIT0;\r
+ }\r
+ } else {\r
+ //\r
+ // Wait Command Inhibit (CMD) in the Present State register\r
+ // to be 0\r
+ //\r
+ PresentState = BIT0;\r
+ }\r
+\r
+ PciIo = Private->PciIo;\r
+ Status = SdMmcHcCheckMmioSet (\r
+ PciIo,\r
+ Trb->Slot,\r
+ SD_MMC_HC_PRESENT_STATE,\r
+ sizeof (PresentState),\r
+ PresentState,\r
+ 0\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Wait for the env to be ready for execute specified TRB.\r
+\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The env is ready for TRB execution.\r
+ @retval EFI_TIMEOUT The env is not ready for TRB execution in time.\r
+ @retval Others Some erros happen.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcWaitTrbEnv (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN SD_MMC_HC_TRB *Trb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
+ UINT64 Timeout;\r
+ BOOLEAN InfiniteWait;\r
+\r
+ //\r
+ // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register\r
+ //\r
+ Packet = Trb->Packet;\r
+ Timeout = Packet->Timeout;\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
+\r
+ while (InfiniteWait || (Timeout > 0)) {\r
+ //\r
+ // Check Trb execution result by reading Normal Interrupt Status register.\r
+ //\r
+ Status = SdMmcCheckTrbEnv (Private, Trb);\r
+ if (Status != EFI_NOT_READY) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Stall for 1 microsecond.\r
+ //\r
+ gBS->Stall (1);\r
+\r
+ Timeout--;\r
+ }\r
+\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+ Execute the specified TRB.\r
+\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The TRB is sent to host controller successfully.\r
+ @retval Others Some erros happen when sending this request to the host controller.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcExecTrb (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN SD_MMC_HC_TRB *Trb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT16 Cmd;\r
+ UINT16 IntStatus;\r
+ UINT32 Argument;\r
+ UINT16 BlkCount;\r
+ UINT16 BlkSize;\r
+ UINT16 TransMode;\r
+ UINT8 HostCtrl1;\r
+ UINT32 SdmaAddr;\r
+ UINT64 AdmaAddr;\r
+\r
+ Packet = Trb->Packet;\r
+ PciIo = Trb->Private->PciIo;\r
+ //\r
+ // Clear all bits in Error Interrupt Status Register\r
+ //\r
+ IntStatus = 0xFFFF;\r
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ERR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Clear all bits in Normal Interrupt Status Register excepts for Card Removal & Card Insertion bits.\r
+ //\r
+ IntStatus = 0xFF3F;\r
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set Host Control 1 register DMA Select field\r
+ //\r
+ if (Trb->Mode == SdMmcAdmaMode) {\r
+ HostCtrl1 = BIT4;\r
+ Status = SdMmcHcOrMmio (PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ SdMmcHcLedOnOff (PciIo, Trb->Slot, TRUE);\r
+\r
+ if (Trb->Mode == SdMmcSdmaMode) {\r
+ if ((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ SdmaAddr = (UINT32)(UINTN)Trb->DataPhy;\r
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ } else if (Trb->Mode == SdMmcAdmaMode) {\r
+ AdmaAddr = (UINT64)(UINTN)Trb->AdmaDescPhy;\r
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ BlkSize = Trb->BlockSize;\r
+ if (Trb->Mode == SdMmcSdmaMode) {\r
+ //\r
+ // Set SDMA boundary to be 512K bytes.\r
+ //\r
+ BlkSize |= 0x7000;\r
+ }\r
+\r
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_BLK_SIZE, FALSE, sizeof (BlkSize), &BlkSize);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);\r
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Argument = Packet->SdMmcCmdBlk->CommandArgument;\r
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ARG1, FALSE, sizeof (Argument), &Argument);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ TransMode = 0;\r
+ if (Trb->Mode != SdMmcNoData) {\r
+ if (Trb->Mode != SdMmcPioMode) {\r
+ TransMode |= BIT0;\r
+ }\r
+ if (Trb->Read) {\r
+ TransMode |= BIT4;\r
+ }\r
+ if (BlkCount != 0) {\r
+ TransMode |= BIT5 | BIT1;\r
+ }\r
+ //\r
+ // Only SD memory card needs to use AUTO CMD12 feature.\r
+ //\r
+ if (Private->Slot[Trb->Slot].CardType == SdCardType) {\r
+ if (BlkCount > 1) {\r
+ TransMode |= BIT2;\r
+ }\r
+ }\r
+ }\r
+\r
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_TRANS_MOD, FALSE, sizeof (TransMode), &TransMode);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Cmd = (UINT16)LShiftU64(Packet->SdMmcCmdBlk->CommandIndex, 8);\r
+ if (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc) {\r
+ Cmd |= BIT5;\r
+ }\r
+ //\r
+ // Convert ResponseType to value\r
+ //\r
+ if (Packet->SdMmcCmdBlk->CommandType != SdMmcCommandTypeBc) {\r
+ switch (Packet->SdMmcCmdBlk->ResponseType) {\r
+ case SdMmcResponseTypeR1:\r
+ case SdMmcResponseTypeR5:\r
+ case SdMmcResponseTypeR6:\r
+ case SdMmcResponseTypeR7:\r
+ Cmd |= (BIT1 | BIT3 | BIT4);\r
+ break;\r
+ case SdMmcResponseTypeR2:\r
+ Cmd |= (BIT0 | BIT3);\r
+ break;\r
+ case SdMmcResponseTypeR3:\r
+ case SdMmcResponseTypeR4:\r
+ Cmd |= BIT1;\r
+ break;\r
+ case SdMmcResponseTypeR1b:\r
+ case SdMmcResponseTypeR5b:\r
+ Cmd |= (BIT0 | BIT1 | BIT3 | BIT4);\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // Execute cmd\r
+ //\r
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Check the TRB execution result.\r
+\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The TRB is executed successfully.\r
+ @retval EFI_NOT_READY The TRB is not completed for execution.\r
+ @retval Others Some erros happen when executing this request.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcCheckTrbResult (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN SD_MMC_HC_TRB *Trb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
+ UINT16 IntStatus;\r
+ UINT32 Response[4];\r
+ UINT32 SdmaAddr;\r
+ UINT8 Index;\r
+ UINT8 SwReset;\r
+\r
+ SwReset = 0;\r
+ Packet = Trb->Packet;\r
+ //\r
+ // Check Trb execution result by reading Normal Interrupt Status register.\r
+ //\r
+ Status = SdMmcHcRwMmio (\r
+ Private->PciIo,\r
+ Trb->Slot,\r
+ SD_MMC_HC_NOR_INT_STS,\r
+ TRUE,\r
+ sizeof (IntStatus),\r
+ &IntStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Check Transfer Complete bit is set or not.\r
+ //\r
+ if ((IntStatus & BIT1) == BIT1) {\r
+ if ((IntStatus & BIT15) == BIT15) {\r
+ //\r
+ // Read Error Interrupt Status register to check if the error is\r
+ // Data Timeout Error.\r
+ // If yes, treat it as success as Transfer Complete has higher\r
+ // priority than Data Timeout Error.\r
+ //\r
+ Status = SdMmcHcRwMmio (\r
+ Private->PciIo,\r
+ Trb->Slot,\r
+ SD_MMC_HC_ERR_INT_STS,\r
+ TRUE,\r
+ sizeof (IntStatus),\r
+ &IntStatus\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ if ((IntStatus & BIT4) == BIT4) {\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+ }\r
+\r
+ goto Done;\r
+ }\r
+ //\r
+ // Check if there is a error happened during cmd execution.\r
+ // If yes, then do error recovery procedure to follow SD Host Controller\r
+ // Simplified Spec 3.0 section 3.10.1.\r
+ //\r
+ if ((IntStatus & BIT15) == BIT15) {\r
+ Status = SdMmcHcRwMmio (\r
+ Private->PciIo,\r
+ Trb->Slot,\r
+ SD_MMC_HC_ERR_INT_STS,\r
+ TRUE,\r
+ sizeof (IntStatus),\r
+ &IntStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ if ((IntStatus & 0x0F) != 0) {\r
+ SwReset |= BIT1;\r
+ }\r
+ if ((IntStatus & 0xF0) != 0) {\r
+ SwReset |= BIT2;\r
+ }\r
+\r
+ Status = SdMmcHcRwMmio (\r
+ Private->PciIo,\r
+ Trb->Slot,\r
+ SD_MMC_HC_SW_RST,\r
+ FALSE,\r
+ sizeof (SwReset),\r
+ &SwReset\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ Status = SdMmcHcWaitMmioSet (\r
+ Private->PciIo,\r
+ Trb->Slot,\r
+ SD_MMC_HC_SW_RST,\r
+ sizeof (SwReset),\r
+ 0xFF,\r
+ 0,\r
+ SD_MMC_HC_GENERIC_TIMEOUT\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+ //\r
+ // Check if DMA interrupt is signalled for the SDMA transfer.\r
+ //\r
+ if ((Trb->Mode == SdMmcSdmaMode) && ((IntStatus & BIT3) == BIT3)) {\r
+ //\r
+ // Clear DMA interrupt bit.\r
+ //\r
+ IntStatus = BIT3;\r
+ Status = SdMmcHcRwMmio (\r
+ Private->PciIo,\r
+ Trb->Slot,\r
+ SD_MMC_HC_NOR_INT_STS,\r
+ FALSE,\r
+ sizeof (IntStatus),\r
+ &IntStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Update SDMA Address register.\r
+ //\r
+ SdmaAddr = SD_MMC_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->DataPhy, SD_MMC_SDMA_BOUNDARY);\r
+ Status = SdMmcHcRwMmio (\r
+ Private->PciIo,\r
+ Trb->Slot,\r
+ SD_MMC_HC_SDMA_ADDR,\r
+ FALSE,\r
+ sizeof (UINT32),\r
+ &SdmaAddr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ Trb->DataPhy = (UINT32)(UINTN)SdmaAddr;\r
+ }\r
+\r
+ if ((Packet->SdMmcCmdBlk->CommandType != SdMmcCommandTypeAdtc) &&\r
+ (Packet->SdMmcCmdBlk->ResponseType != SdMmcResponseTypeR1b) &&\r
+ (Packet->SdMmcCmdBlk->ResponseType != SdMmcResponseTypeR5b)) {\r
+ if ((IntStatus & BIT0) == BIT0) {\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) &&\r
+ (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) ||\r
+ ((Private->Slot[Trb->Slot].CardType == SdCardType) &&\r
+ (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) {\r
+ //\r
+ // While performing tuning procedure (Execute Tuning is set to 1),\r
+ // Transfer Completeis not set to 1\r
+ // Refer to SD Host Controller Simplified Specification 3.0 table 2-23 for details.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+ Status = EFI_NOT_READY;\r
+Done:\r
+ //\r
+ // Get response data when the cmd is executed successfully.\r
+ //\r
+ if (!EFI_ERROR (Status)) {\r
+ if (Packet->SdMmcCmdBlk->CommandType != SdMmcCommandTypeBc) {\r
+ for (Index = 0; Index < 4; Index++) {\r
+ Status = SdMmcHcRwMmio (\r
+ Private->PciIo,\r
+ Trb->Slot,\r
+ SD_MMC_HC_RESPONSE + Index * 4,\r
+ TRUE,\r
+ sizeof (UINT32),\r
+ &Response[Index]\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ SdMmcHcLedOnOff (Private->PciIo, Trb->Slot, FALSE);\r
+ return Status;\r
+ }\r
+ }\r
+ CopyMem (Packet->SdMmcStatusBlk, Response, sizeof (Response));\r
+ }\r
+ }\r
+\r
+ if (Status != EFI_NOT_READY) {\r
+ SdMmcHcLedOnOff (Private->PciIo, Trb->Slot, FALSE);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Wait for the TRB execution result.\r
+\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Trb The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The TRB is executed successfully.\r
+ @retval Others Some erros happen when executing this request.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcWaitTrbResult (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN SD_MMC_HC_TRB *Trb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
+ UINT64 Timeout;\r
+ BOOLEAN InfiniteWait;\r
+\r
+ Packet = Trb->Packet;\r
+ //\r
+ // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register\r
+ //\r
+ Timeout = Packet->Timeout;\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
+\r
+ while (InfiniteWait || (Timeout > 0)) {\r
+ //\r
+ // Check Trb execution result by reading Normal Interrupt Status register.\r
+ //\r
+ Status = SdMmcCheckTrbResult (Private, Trb);\r
+ if (Status != EFI_NOT_READY) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Stall for 1 microsecond.\r
+ //\r
+ gBS->Stall (1);\r
+\r
+ Timeout--;\r
+ }\r
+\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+\r
+ Provides some data structure definitions used by the SD/MMC host controller driver.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_MMC_PCI_HCI_H_\r
+#define _SD_MMC_PCI_HCI_H_\r
+\r
+//\r
+// SD Host Controller SlotInfo Register Offset\r
+//\r
+#define SD_MMC_HC_SLOT_OFFSET 0x40\r
+\r
+#define SD_MMC_HC_MAX_SLOT 6\r
+\r
+//\r
+// SD Host Controller MMIO Register Offset\r
+//\r
+#define SD_MMC_HC_SDMA_ADDR 0x00\r
+#define SD_MMC_HC_ARG2 0x00\r
+#define SD_MMC_HC_BLK_SIZE 0x04\r
+#define SD_MMC_HC_BLK_COUNT 0x06\r
+#define SD_MMC_HC_ARG1 0x08\r
+#define SD_MMC_HC_TRANS_MOD 0x0C\r
+#define SD_MMC_HC_COMMAND 0x0E\r
+#define SD_MMC_HC_RESPONSE 0x10\r
+#define SD_MMC_HC_BUF_DAT_PORT 0x20\r
+#define SD_MMC_HC_PRESENT_STATE 0x24\r
+#define SD_MMC_HC_HOST_CTRL1 0x28\r
+#define SD_MMC_HC_POWER_CTRL 0x29\r
+#define SD_MMC_HC_BLK_GAP_CTRL 0x2A\r
+#define SD_MMC_HC_WAKEUP_CTRL 0x2B\r
+#define SD_MMC_HC_CLOCK_CTRL 0x2C\r
+#define SD_MMC_HC_TIMEOUT_CTRL 0x2E\r
+#define SD_MMC_HC_SW_RST 0x2F\r
+#define SD_MMC_HC_NOR_INT_STS 0x30\r
+#define SD_MMC_HC_ERR_INT_STS 0x32\r
+#define SD_MMC_HC_NOR_INT_STS_EN 0x34\r
+#define SD_MMC_HC_ERR_INT_STS_EN 0x36\r
+#define SD_MMC_HC_NOR_INT_SIG_EN 0x38\r
+#define SD_MMC_HC_ERR_INT_SIG_EN 0x3A\r
+#define SD_MMC_HC_AUTO_CMD_ERR_STS 0x3C\r
+#define SD_MMC_HC_HOST_CTRL2 0x3E\r
+#define SD_MMC_HC_CAP 0x40\r
+#define SD_MMC_HC_MAX_CURRENT_CAP 0x48\r
+#define SD_MMC_HC_FORCE_EVT_AUTO_CMD 0x50\r
+#define SD_MMC_HC_FORCE_EVT_ERR_INT 0x52\r
+#define SD_MMC_HC_ADMA_ERR_STS 0x54\r
+#define SD_MMC_HC_ADMA_SYS_ADDR 0x58\r
+#define SD_MMC_HC_PRESET_VAL 0x60\r
+#define SD_MMC_HC_SHARED_BUS_CTRL 0xE0\r
+#define SD_MMC_HC_SLOT_INT_STS 0xFC\r
+#define SD_MMC_HC_CTRL_VER 0xFE\r
+\r
+//\r
+// The transfer modes supported by SD Host Controller\r
+// Simplified Spec 3.0 Table 1-2\r
+//\r
+typedef enum {\r
+ SdMmcNoData,\r
+ SdMmcPioMode,\r
+ SdMmcSdmaMode,\r
+ SdMmcAdmaMode\r
+} SD_MMC_HC_TRANSFER_MODE;\r
+\r
+//\r
+// The maximum data length of each descriptor line\r
+//\r
+#define ADMA_MAX_DATA_PER_LINE 0x10000\r
+\r
+typedef struct {\r
+ UINT32 Valid:1;\r
+ UINT32 End:1;\r
+ UINT32 Int:1;\r
+ UINT32 Reserved:1;\r
+ UINT32 Act:2;\r
+ UINT32 Reserved1:10;\r
+ UINT32 Length:16;\r
+ UINT32 Address;\r
+} SD_MMC_HC_ADMA_DESC_LINE;\r
+\r
+#define SD_MMC_SDMA_BOUNDARY 512 * 1024\r
+#define SD_MMC_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1))\r
+\r
+typedef struct {\r
+ UINT8 FirstBar:3; // bit 0:2\r
+ UINT8 Reserved:1; // bit 3\r
+ UINT8 SlotNum:3; // bit 4:6\r
+ UINT8 Reserved1:1; // bit 7\r
+} SD_MMC_HC_SLOT_INFO;\r
+\r
+typedef struct {\r
+ UINT32 TimeoutFreq:6; // bit 0:5\r
+ UINT32 Reserved:1; // bit 6\r
+ UINT32 TimeoutUnit:1; // bit 7\r
+ UINT32 BaseClkFreq:8; // bit 8:15\r
+ UINT32 MaxBlkLen:2; // bit 16:17\r
+ UINT32 BusWidth8:1; // bit 18\r
+ UINT32 Adma2:1; // bit 19\r
+ UINT32 Reserved2:1; // bit 20\r
+ UINT32 HighSpeed:1; // bit 21\r
+ UINT32 Sdma:1; // bit 22\r
+ UINT32 SuspRes:1; // bit 23\r
+ UINT32 Voltage33:1; // bit 24\r
+ UINT32 Voltage30:1; // bit 25\r
+ UINT32 Voltage18:1; // bit 26\r
+ UINT32 Reserved3:1; // bit 27\r
+ UINT32 SysBus64:1; // bit 28\r
+ UINT32 AsyncInt:1; // bit 29\r
+ UINT32 SlotType:2; // bit 30:31\r
+ UINT32 Sdr50:1; // bit 32\r
+ UINT32 Sdr104:1; // bit 33\r
+ UINT32 Ddr50:1; // bit 34\r
+ UINT32 Reserved4:1; // bit 35\r
+ UINT32 DriverTypeA:1; // bit 36\r
+ UINT32 DriverTypeC:1; // bit 37\r
+ UINT32 DriverTypeD:1; // bit 38\r
+ UINT32 DriverType4:1; // bit 39\r
+ UINT32 TimerCount:4; // bit 40:43\r
+ UINT32 Reserved5:1; // bit 44\r
+ UINT32 TuningSDR50:1; // bit 45\r
+ UINT32 RetuningMod:2; // bit 46:47\r
+ UINT32 ClkMultiplier:8; // bit 48:55\r
+ UINT32 Reserved6:7; // bit 56:62\r
+ UINT32 Hs400:1; // bit 63\r
+} SD_MMC_HC_SLOT_CAP;\r
+\r
+/**\r
+ Dump the content of SD/MMC host controller's Capability Register.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Capability The buffer to store the capability data.\r
+\r
+**/\r
+VOID\r
+DumpCapabilityReg (\r
+ IN UINT8 Slot,\r
+ IN SD_MMC_HC_SLOT_CAP *Capability\r
+ );\r
+\r
+/**\r
+ Read SlotInfo register from SD/MMC host controller pci config space.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[out] FirstBar The buffer to store the first BAR value.\r
+ @param[out] SlotNum The buffer to store the supported slot number.\r
+\r
+ @retval EFI_SUCCESS The operation succeeds.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcGetSlotInfo (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ OUT UINT8 *FirstBar,\r
+ OUT UINT8 *SlotNum\r
+ );\r
+\r
+/**\r
+ Read/Write specified SD/MMC host controller mmio register.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] BarIndex The BAR index of the standard PCI Configuration\r
+ header to use as the base address for the memory\r
+ operation to perform.\r
+ @param[in] Offset The offset within the selected BAR to start the\r
+ memory operation.\r
+ @param[in] Read A boolean to indicate it's read or write operation.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2 , 4 or 8 bytes.\r
+ @param[in, out] Data For read operations, the destination buffer to store\r
+ the results. For write operations, the source buffer\r
+ to write data from. The caller is responsible for\r
+ having ownership of the data buffer and ensuring its\r
+ size not less than Count bytes.\r
+\r
+ @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid.\r
+ @retval EFI_SUCCESS The read/write operation succeeds.\r
+ @retval Others The read/write operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcRwMmio (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 BarIndex,\r
+ IN UINT32 Offset,\r
+ IN BOOLEAN Read,\r
+ IN UINT8 Count,\r
+ IN OUT VOID *Data\r
+ );\r
+\r
+/**\r
+ Do OR operation with the value of the specified SD/MMC host controller mmio register.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] BarIndex The BAR index of the standard PCI Configuration\r
+ header to use as the base address for the memory\r
+ operation to perform.\r
+ @param[in] Offset The offset within the selected BAR to start the\r
+ memory operation.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2 , 4 or 8 bytes.\r
+ @param[in] OrData The pointer to the data used to do OR operation.\r
+ The caller is responsible for having ownership of\r
+ the data buffer and ensuring its size not less than\r
+ Count bytes.\r
+\r
+ @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid.\r
+ @retval EFI_SUCCESS The OR operation succeeds.\r
+ @retval Others The OR operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcOrMmio (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 BarIndex,\r
+ IN UINT32 Offset,\r
+ IN UINT8 Count,\r
+ IN VOID *OrData\r
+ );\r
+\r
+/**\r
+ Do AND operation with the value of the specified SD/MMC host controller mmio register.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] BarIndex The BAR index of the standard PCI Configuration\r
+ header to use as the base address for the memory\r
+ operation to perform.\r
+ @param[in] Offset The offset within the selected BAR to start the\r
+ memory operation.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2 , 4 or 8 bytes.\r
+ @param[in] AndData The pointer to the data used to do AND operation.\r
+ The caller is responsible for having ownership of\r
+ the data buffer and ensuring its size not less than\r
+ Count bytes.\r
+\r
+ @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid.\r
+ @retval EFI_SUCCESS The AND operation succeeds.\r
+ @retval Others The AND operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcAndMmio (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 BarIndex,\r
+ IN UINT32 Offset,\r
+ IN UINT8 Count,\r
+ IN VOID *AndData\r
+ );\r
+\r
+/**\r
+ Wait for the value of the specified MMIO register set to the test value.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] BarIndex The BAR index of the standard PCI Configuration\r
+ header to use as the base address for the memory\r
+ operation to perform.\r
+ @param[in] Offset The offset within the selected BAR to start the\r
+ memory operation.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2, 4 or 8 bytes.\r
+ @param[in] MaskValue The mask value of memory.\r
+ @param[in] TestValue The test value of memory.\r
+ @param[in] Timeout The time out value for wait memory set, uses 1\r
+ microsecond as a unit.\r
+\r
+ @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout\r
+ range.\r
+ @retval EFI_SUCCESS The MMIO register has expected value.\r
+ @retval Others The MMIO operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcWaitMmioSet (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 BarIndex,\r
+ IN UINT32 Offset,\r
+ IN UINT8 Count,\r
+ IN UINT64 MaskValue,\r
+ IN UINT64 TestValue,\r
+ IN UINT64 Timeout\r
+ );\r
+\r
+/**\r
+ Software reset the specified SD/MMC host controller.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The software reset executes successfully.\r
+ @retval Others The software reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcReset (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot\r
+ );\r
+\r
+/**\r
+ Set all interrupt status bits in Normal and Error Interrupt Status Enable\r
+ register.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The operation executes successfully.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcEnableInterrupt (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot\r
+ );\r
+\r
+/**\r
+ Get the capability data from the specified slot.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[out] Capability The buffer to store the capability data.\r
+\r
+ @retval EFI_SUCCESS The operation executes successfully.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcGetCapability (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ OUT SD_MMC_HC_SLOT_CAP *Capability\r
+ );\r
+\r
+/**\r
+ Get the maximum current capability data from the specified slot.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[out] MaxCurrent The buffer to store the maximum current capability data.\r
+\r
+ @retval EFI_SUCCESS The operation executes successfully.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcGetMaxCurrent (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ OUT UINT64 *MaxCurrent\r
+ );\r
+\r
+/**\r
+ Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller\r
+ slot.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[out] MediaPresent The pointer to the media present boolean value.\r
+\r
+ @retval EFI_SUCCESS There is no media change happened.\r
+ @retval EFI_MEDIA_CHANGED There is media change happened.\r
+ @retval Others The detection fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcCardDetect (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ OUT BOOLEAN *MediaPresent\r
+ );\r
+\r
+/**\r
+ Stop SD/MMC card clock.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS Succeed to stop SD/MMC clock.\r
+ @retval Others Fail to stop SD/MMC clock.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcStopClock (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot\r
+ );\r
+\r
+/**\r
+ SD/MMC card clock supply.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.\r
+ @param[in] Capability The capability of the slot.\r
+\r
+ @retval EFI_SUCCESS The clock is supplied successfully.\r
+ @retval Others The clock isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcClockSupply (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ IN UINT64 ClockFreq,\r
+ IN SD_MMC_HC_SLOT_CAP Capability\r
+ );\r
+\r
+/**\r
+ SD/MMC bus power control.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] PowerCtrl The value setting to the power control register.\r
+\r
+ @retval TRUE There is a SD/MMC card attached.\r
+ @retval FALSE There is no a SD/MMC card attached.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcPowerControl (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ IN UINT8 PowerCtrl\r
+ );\r
+\r
+/**\r
+ Set the SD/MMC bus width.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] BusWidth The bus width used by the SD/MMC device, it must be 1, 4 or 8.\r
+\r
+ @retval EFI_SUCCESS The bus width is set successfully.\r
+ @retval Others The bus width isn't set successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcSetBusWidth (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ IN UINT16 BusWidth\r
+ );\r
+\r
+/**\r
+ Supply SD/MMC card with lowest clock frequency at initialization.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Capability The capability of the slot.\r
+\r
+ @retval EFI_SUCCESS The clock is supplied successfully.\r
+ @retval Others The clock isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitClockFreq (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ IN SD_MMC_HC_SLOT_CAP Capability\r
+ );\r
+\r
+/**\r
+ Supply SD/MMC card with maximum voltage at initialization.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Capability The capability of the slot.\r
+\r
+ @retval EFI_SUCCESS The voltage is supplied successfully.\r
+ @retval Others The voltage isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitPowerVoltage (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ IN SD_MMC_HC_SLOT_CAP Capability\r
+ );\r
+\r
+/**\r
+ Initialize the Timeout Control register with most conservative value at initialization.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The timeout control register is configured successfully.\r
+ @retval Others The timeout control register isn't configured successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitTimeoutCtrl (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot\r
+ );\r
+\r
+/**\r
+ Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value\r
+ at initialization.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Capability The capability of the slot.\r
+\r
+ @retval EFI_SUCCESS The host controller is initialized successfully.\r
+ @retval Others The host controller isn't initialized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitHost (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ IN SD_MMC_HC_SLOT_CAP Capability\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ SdMmcPciHcPei driver is used to provide platform-dependent info, mainly SD/MMC\r
+ host controller MMIO base, to upper layer SD/MMC drivers.\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdMmcPciHcPei.h"\r
+\r
+EDKII_SD_MMC_HOST_CONTROLLER_PPI mSdMmcHostControllerPpi = { GetSdMmcHcMmioBar };\r
+\r
+EFI_PEI_PPI_DESCRIPTOR mPpiList = {\r
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gEdkiiPeiSdMmcHostControllerPpiGuid,\r
+ &mSdMmcHostControllerPpi\r
+};\r
+\r
+/**\r
+ Get the MMIO base address of SD/MMC host controller.\r
+\r
+ @param[in] This The protocol instance pointer.\r
+ @param[in] ControllerId The ID of the SD/MMC host controller.\r
+ @param[in,out] MmioBar The pointer to store the array of available\r
+ SD/MMC host controller slot MMIO base addresses.\r
+ The entry number of the array is specified by BarNum.\r
+ @param[out] BarNum The pointer to store the supported bar number.\r
+\r
+ @retval EFI_SUCCESS The operation succeeds.\r
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetSdMmcHcMmioBar (\r
+ IN EDKII_SD_MMC_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 ControllerId,\r
+ IN OUT UINTN **MmioBar,\r
+ OUT UINT8 *BarNum\r
+ )\r
+{\r
+ SD_MMC_HC_PEI_PRIVATE_DATA *Private;\r
+\r
+ if ((This == NULL) || (MmioBar == NULL) || (BarNum == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = SD_MMC_HC_PEI_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (ControllerId >= Private->TotalSdMmcHcs) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *MmioBar = &Private->MmioBar[ControllerId].MmioBarAddr[0];\r
+ *BarNum = (UINT8)Private->MmioBar[ControllerId].SlotNum;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ The user code starts with this function.\r
+\r
+ @param FileHandle Handle of the file being invoked.\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+\r
+ @retval EFI_SUCCESS The driver is successfully initialized.\r
+ @retval Others Can't initialize the driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSdMmcHcPeim (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ EFI_BOOT_MODE BootMode;\r
+ EFI_STATUS Status;\r
+ UINT16 Bus;\r
+ UINT16 Device;\r
+ UINT16 Function;\r
+ UINT32 Size;\r
+ UINT64 MmioSize;\r
+ UINT8 SubClass;\r
+ UINT8 BaseClass;\r
+ UINT8 SlotInfo;\r
+ UINT8 SlotNum;\r
+ UINT8 FirstBar;\r
+ UINT8 Index;\r
+ UINT8 Slot;\r
+ UINT32 BarAddr;\r
+ SD_MMC_HC_PEI_PRIVATE_DATA *Private;\r
+\r
+ //\r
+ // Shadow this PEIM to run from memory\r
+ //\r
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = PeiServicesGetBootMode (&BootMode);\r
+ ///\r
+ /// We do not expose this in S3 boot path, because it is only for recovery.\r
+ ///\r
+ if (BootMode == BOOT_ON_S3_RESUME) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Private = (SD_MMC_HC_PEI_PRIVATE_DATA *) AllocateZeroPool (sizeof (SD_MMC_HC_PEI_PRIVATE_DATA));\r
+ if (Private == NULL) {\r
+ DEBUG ((EFI_D_ERROR, "Failed to allocate memory for SD_MMC_HC_PEI_PRIVATE_DATA! \n"));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Private->Signature = SD_MMC_HC_PEI_SIGNATURE;\r
+ Private->SdMmcHostControllerPpi = mSdMmcHostControllerPpi;\r
+ Private->PpiList = mPpiList;\r
+ Private->PpiList.Ppi = &Private->SdMmcHostControllerPpi;\r
+\r
+ BarAddr = PcdGet32 (PcdSdMmcPciHostControllerMmioBase);\r
+ for (Bus = 0; Bus < 256; Bus++) {\r
+ for (Device = 0; Device < 32; Device++) {\r
+ for (Function = 0; Function < 8; Function++) {\r
+ SubClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));\r
+ BaseClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));\r
+\r
+ if ((SubClass == PCI_SUBCLASS_SD_HOST_CONTROLLER) && (BaseClass == PCI_CLASS_SYSTEM_PERIPHERAL)) {\r
+ //\r
+ // Get the SD/MMC Pci host controller's Slot Info.\r
+ //\r
+ SlotInfo = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, SD_MMC_HC_PEI_SLOT_OFFSET));\r
+ FirstBar = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).FirstBar;\r
+ SlotNum = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).SlotNum + 1;\r
+ ASSERT ((FirstBar + SlotNum) < MAX_SD_MMC_SLOTS);\r
+\r
+ for (Index = 0, Slot = FirstBar; Slot < (FirstBar + SlotNum); Index++, Slot++) {\r
+ //\r
+ // Get the SD/MMC Pci host controller's MMIO region size.\r
+ //\r
+ PciAnd16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (UINT16)~(EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));\r
+ PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), 0xFFFFFFFF);\r
+ Size = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot));\r
+\r
+ switch (Size & 0x07) {\r
+ case 0x0:\r
+ //\r
+ // Memory space: anywhere in 32 bit address space\r
+ //\r
+ MmioSize = (~(Size & 0xFFFFFFF0)) + 1;\r
+ break;\r
+ case 0x4:\r
+ //\r
+ // Memory space: anywhere in 64 bit address space\r
+ //\r
+ MmioSize = Size & 0xFFFFFFF0;\r
+ PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), 0xFFFFFFFF);\r
+ Size = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4)); \r
+ //\r
+ // Fix the length to support some spefic 64 bit BAR\r
+ //\r
+ Size |= ((UINT32)(-1) << HighBitSet32 (Size));\r
+ //\r
+ // Calculate the size of 64bit bar\r
+ //\r
+ MmioSize |= LShiftU64 ((UINT64) Size, 32);\r
+ MmioSize = (~(MmioSize)) + 1;\r
+ //\r
+ // Clean the high 32bits of this 64bit BAR to 0 as we only allow a 32bit BAR.\r
+ //\r
+ PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot + 4), 0);\r
+ break;\r
+ default:\r
+ //\r
+ // Unknown BAR type\r
+ //\r
+ ASSERT (FALSE);\r
+ continue;\r
+ };\r
+ //\r
+ // Assign resource to the SdMmc Pci host controller's MMIO BAR.\r
+ // Enable the SdMmc Pci host controller by setting BME and MSE bits of PCI_CMD register.\r
+ //\r
+ PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), BarAddr);\r
+ PciOr16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));\r
+ //\r
+ // Record the allocated Mmio base address.\r
+ //\r
+ Private->MmioBar[Private->TotalSdMmcHcs].SlotNum++;\r
+ Private->MmioBar[Private->TotalSdMmcHcs].MmioBarAddr[Index] = BarAddr;\r
+ BarAddr += (UINT32)MmioSize;\r
+ }\r
+ Private->TotalSdMmcHcs++;\r
+ ASSERT (Private->TotalSdMmcHcs < MAX_SD_MMC_HCS);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ ///\r
+ /// Install SdMmc Host Controller PPI\r
+ ///\r
+ Status = PeiServicesInstallPpi (&Private->PpiList);\r
+\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_MMC_PCI_HOST_CONTROLLER_PEI_H_\r
+#define _SD_MMC_PCI_HOST_CONTROLLER_PEI_H_\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/MasterBootMode.h>\r
+#include <Ppi/SdMmcHostController.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#define SD_MMC_HC_PEI_SIGNATURE SIGNATURE_32 ('S', 'D', 'M', 'C')\r
+\r
+#define MAX_SD_MMC_HCS 8\r
+#define MAX_SD_MMC_SLOTS 6\r
+\r
+//\r
+// SD Host Controller SlotInfo Register Offset\r
+//\r
+#define SD_MMC_HC_PEI_SLOT_OFFSET 0x40\r
+\r
+typedef struct {\r
+ UINT8 FirstBar:3; // bit 0:2\r
+ UINT8 Reserved:1; // bit 3\r
+ UINT8 SlotNum:3; // bit 4:6\r
+ UINT8 Reserved1:1; // bit 7\r
+} SD_MMC_HC_PEI_SLOT_INFO;\r
+\r
+typedef struct {\r
+ UINTN SlotNum;\r
+ UINTN MmioBarAddr[MAX_SD_MMC_SLOTS];\r
+} SD_MMC_HC_PEI_BAR;\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ EDKII_SD_MMC_HOST_CONTROLLER_PPI SdMmcHostControllerPpi;\r
+ EFI_PEI_PPI_DESCRIPTOR PpiList;\r
+ UINTN TotalSdMmcHcs;\r
+ SD_MMC_HC_PEI_BAR MmioBar[MAX_SD_MMC_HCS];\r
+} SD_MMC_HC_PEI_PRIVATE_DATA;\r
+\r
+#define SD_MMC_HC_PEI_PRIVATE_DATA_FROM_THIS(a) CR (a, SD_MMC_HC_PEI_PRIVATE_DATA, SdMmcHostControllerPpi, SD_MMC_HC_PEI_SIGNATURE)\r
+\r
+/**\r
+ Get the MMIO base address of SD/MMC host controller.\r
+\r
+ @param[in] This The protocol instance pointer.\r
+ @param[in] ControllerId The ID of the SD/MMC host controller.\r
+ @param[in,out] MmioBar The pointer to store the array of available\r
+ SD/MMC host controller slot MMIO base addresses.\r
+ The entry number of the array is specified by BarNum.\r
+ @param[out] BarNum The pointer to store the supported bar number.\r
+\r
+ @retval EFI_SUCCESS The operation succeeds.\r
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetSdMmcHcMmioBar (\r
+ IN EDKII_SD_MMC_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 ControllerId,\r
+ IN OUT UINTN **MmioBar,\r
+ OUT UINT8 *BarNum\r
+ );\r
+\r
+#endif\r
--- /dev/null
+## @file\r
+# Component Description File For SD/MMC Pci Host Controller Pei Module.\r
+#\r
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php.\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = SdMmcPciHcPei\r
+ MODULE_UNI_FILE = SdMmcPciHcPei.uni\r
+ FILE_GUID = 1BB737EF-427A-4144-8B3B-B76EF38515E6\r
+ MODULE_TYPE = PEIM\r
+ VERSION_STRING = 1.0\r
+\r
+ ENTRY_POINT = InitializeSdMmcHcPeim\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ SdMmcPciHcPei.c\r
+ SdMmcPciHcPei.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+ PciLib\r
+ DebugLib\r
+ PeiServicesLib\r
+ MemoryAllocationLib\r
+ PeimEntryPoint\r
+\r
+[Pcd]\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSdMmcPciHostControllerMmioBase ## CONSUMES\r
+\r
+[Ppis]\r
+ gEdkiiPeiSdMmcHostControllerPpiGuid ## PRODUCES\r
+\r
+[Depex]\r
+ gEfiPeiMasterBootModePpiGuid AND gEfiPeiMemoryDiscoveredPpiGuid\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+ SdMmcPciHcPeiExtra.uni
\ No newline at end of file
--- /dev/null
+// /** @file\r
+// The SdMmcPciHcPei driver is used by upper layer to retrieve mmio base address\r
+// of managed pci-based SD/MMC host controller at PEI phase.\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions\r
+// of the BSD License which accompanies this distribution. The\r
+// full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "Providing interface for upper layer to retrieve mmio base address of managed pci-based SD/MMC host controller at PEI phase."\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "It implements the interface of getting mmio base address of managed pci-based SD/MMC host controller at PEI phase."\r
+\r
--- /dev/null
+// /** @file\r
+// SdMmcPciHcPei Localized Strings and Content\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions\r
+// of the BSD License which accompanies this distribution. The\r
+// full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+#string STR_PROPERTIES_MODULE_NAME\r
+#language en-US\r
+"SD/MMC PCI-Based HC Module for Recovery"\r
+\r
+\r
--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "EmmcBlockIoPei.h"\r
+\r
+//\r
+// Template for EMMC HC Slot Data.\r
+//\r
+EMMC_PEIM_HC_SLOT gEmmcHcSlotTemplate = {\r
+ EMMC_PEIM_SLOT_SIG, // Signature\r
+ { // Media\r
+ {\r
+ MSG_EMMC_DP,\r
+ FALSE,\r
+ TRUE,\r
+ FALSE,\r
+ 0x200,\r
+ 0\r
+ },\r
+ {\r
+ MSG_EMMC_DP,\r
+ FALSE,\r
+ TRUE,\r
+ FALSE,\r
+ 0x200,\r
+ 0\r
+ },\r
+ {\r
+ MSG_EMMC_DP,\r
+ FALSE,\r
+ TRUE,\r
+ FALSE,\r
+ 0x200,\r
+ 0\r
+ },\r
+ {\r
+ MSG_EMMC_DP,\r
+ FALSE,\r
+ TRUE,\r
+ FALSE,\r
+ 0x200,\r
+ 0\r
+ },\r
+ {\r
+ MSG_EMMC_DP,\r
+ FALSE,\r
+ TRUE,\r
+ FALSE,\r
+ 0x200,\r
+ 0\r
+ },\r
+ {\r
+ MSG_EMMC_DP,\r
+ FALSE,\r
+ TRUE,\r
+ FALSE,\r
+ 0x200,\r
+ 0\r
+ },\r
+ {\r
+ MSG_EMMC_DP,\r
+ FALSE,\r
+ TRUE,\r
+ FALSE,\r
+ 0x200,\r
+ 0\r
+ },\r
+ {\r
+ MSG_EMMC_DP,\r
+ FALSE,\r
+ TRUE,\r
+ FALSE,\r
+ 0x200,\r
+ 0\r
+ }\r
+ },\r
+ 0, // MediaNum\r
+ { // PartitionType\r
+ EmmcPartitionUnknown,\r
+ EmmcPartitionUnknown,\r
+ EmmcPartitionUnknown,\r
+ EmmcPartitionUnknown,\r
+ EmmcPartitionUnknown,\r
+ EmmcPartitionUnknown,\r
+ EmmcPartitionUnknown,\r
+ EmmcPartitionUnknown\r
+ },\r
+ 0, // EmmcHcBase\r
+ { // Capability\r
+ 0,\r
+ },\r
+ { // Csd\r
+ 0,\r
+ },\r
+ { // ExtCsd\r
+ {0},\r
+ },\r
+ TRUE, // SectorAddressing\r
+ NULL // Private\r
+};\r
+\r
+//\r
+// Template for EMMC HC Private Data.\r
+//\r
+EMMC_PEIM_HC_PRIVATE_DATA gEmmcHcPrivateTemplate = {\r
+ EMMC_PEIM_SIG, // Signature\r
+ NULL, // Pool\r
+ { // BlkIoPpi\r
+ EmmcBlockIoPeimGetDeviceNo,\r
+ EmmcBlockIoPeimGetMediaInfo,\r
+ EmmcBlockIoPeimReadBlocks\r
+ },\r
+ { // BlkIo2Ppi\r
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,\r
+ EmmcBlockIoPeimGetDeviceNo2,\r
+ EmmcBlockIoPeimGetMediaInfo2,\r
+ EmmcBlockIoPeimReadBlocks2\r
+ },\r
+ { // BlkIoPpiList\r
+ EFI_PEI_PPI_DESCRIPTOR_PPI,\r
+ &gEfiPeiVirtualBlockIoPpiGuid,\r
+ NULL\r
+ },\r
+ { // BlkIo2PpiList\r
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
+ &gEfiPeiVirtualBlockIo2PpiGuid,\r
+ NULL\r
+ },\r
+ { // Slot\r
+ {\r
+ 0,\r
+ },\r
+ {\r
+ 0,\r
+ },\r
+ {\r
+ 0,\r
+ },\r
+ {\r
+ 0,\r
+ },\r
+ {\r
+ 0,\r
+ },\r
+ {\r
+ 0,\r
+ }\r
+ },\r
+ 0, // SlotNum\r
+ 0 // TotalBlkIoDevices\r
+};\r
+/**\r
+ Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+ This function is used for getting the count of block I/O devices that one\r
+ specific block driver detects. To the PEI ATAPI driver, it returns the number\r
+ of all the detected ATAPI devices it detects during the enumeration process.\r
+ To the PEI legacy floppy driver, it returns the number of all the legacy\r
+ devices it finds during its enumeration process. If no device is detected,\r
+ then the function will return zero.\r
+\r
+ @param[in] PeiServices General-purpose services that are available\r
+ to every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI\r
+ instance.\r
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.\r
+\r
+ @retval EFI_SUCCESS The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimGetDeviceNo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ OUT UINTN *NumberBlockDevices\r
+ )\r
+{\r
+ EMMC_PEIM_HC_PRIVATE_DATA *Private;\r
+\r
+ Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);\r
+ *NumberBlockDevices = Private->TotalBlkIoDevices;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Gets a block device's media information.\r
+\r
+ This function will provide the caller with the specified block device's media\r
+ information. If the media changes, calling this function will update the media\r
+ information accordingly.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, the PPIs that\r
+ want to talk to a single device must specify the\r
+ device index that was assigned during the enumeration\r
+ process. This index is a number from one to\r
+ NumberBlockDevices.\r
+ @param[out] MediaInfo The media information of the specified block media.\r
+ The caller is responsible for the ownership of this\r
+ data structure.\r
+\r
+ @par Note:\r
+ The MediaInfo structure describes an enumeration of possible block device\r
+ types. This enumeration exists because no device paths are actually passed\r
+ across interfaces that describe the type or class of hardware that is publishing\r
+ the block I/O interface. This enumeration will allow for policy decisions\r
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+ by a given device type, they should be reported in ascending order; this\r
+ order also applies to nested partitions, such as legacy MBR, where the\r
+ outermost partitions would have precedence in the reporting order. The\r
+ same logic applies to systems such as IDE that have precedence relationships\r
+ like "Master/Slave" or "Primary/Secondary". The master device should be\r
+ reported first, the slave second.\r
+\r
+ @retval EFI_SUCCESS Media information about the specified block device\r
+ was obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware\r
+ error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimGetMediaInfo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo\r
+ )\r
+{\r
+ EMMC_PEIM_HC_PRIVATE_DATA *Private;\r
+ UINT8 SlotNum;\r
+ UINT8 MediaNum;\r
+ UINT8 Location;\r
+ BOOLEAN Found;\r
+\r
+ Found = FALSE;\r
+ Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Location = 0;\r
+ MediaNum = 0;\r
+ for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {\r
+ for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {\r
+ Location ++;\r
+ if (Location == DeviceIndex) {\r
+ Found = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ if (Found) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ MediaInfo->DeviceType = EMMC;\r
+ MediaInfo->MediaPresent = TRUE;\r
+ MediaInfo->LastBlock = (UINTN)Private->Slot[SlotNum].Media[MediaNum].LastBlock;\r
+ MediaInfo->BlockSize = Private->Slot[SlotNum].Media[MediaNum].BlockSize;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Reads the requested number of blocks from the specified block device.\r
+\r
+ The function reads the requested number of blocks from the device. All the\r
+ blocks are read, or an error is returned. If there is no media in the device,\r
+ the function returns EFI_NO_MEDIA.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to\r
+ every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, PPIs that\r
+ want to talk to a single device must specify the device\r
+ index that was assigned during the enumeration process.\r
+ This index is a number from one to NumberBlockDevices.\r
+ @param[in] StartLBA The starting logical block address (LBA) to read from\r
+ on the device\r
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be\r
+ a multiple of the intrinsic block size of the device.\r
+ @param[out] Buffer A pointer to the destination buffer for the data.\r
+ The caller is responsible for the ownership of the\r
+ buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
+ to perform the read operation.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
+ valid, or the buffer is not properly aligned.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
+ the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimReadBlocks (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ IN EFI_PEI_LBA StartLBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+ UINTN NumberOfBlocks;\r
+ EMMC_PEIM_HC_PRIVATE_DATA *Private;\r
+ UINT8 SlotNum;\r
+ UINT8 MediaNum;\r
+ UINT8 Location;\r
+ UINT8 PartitionConfig;\r
+ UINTN Remaining;\r
+ UINT32 MaxBlock;\r
+ BOOLEAN Found;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Found = FALSE;\r
+ Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ //\r
+ // Check parameters\r
+ //\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Location = 0;\r
+ MediaNum = 0;\r
+ for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {\r
+ for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {\r
+ Location ++;\r
+ if (Location == DeviceIndex) {\r
+ Found = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ if (Found) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ BlockSize = Private->Slot[SlotNum].Media[MediaNum].BlockSize;\r
+ if (BufferSize % BlockSize != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ if (StartLBA > Private->Slot[SlotNum].Media[MediaNum].LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ NumberOfBlocks = BufferSize / BlockSize;\r
+\r
+ //\r
+ // Check if needs to switch partition access.\r
+ //\r
+ PartitionConfig = Private->Slot[SlotNum].ExtCsd.PartitionConfig;\r
+ if ((PartitionConfig & 0x7) != Private->Slot[SlotNum].PartitionType[MediaNum]) {\r
+ PartitionConfig &= (UINT8)~0x7;\r
+ PartitionConfig |= Private->Slot[SlotNum].PartitionType[MediaNum];\r
+ Status = EmmcPeimSwitch (\r
+ &Private->Slot[SlotNum],\r
+ 0x3,\r
+ OFFSET_OF (EMMC_EXT_CSD, PartitionConfig),\r
+ PartitionConfig,\r
+ 0x0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ Private->Slot[SlotNum].ExtCsd.PartitionConfig = PartitionConfig;\r
+ }\r
+ //\r
+ // Start to execute data transfer. The max block number in single cmd is 65535 blocks.\r
+ //\r
+ Remaining = NumberOfBlocks;\r
+ MaxBlock = 0xFFFF;\r
+\r
+ while (Remaining > 0) {\r
+ if (Remaining <= MaxBlock) {\r
+ NumberOfBlocks = Remaining;\r
+ } else {\r
+ NumberOfBlocks = MaxBlock;\r
+ }\r
+\r
+ Status = EmmcPeimSetBlkCount (&Private->Slot[SlotNum], (UINT16)NumberOfBlocks);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ BufferSize = NumberOfBlocks * BlockSize;\r
+ Status = EmmcPeimRwMultiBlocks (&Private->Slot[SlotNum], StartLBA, BlockSize, Buffer, BufferSize, TRUE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ StartLBA += NumberOfBlocks;\r
+ Buffer = (UINT8*)Buffer + BufferSize;\r
+ Remaining -= NumberOfBlocks;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+ This function is used for getting the count of block I/O devices that one\r
+ specific block driver detects. To the PEI ATAPI driver, it returns the number\r
+ of all the detected ATAPI devices it detects during the enumeration process.\r
+ To the PEI legacy floppy driver, it returns the number of all the legacy\r
+ devices it finds during its enumeration process. If no device is detected,\r
+ then the function will return zero.\r
+\r
+ @param[in] PeiServices General-purpose services that are available\r
+ to every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI\r
+ instance.\r
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.\r
+\r
+ @retval EFI_SUCCESS The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimGetDeviceNo2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ OUT UINTN *NumberBlockDevices\r
+ )\r
+{\r
+ EMMC_PEIM_HC_PRIVATE_DATA *Private;\r
+\r
+ Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);\r
+ *NumberBlockDevices = Private->TotalBlkIoDevices;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Gets a block device's media information.\r
+\r
+ This function will provide the caller with the specified block device's media\r
+ information. If the media changes, calling this function will update the media\r
+ information accordingly.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, the PPIs that\r
+ want to talk to a single device must specify the\r
+ device index that was assigned during the enumeration\r
+ process. This index is a number from one to\r
+ NumberBlockDevices.\r
+ @param[out] MediaInfo The media information of the specified block media.\r
+ The caller is responsible for the ownership of this\r
+ data structure.\r
+\r
+ @par Note:\r
+ The MediaInfo structure describes an enumeration of possible block device\r
+ types. This enumeration exists because no device paths are actually passed\r
+ across interfaces that describe the type or class of hardware that is publishing\r
+ the block I/O interface. This enumeration will allow for policy decisions\r
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+ by a given device type, they should be reported in ascending order; this\r
+ order also applies to nested partitions, such as legacy MBR, where the\r
+ outermost partitions would have precedence in the reporting order. The\r
+ same logic applies to systems such as IDE that have precedence relationships\r
+ like "Master/Slave" or "Primary/Secondary". The master device should be\r
+ reported first, the slave second.\r
+\r
+ @retval EFI_SUCCESS Media information about the specified block device\r
+ was obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware\r
+ error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimGetMediaInfo2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_PEIM_HC_PRIVATE_DATA *Private;\r
+ EFI_PEI_BLOCK_IO_MEDIA Media;\r
+ UINT8 SlotNum;\r
+ UINT8 MediaNum;\r
+ UINT8 Location;\r
+ BOOLEAN Found;\r
+\r
+ Found = FALSE;\r
+ Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);\r
+\r
+ Status = EmmcBlockIoPeimGetMediaInfo (\r
+ PeiServices,\r
+ &Private->BlkIoPpi,\r
+ DeviceIndex,\r
+ &Media\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Location = 0;\r
+ MediaNum = 0;\r
+ for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {\r
+ for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {\r
+ Location ++;\r
+ if (Location == DeviceIndex) {\r
+ Found = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ if (Found) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ CopyMem (MediaInfo, &(Private->Slot[SlotNum].Media[MediaNum]), sizeof (EFI_PEI_BLOCK_IO2_MEDIA));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Reads the requested number of blocks from the specified block device.\r
+\r
+ The function reads the requested number of blocks from the device. All the\r
+ blocks are read, or an error is returned. If there is no media in the device,\r
+ the function returns EFI_NO_MEDIA.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to\r
+ every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, PPIs that\r
+ want to talk to a single device must specify the device\r
+ index that was assigned during the enumeration process.\r
+ This index is a number from one to NumberBlockDevices.\r
+ @param[in] StartLBA The starting logical block address (LBA) to read from\r
+ on the device\r
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be\r
+ a multiple of the intrinsic block size of the device.\r
+ @param[out] Buffer A pointer to the destination buffer for the data.\r
+ The caller is responsible for the ownership of the\r
+ buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
+ to perform the read operation.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
+ valid, or the buffer is not properly aligned.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
+ the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimReadBlocks2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ IN EFI_PEI_LBA StartLBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_PEIM_HC_PRIVATE_DATA *Private;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);\r
+\r
+ Status = EmmcBlockIoPeimReadBlocks (\r
+ PeiServices,\r
+ &Private->BlkIoPpi,\r
+ DeviceIndex,\r
+ StartLBA,\r
+ BufferSize,\r
+ Buffer\r
+ );\r
+ return Status;\r
+}\r
+\r
+/**\r
+ The user code starts with this function.\r
+\r
+ @param FileHandle Handle of the file being invoked.\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+\r
+ @retval EFI_SUCCESS The driver is successfully initialized.\r
+ @retval Others Can't initialize the driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeEmmcBlockIoPeim (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_PEIM_HC_PRIVATE_DATA *Private;\r
+ EDKII_SD_MMC_HOST_CONTROLLER_PPI *SdMmcHcPpi;\r
+ UINT32 Index;\r
+ UINT32 PartitionIndex;\r
+ UINTN *MmioBase;\r
+ UINT8 BarNum;\r
+ UINT8 SlotNum;\r
+ UINT8 MediaNum;\r
+ UINT8 Controller;\r
+ UINT64 Capacity;\r
+ EMMC_EXT_CSD *ExtCsd;\r
+ EMMC_HC_SLOT_CAP Capability;\r
+ EMMC_PEIM_HC_SLOT *Slot;\r
+ UINT32 SecCount;\r
+ UINT32 GpSizeMult;\r
+\r
+ //\r
+ // Shadow this PEIM to run from memory\r
+ //\r
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // locate Emmc host controller PPI\r
+ //\r
+ Status = PeiServicesLocatePpi (\r
+ &gEdkiiPeiSdMmcHostControllerPpiGuid,\r
+ 0,\r
+ NULL,\r
+ (VOID **) &SdMmcHcPpi\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Controller = 0;\r
+ MmioBase = NULL;\r
+ while (TRUE) {\r
+ Status = SdMmcHcPpi->GetSdMmcHcMmioBar (SdMmcHcPpi, Controller, &MmioBase, &BarNum);\r
+ //\r
+ // When status is error, meant no controller is found\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ if (BarNum == 0) {\r
+ Controller++;\r
+ continue;\r
+ }\r
+\r
+ Private = AllocateCopyPool (sizeof (EMMC_PEIM_HC_PRIVATE_DATA), &gEmmcHcPrivateTemplate);\r
+ if (Private == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ break;\r
+ }\r
+ Private->BlkIoPpiList.Ppi = (VOID*)&Private->BlkIoPpi;\r
+ Private->BlkIo2PpiList.Ppi = (VOID*)&Private->BlkIo2Ppi;\r
+ //\r
+ // Initialize the memory pool which will be used in all transactions.\r
+ //\r
+ Status = EmmcPeimInitMemPool (Private);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ break;\r
+ }\r
+\r
+ for (Index = 0; Index < BarNum; Index++) {\r
+ Status = EmmcPeimHcGetCapability (MmioBase[Index], &Capability);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ if (Capability.SlotType != 0x1) {\r
+ DEBUG ((EFI_D_INFO, "The slot at 0x%x is not embedded slot type\n", MmioBase[Index]));\r
+ Status = EFI_UNSUPPORTED;\r
+ continue;\r
+ }\r
+\r
+ Status = EmmcPeimHcReset (MmioBase[Index]);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ Status = EmmcPeimHcCardDetect (MmioBase[Index]);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ Status = EmmcPeimHcInitHost (MmioBase[Index]);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ SlotNum = Private->SlotNum;\r
+ Slot = &Private->Slot[SlotNum];\r
+ CopyMem (Slot, &gEmmcHcSlotTemplate, sizeof (EMMC_PEIM_HC_SLOT));\r
+ Slot->Private = Private;\r
+ Slot->EmmcHcBase = MmioBase[Index];\r
+ CopyMem (&Slot->Capability, &Capability, sizeof (Capability));\r
+\r
+ Status = EmmcPeimIdentification (Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ ExtCsd = &Slot->ExtCsd;\r
+ if (ExtCsd->ExtCsdRev < 5) {\r
+ DEBUG ((EFI_D_ERROR, "The EMMC device version is too low, we don't support!!!\n"));\r
+ Status = EFI_UNSUPPORTED;\r
+ continue;\r
+ }\r
+ if ((ExtCsd->PartitioningSupport & BIT0) != BIT0) {\r
+ DEBUG ((EFI_D_ERROR, "The EMMC device doesn't support Partition Feature!!!\n"));\r
+ Status = EFI_UNSUPPORTED;\r
+ continue;\r
+ }\r
+\r
+ for (PartitionIndex = 0; PartitionIndex < EMMC_PEIM_MAX_PARTITIONS; PartitionIndex++) {\r
+ switch (PartitionIndex) {\r
+ case EmmcPartitionUserData:\r
+ SecCount = *(UINT32*)&ExtCsd->SecCount;\r
+ Capacity = MultU64x32 ((UINT64)SecCount, 0x200);\r
+ break;\r
+ case EmmcPartitionBoot1:\r
+ case EmmcPartitionBoot2:\r
+ Capacity = ExtCsd->BootSizeMult * SIZE_128KB;\r
+ break;\r
+ case EmmcPartitionRPMB:\r
+ Capacity = ExtCsd->RpmbSizeMult * SIZE_128KB;\r
+ break;\r
+ case EmmcPartitionGP1:\r
+ GpSizeMult = (ExtCsd->GpSizeMult[0] | (ExtCsd->GpSizeMult[1] << 8) | (ExtCsd->GpSizeMult[2] << 16));\r
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
+ break;\r
+ case EmmcPartitionGP2:\r
+ GpSizeMult = (ExtCsd->GpSizeMult[3] | (ExtCsd->GpSizeMult[4] << 8) | (ExtCsd->GpSizeMult[5] << 16));\r
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
+ break;\r
+ case EmmcPartitionGP3:\r
+ GpSizeMult = (ExtCsd->GpSizeMult[6] | (ExtCsd->GpSizeMult[7] << 8) | (ExtCsd->GpSizeMult[8] << 16));\r
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
+ break;\r
+ case EmmcPartitionGP4:\r
+ GpSizeMult = (ExtCsd->GpSizeMult[9] | (ExtCsd->GpSizeMult[10] << 8) | (ExtCsd->GpSizeMult[11] << 16));\r
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ continue;\r
+ }\r
+\r
+ MediaNum = Slot->MediaNum;\r
+ if (Capacity != 0) {\r
+ Slot->Media[MediaNum].LastBlock = DivU64x32 (Capacity, Slot->Media[MediaNum].BlockSize) - 1;\r
+ Slot->PartitionType[MediaNum] = PartitionIndex;\r
+ Private->TotalBlkIoDevices++;\r
+ Slot->MediaNum++;\r
+ }\r
+ }\r
+ Private->SlotNum++;\r
+ }\r
+ Controller++;\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ PeiServicesInstallPpi (&Private->BlkIoPpiList);\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EMMC_BLOCK_IO_PEI_H_\r
+#define _EMMC_BLOCK_IO_PEI_H_\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/SdMmcHostController.h>\r
+#include <Ppi/BlockIo.h>\r
+#include <Ppi/BlockIo2.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+\r
+#include <IndustryStandard/Emmc.h>\r
+\r
+typedef struct _EMMC_PEIM_HC_PRIVATE_DATA EMMC_PEIM_HC_PRIVATE_DATA;\r
+typedef struct _EMMC_PEIM_HC_SLOT EMMC_PEIM_HC_SLOT;\r
+typedef struct _EMMC_TRB EMMC_TRB;\r
+\r
+#include "EmmcHci.h"\r
+#include "EmmcHcMem.h"\r
+\r
+#define EMMC_PEIM_SIG SIGNATURE_32 ('E', 'M', 'C', 'P')\r
+#define EMMC_PEIM_SLOT_SIG SIGNATURE_32 ('E', 'M', 'C', 'S')\r
+\r
+#define EMMC_PEIM_MAX_SLOTS 6\r
+#define EMMC_PEIM_MAX_PARTITIONS 8\r
+\r
+struct _EMMC_PEIM_HC_SLOT {\r
+ UINT32 Signature;\r
+ EFI_PEI_BLOCK_IO2_MEDIA Media[EMMC_PEIM_MAX_PARTITIONS];\r
+ UINT8 MediaNum;\r
+ EMMC_PARTITION_TYPE PartitionType[EMMC_PEIM_MAX_PARTITIONS];\r
+\r
+ UINTN EmmcHcBase;\r
+ EMMC_HC_SLOT_CAP Capability;\r
+ EMMC_CSD Csd;\r
+ EMMC_EXT_CSD ExtCsd;\r
+ BOOLEAN SectorAddressing;\r
+ EMMC_PEIM_HC_PRIVATE_DATA *Private;\r
+};\r
+\r
+struct _EMMC_PEIM_HC_PRIVATE_DATA {\r
+ UINT32 Signature;\r
+ EMMC_PEIM_MEM_POOL *Pool;\r
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi;\r
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI BlkIo2Ppi;\r
+ EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList;\r
+ EFI_PEI_PPI_DESCRIPTOR BlkIo2PpiList;\r
+ EMMC_PEIM_HC_SLOT Slot[EMMC_PEIM_MAX_SLOTS];\r
+ UINT8 SlotNum;\r
+ UINT8 TotalBlkIoDevices;\r
+};\r
+\r
+#define EMMC_TIMEOUT MultU64x32((UINT64)(3), 1000000)\r
+#define GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS(a) CR (a, EMMC_PEIM_HC_PRIVATE_DATA, BlkIoPpi, EMMC_PEIM_SIG)\r
+#define GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2(a) CR (a, EMMC_PEIM_HC_PRIVATE_DATA, BlkIo2Ppi, EMMC_PEIM_SIG)\r
+\r
+struct _EMMC_TRB {\r
+ EMMC_PEIM_HC_SLOT *Slot;\r
+ UINT16 BlockSize;\r
+\r
+ EMMC_COMMAND_PACKET *Packet;\r
+ VOID *Data;\r
+ UINT32 DataLen;\r
+ BOOLEAN Read;\r
+ EMMC_HC_TRANSFER_MODE Mode;\r
+\r
+ UINT64 Timeout;\r
+\r
+ EMMC_HC_ADMA_DESC_LINE *AdmaDesc;\r
+ UINTN AdmaDescSize;\r
+};\r
+\r
+/**\r
+ Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+ This function is used for getting the count of block I/O devices that one\r
+ specific block driver detects. To the PEI ATAPI driver, it returns the number\r
+ of all the detected ATAPI devices it detects during the enumeration process.\r
+ To the PEI legacy floppy driver, it returns the number of all the legacy\r
+ devices it finds during its enumeration process. If no device is detected,\r
+ then the function will return zero.\r
+\r
+ @param[in] PeiServices General-purpose services that are available\r
+ to every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI\r
+ instance.\r
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.\r
+\r
+ @retval EFI_SUCCESS The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimGetDeviceNo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ OUT UINTN *NumberBlockDevices\r
+ );\r
+\r
+/**\r
+ Gets a block device's media information.\r
+\r
+ This function will provide the caller with the specified block device's media\r
+ information. If the media changes, calling this function will update the media\r
+ information accordingly.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, the PPIs that\r
+ want to talk to a single device must specify the\r
+ device index that was assigned during the enumeration\r
+ process. This index is a number from one to\r
+ NumberBlockDevices.\r
+ @param[out] MediaInfo The media information of the specified block media.\r
+ The caller is responsible for the ownership of this\r
+ data structure.\r
+\r
+ @par Note:\r
+ The MediaInfo structure describes an enumeration of possible block device\r
+ types. This enumeration exists because no device paths are actually passed\r
+ across interfaces that describe the type or class of hardware that is publishing\r
+ the block I/O interface. This enumeration will allow for policy decisions\r
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+ by a given device type, they should be reported in ascending order; this\r
+ order also applies to nested partitions, such as legacy MBR, where the\r
+ outermost partitions would have precedence in the reporting order. The\r
+ same logic applies to systems such as IDE that have precedence relationships\r
+ like "Master/Slave" or "Primary/Secondary". The master device should be\r
+ reported first, the slave second.\r
+\r
+ @retval EFI_SUCCESS Media information about the specified block device\r
+ was obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware\r
+ error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimGetMediaInfo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo\r
+ );\r
+\r
+/**\r
+ Reads the requested number of blocks from the specified block device.\r
+\r
+ The function reads the requested number of blocks from the device. All the\r
+ blocks are read, or an error is returned. If there is no media in the device,\r
+ the function returns EFI_NO_MEDIA.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to\r
+ every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, PPIs that\r
+ want to talk to a single device must specify the device\r
+ index that was assigned during the enumeration process.\r
+ This index is a number from one to NumberBlockDevices.\r
+ @param[in] StartLBA The starting logical block address (LBA) to read from\r
+ on the device\r
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be\r
+ a multiple of the intrinsic block size of the device.\r
+ @param[out] Buffer A pointer to the destination buffer for the data.\r
+ The caller is responsible for the ownership of the\r
+ buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
+ to perform the read operation.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
+ valid, or the buffer is not properly aligned.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
+ the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimReadBlocks (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ IN EFI_PEI_LBA StartLBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+ This function is used for getting the count of block I/O devices that one\r
+ specific block driver detects. To the PEI ATAPI driver, it returns the number\r
+ of all the detected ATAPI devices it detects during the enumeration process.\r
+ To the PEI legacy floppy driver, it returns the number of all the legacy\r
+ devices it finds during its enumeration process. If no device is detected,\r
+ then the function will return zero.\r
+\r
+ @param[in] PeiServices General-purpose services that are available\r
+ to every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI\r
+ instance.\r
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.\r
+\r
+ @retval EFI_SUCCESS The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimGetDeviceNo2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ OUT UINTN *NumberBlockDevices\r
+ );\r
+\r
+/**\r
+ Gets a block device's media information.\r
+\r
+ This function will provide the caller with the specified block device's media\r
+ information. If the media changes, calling this function will update the media\r
+ information accordingly.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, the PPIs that\r
+ want to talk to a single device must specify the\r
+ device index that was assigned during the enumeration\r
+ process. This index is a number from one to\r
+ NumberBlockDevices.\r
+ @param[out] MediaInfo The media information of the specified block media.\r
+ The caller is responsible for the ownership of this\r
+ data structure.\r
+\r
+ @par Note:\r
+ The MediaInfo structure describes an enumeration of possible block device\r
+ types. This enumeration exists because no device paths are actually passed\r
+ across interfaces that describe the type or class of hardware that is publishing\r
+ the block I/O interface. This enumeration will allow for policy decisions\r
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+ by a given device type, they should be reported in ascending order; this\r
+ order also applies to nested partitions, such as legacy MBR, where the\r
+ outermost partitions would have precedence in the reporting order. The\r
+ same logic applies to systems such as IDE that have precedence relationships\r
+ like "Master/Slave" or "Primary/Secondary". The master device should be\r
+ reported first, the slave second.\r
+\r
+ @retval EFI_SUCCESS Media information about the specified block device\r
+ was obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware\r
+ error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimGetMediaInfo2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo\r
+ );\r
+\r
+/**\r
+ Reads the requested number of blocks from the specified block device.\r
+\r
+ The function reads the requested number of blocks from the device. All the\r
+ blocks are read, or an error is returned. If there is no media in the device,\r
+ the function returns EFI_NO_MEDIA.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to\r
+ every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, PPIs that\r
+ want to talk to a single device must specify the device\r
+ index that was assigned during the enumeration process.\r
+ This index is a number from one to NumberBlockDevices.\r
+ @param[in] StartLBA The starting logical block address (LBA) to read from\r
+ on the device\r
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be\r
+ a multiple of the intrinsic block size of the device.\r
+ @param[out] Buffer A pointer to the destination buffer for the data.\r
+ The caller is responsible for the ownership of the\r
+ buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
+ to perform the read operation.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
+ valid, or the buffer is not properly aligned.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
+ the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimReadBlocks2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ IN EFI_PEI_LBA StartLBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Initialize the memory management pool for the host controller.\r
+\r
+ @param Private The Emmc Peim driver private data.\r
+\r
+ @retval EFI_SUCCESS The memory pool is initialized.\r
+ @retval Others Fail to init the memory pool.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimInitMemPool (\r
+ IN EMMC_PEIM_HC_PRIVATE_DATA *Private\r
+ );\r
+\r
+/**\r
+ Allocate some memory from the host controller's memory pool\r
+ which can be used to communicate with host controller.\r
+\r
+ @param Pool The host controller's memory pool.\r
+ @param Size Size of the memory to allocate.\r
+\r
+ @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+EmmcPeimAllocateMem (\r
+ IN EMMC_PEIM_MEM_POOL *Pool,\r
+ IN UINTN Size\r
+ );\r
+\r
+/**\r
+ Free the allocated memory back to the memory pool.\r
+\r
+ @param Pool The memory pool of the host controller.\r
+ @param Mem The memory to free.\r
+ @param Size The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+EmmcPeimFreeMem (\r
+ IN EMMC_PEIM_MEM_POOL *Pool,\r
+ IN VOID *Mem,\r
+ IN UINTN Size\r
+ );\r
+\r
+#endif\r
--- /dev/null
+## @file\r
+# Description file for the Embedded MMC (eMMC) Peim driver.\r
+#\r
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = EmmcBlockIoPei\r
+ MODULE_UNI_FILE = EmmcBlockIoPei.uni\r
+ FILE_GUID = 7F06A90F-AE0D-4887-82C0-FEC7F4F68B29\r
+ MODULE_TYPE = PEIM\r
+ VERSION_STRING = 1.0\r
+\r
+ ENTRY_POINT = InitializeEmmcBlockIoPeim\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ EmmcBlockIoPei.c\r
+ EmmcBlockIoPei.h\r
+ EmmcHci.c\r
+ EmmcHci.h\r
+ EmmcHcMem.c\r
+ EmmcHcMem.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+ IoLib\r
+ TimerLib\r
+ BaseMemoryLib\r
+ PeimEntryPoint\r
+ PeiServicesLib\r
+ DebugLib\r
+\r
+[Ppis]\r
+ gEfiPeiVirtualBlockIoPpiGuid ## PRODUCES\r
+ gEfiPeiVirtualBlockIo2PpiGuid ## PRODUCES\r
+ gEdkiiPeiSdMmcHostControllerPpiGuid ## CONSUMES\r
+\r
+[Depex]\r
+ gEfiPeiMemoryDiscoveredPpiGuid AND gEdkiiPeiSdMmcHostControllerPpiGuid\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+ EmmcBlockIoPeiExtra.uni\r
+\r
--- /dev/null
+// /** @file\r
+// The EmmcBlockIoPei driver is used to support recovery from EMMC device.\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions\r
+// of the BSD License which accompanies this distribution. The\r
+// full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "Support recovery from EMMC devices"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "The EmmcBlockIoPei driver is used to support recovery from EMMC device."\r
+\r
--- /dev/null
+// /** @file\r
+// EmmcBlockIoPei Localized Strings and Content\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions\r
+// of the BSD License which accompanies this distribution. The\r
+// full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+#string STR_PROPERTIES_MODULE_NAME\r
+#language en-US\r
+"EMMC BlockIo Peim for Recovery"\r
+\r
+\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "EmmcBlockIoPei.h"\r
+\r
+/**\r
+ Allocate a block of memory to be used by the buffer pool.\r
+\r
+ @param Pages How many pages to allocate.\r
+\r
+ @return The allocated memory block or NULL if failed.\r
+\r
+**/\r
+EMMC_PEIM_MEM_BLOCK *\r
+EmmcPeimAllocMemBlock (\r
+ IN UINTN Pages\r
+ )\r
+{\r
+ EMMC_PEIM_MEM_BLOCK *Block;\r
+ EFI_STATUS Status;\r
+ VOID *TempPtr;\r
+ EFI_PHYSICAL_ADDRESS Address;\r
+\r
+ TempPtr = NULL;\r
+ Block = NULL;\r
+\r
+ Status = PeiServicesAllocatePool (sizeof(EMMC_PEIM_MEM_BLOCK), &TempPtr);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ ZeroMem ((VOID*)(UINTN)TempPtr, sizeof(EMMC_PEIM_MEM_BLOCK));\r
+\r
+ //\r
+ // each bit in the bit array represents EMMC_PEIM_MEM_UNIT\r
+ // bytes of memory in the memory block.\r
+ //\r
+ ASSERT (EMMC_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
+\r
+ Block = (EMMC_PEIM_MEM_BLOCK*)(UINTN)TempPtr;\r
+ Block->BufLen = EFI_PAGES_TO_SIZE (Pages);\r
+ Block->BitsLen = Block->BufLen / (EMMC_PEIM_MEM_UNIT * 8);\r
+\r
+ Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ ZeroMem ((VOID*)(UINTN)TempPtr, Block->BitsLen);\r
+\r
+ Block->Bits = (UINT8*)(UINTN)TempPtr;\r
+\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ Pages,\r
+ &Address\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ ZeroMem ((VOID*)(UINTN)Address, EFI_PAGES_TO_SIZE (Pages));\r
+\r
+ Block->Buf = (UINT8*)((UINTN)Address);\r
+ Block->Next = NULL;\r
+\r
+ return Block;\r
+}\r
+\r
+/**\r
+ Free the memory block from the memory pool.\r
+\r
+ @param Pool The memory pool to free the block from.\r
+ @param Block The memory block to free.\r
+\r
+**/\r
+VOID\r
+EmmcPeimFreeMemBlock (\r
+ IN EMMC_PEIM_MEM_POOL *Pool,\r
+ IN EMMC_PEIM_MEM_BLOCK *Block\r
+ )\r
+{\r
+ ASSERT ((Pool != NULL) && (Block != NULL));\r
+}\r
+\r
+/**\r
+ Alloc some memory from the block.\r
+\r
+ @param Block The memory block to allocate memory from.\r
+ @param Units Number of memory units to allocate.\r
+\r
+ @return The pointer to the allocated memory. If couldn't allocate the needed memory,\r
+ the return value is NULL.\r
+\r
+**/\r
+VOID *\r
+EmmcPeimAllocMemFromBlock (\r
+ IN EMMC_PEIM_MEM_BLOCK *Block,\r
+ IN UINTN Units\r
+ )\r
+{\r
+ UINTN Byte;\r
+ UINT8 Bit;\r
+ UINTN StartByte;\r
+ UINT8 StartBit;\r
+ UINTN Available;\r
+ UINTN Count;\r
+\r
+ ASSERT ((Block != 0) && (Units != 0));\r
+\r
+ StartByte = 0;\r
+ StartBit = 0;\r
+ Available = 0;\r
+\r
+ for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
+ //\r
+ // If current bit is zero, the corresponding memory unit is\r
+ // available, otherwise we need to restart our searching.\r
+ // Available counts the consective number of zero bit.\r
+ //\r
+ if (!EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
+ Available++;\r
+\r
+ if (Available >= Units) {\r
+ break;\r
+ }\r
+\r
+ EMMC_PEIM_NEXT_BIT (Byte, Bit);\r
+\r
+ } else {\r
+ EMMC_PEIM_NEXT_BIT (Byte, Bit);\r
+\r
+ Available = 0;\r
+ StartByte = Byte;\r
+ StartBit = Bit;\r
+ }\r
+ }\r
+\r
+ if (Available < Units) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Mark the memory as allocated\r
+ //\r
+ Byte = StartByte;\r
+ Bit = StartBit;\r
+\r
+ for (Count = 0; Count < Units; Count++) {\r
+ ASSERT (!EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) EMMC_PEIM_MEM_BIT (Bit));\r
+ EMMC_PEIM_NEXT_BIT (Byte, Bit);\r
+ }\r
+\r
+ return Block->Buf + (StartByte * 8 + StartBit) * EMMC_PEIM_MEM_UNIT;\r
+}\r
+\r
+/**\r
+ Insert the memory block to the pool's list of the blocks.\r
+\r
+ @param Head The head of the memory pool's block list.\r
+ @param Block The memory block to insert.\r
+\r
+**/\r
+VOID\r
+EmmcPeimInsertMemBlockToPool (\r
+ IN EMMC_PEIM_MEM_BLOCK *Head,\r
+ IN EMMC_PEIM_MEM_BLOCK *Block\r
+ )\r
+{\r
+ ASSERT ((Head != NULL) && (Block != NULL));\r
+ Block->Next = Head->Next;\r
+ Head->Next = Block;\r
+}\r
+\r
+/**\r
+ Is the memory block empty?\r
+\r
+ @param Block The memory block to check.\r
+\r
+ @retval TRUE The memory block is empty.\r
+ @retval FALSE The memory block isn't empty.\r
+\r
+**/\r
+BOOLEAN\r
+EmmcPeimIsMemBlockEmpty (\r
+ IN EMMC_PEIM_MEM_BLOCK *Block\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+\r
+ for (Index = 0; Index < Block->BitsLen; Index++) {\r
+ if (Block->Bits[Index] != 0) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Unlink the memory block from the pool's list.\r
+\r
+ @param Head The block list head of the memory's pool.\r
+ @param BlockToUnlink The memory block to unlink.\r
+\r
+**/\r
+VOID\r
+EmmcPeimUnlinkMemBlock (\r
+ IN EMMC_PEIM_MEM_BLOCK *Head,\r
+ IN EMMC_PEIM_MEM_BLOCK *BlockToUnlink\r
+ )\r
+{\r
+ EMMC_PEIM_MEM_BLOCK *Block;\r
+\r
+ ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
+\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ if (Block->Next == BlockToUnlink) {\r
+ Block->Next = BlockToUnlink->Next;\r
+ BlockToUnlink->Next = NULL;\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Initialize the memory management pool for the host controller.\r
+\r
+ @param Private The Emmc Peim driver private data.\r
+\r
+ @retval EFI_SUCCESS The memory pool is initialized.\r
+ @retval Others Fail to init the memory pool.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimInitMemPool (\r
+ IN EMMC_PEIM_HC_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ EMMC_PEIM_MEM_POOL *Pool;\r
+ EFI_STATUS Status;\r
+ VOID *TempPtr;\r
+\r
+ TempPtr = NULL;\r
+ Pool = NULL;\r
+\r
+ Status = PeiServicesAllocatePool (sizeof (EMMC_PEIM_MEM_POOL), &TempPtr);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ ZeroMem ((VOID*)(UINTN)TempPtr, sizeof (EMMC_PEIM_MEM_POOL));\r
+\r
+ Pool = (EMMC_PEIM_MEM_POOL *)((UINTN)TempPtr);\r
+\r
+ Pool->Head = EmmcPeimAllocMemBlock (EMMC_PEIM_MEM_DEFAULT_PAGES);\r
+\r
+ if (Pool->Head == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Private->Pool = Pool;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Release the memory management pool.\r
+\r
+ @param Pool The memory pool to free.\r
+\r
+ @retval EFI_DEVICE_ERROR Fail to free the memory pool.\r
+ @retval EFI_SUCCESS The memory pool is freed.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimFreeMemPool (\r
+ IN EMMC_PEIM_MEM_POOL *Pool\r
+ )\r
+{\r
+ EMMC_PEIM_MEM_BLOCK *Block;\r
+\r
+ ASSERT (Pool->Head != NULL);\r
+\r
+ //\r
+ // Unlink all the memory blocks from the pool, then free them.\r
+ // EmmcPeimUnlinkMemBlock can't be used to unlink and free the\r
+ // first block.\r
+ //\r
+ for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
+ EmmcPeimFreeMemBlock (Pool, Block);\r
+ }\r
+\r
+ EmmcPeimFreeMemBlock (Pool, Pool->Head);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Allocate some memory from the host controller's memory pool\r
+ which can be used to communicate with host controller.\r
+\r
+ @param Pool The host controller's memory pool.\r
+ @param Size Size of the memory to allocate.\r
+\r
+ @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+EmmcPeimAllocateMem (\r
+ IN EMMC_PEIM_MEM_POOL *Pool,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ EMMC_PEIM_MEM_BLOCK *Head;\r
+ EMMC_PEIM_MEM_BLOCK *Block;\r
+ EMMC_PEIM_MEM_BLOCK *NewBlock;\r
+ VOID *Mem;\r
+ UINTN AllocSize;\r
+ UINTN Pages;\r
+\r
+ Mem = NULL;\r
+ AllocSize = EMMC_PEIM_MEM_ROUND (Size);\r
+ Head = Pool->Head;\r
+ ASSERT (Head != NULL);\r
+\r
+ //\r
+ // First check whether current memory blocks can satisfy the allocation.\r
+ //\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ Mem = EmmcPeimAllocMemFromBlock (Block, AllocSize / EMMC_PEIM_MEM_UNIT);\r
+\r
+ if (Mem != NULL) {\r
+ ZeroMem (Mem, Size);\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Mem != NULL) {\r
+ return Mem;\r
+ }\r
+\r
+ //\r
+ // Create a new memory block if there is not enough memory\r
+ // in the pool. If the allocation size is larger than the\r
+ // default page number, just allocate a large enough memory\r
+ // block. Otherwise allocate default pages.\r
+ //\r
+ if (AllocSize > EFI_PAGES_TO_SIZE (EMMC_PEIM_MEM_DEFAULT_PAGES)) {\r
+ Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
+ } else {\r
+ Pages = EMMC_PEIM_MEM_DEFAULT_PAGES;\r
+ }\r
+\r
+ NewBlock = EmmcPeimAllocMemBlock (Pages);\r
+ if (NewBlock == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Add the new memory block to the pool, then allocate memory from it\r
+ //\r
+ EmmcPeimInsertMemBlockToPool (Head, NewBlock);\r
+ Mem = EmmcPeimAllocMemFromBlock (NewBlock, AllocSize / EMMC_PEIM_MEM_UNIT);\r
+\r
+ if (Mem != NULL) {\r
+ ZeroMem (Mem, Size);\r
+ }\r
+\r
+ return Mem;\r
+}\r
+\r
+/**\r
+ Free the allocated memory back to the memory pool.\r
+\r
+ @param Pool The memory pool of the host controller.\r
+ @param Mem The memory to free.\r
+ @param Size The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+EmmcPeimFreeMem (\r
+ IN EMMC_PEIM_MEM_POOL *Pool,\r
+ IN VOID *Mem,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ EMMC_PEIM_MEM_BLOCK *Head;\r
+ EMMC_PEIM_MEM_BLOCK *Block;\r
+ UINT8 *ToFree;\r
+ UINTN AllocSize;\r
+ UINTN Byte;\r
+ UINTN Bit;\r
+ UINTN Count;\r
+\r
+ Head = Pool->Head;\r
+ AllocSize = EMMC_PEIM_MEM_ROUND (Size);\r
+ ToFree = (UINT8 *) Mem;\r
+\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ //\r
+ // scan the memory block list for the memory block that\r
+ // completely contains the memory to free.\r
+ //\r
+ if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
+ //\r
+ // compute the start byte and bit in the bit array\r
+ //\r
+ Byte = ((ToFree - Block->Buf) / EMMC_PEIM_MEM_UNIT) / 8;\r
+ Bit = ((ToFree - Block->Buf) / EMMC_PEIM_MEM_UNIT) % 8;\r
+\r
+ //\r
+ // reset associated bits in bit arry\r
+ //\r
+ for (Count = 0; Count < (AllocSize / EMMC_PEIM_MEM_UNIT); Count++) {\r
+ ASSERT (EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ EMMC_PEIM_MEM_BIT (Bit));\r
+ EMMC_PEIM_NEXT_BIT (Byte, Bit);\r
+ }\r
+\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If Block == NULL, it means that the current memory isn't\r
+ // in the host controller's pool. This is critical because\r
+ // the caller has passed in a wrong memory point\r
+ //\r
+ ASSERT (Block != NULL);\r
+\r
+ //\r
+ // Release the current memory block if it is empty and not the head\r
+ //\r
+ if ((Block != Head) && EmmcPeimIsMemBlockEmpty (Block)) {\r
+ EmmcPeimFreeMemBlock (Pool, Block);\r
+ }\r
+\r
+ return ;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EMMC_PEIM_MEM_H_\r
+#define _EMMC_PEIM_MEM_H_\r
+\r
+#define EMMC_PEIM_MEM_BIT(a) ((UINTN)(1 << (a)))\r
+\r
+#define EMMC_PEIM_MEM_BIT_IS_SET(Data, Bit) \\r
+ ((BOOLEAN)(((Data) & EMMC_PEIM_MEM_BIT(Bit)) == EMMC_PEIM_MEM_BIT(Bit)))\r
+\r
+typedef struct _EMMC_PEIM_MEM_BLOCK EMMC_PEIM_MEM_BLOCK;\r
+\r
+struct _EMMC_PEIM_MEM_BLOCK {\r
+ UINT8 *Bits; // Bit array to record which unit is allocated\r
+ UINTN BitsLen;\r
+ UINT8 *Buf;\r
+ UINTN BufLen; // Memory size in bytes\r
+ EMMC_PEIM_MEM_BLOCK *Next;\r
+};\r
+\r
+typedef struct _EMMC_PEIM_MEM_POOL {\r
+ EMMC_PEIM_MEM_BLOCK *Head;\r
+} EMMC_PEIM_MEM_POOL;\r
+\r
+//\r
+// Memory allocation unit, note that the value must meet EMMC spec alignment requirement.\r
+//\r
+#define EMMC_PEIM_MEM_UNIT 128\r
+\r
+#define EMMC_PEIM_MEM_UNIT_MASK (EMMC_PEIM_MEM_UNIT - 1)\r
+#define EMMC_PEIM_MEM_DEFAULT_PAGES 16\r
+\r
+#define EMMC_PEIM_MEM_ROUND(Len) (((Len) + EMMC_PEIM_MEM_UNIT_MASK) & (~EMMC_PEIM_MEM_UNIT_MASK))\r
+\r
+//\r
+// Advance the byte and bit to the next bit, adjust byte accordingly.\r
+//\r
+#define EMMC_PEIM_NEXT_BIT(Byte, Bit) \\r
+ do { \\r
+ (Bit)++; \\r
+ if ((Bit) > 7) { \\r
+ (Byte)++; \\r
+ (Bit) = 0; \\r
+ } \\r
+ } while (0)\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "EmmcBlockIoPei.h"\r
+\r
+/**\r
+ Read/Write specified EMMC host controller mmio register.\r
+\r
+ @param[in] Address The address of the mmio register to be read/written.\r
+ @param[in] Read A boolean to indicate it's read or write operation.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2 , 4 or 8 bytes.\r
+ @param[in, out] Data For read operations, the destination buffer to store\r
+ the results. For write operations, the source buffer\r
+ to write data from. The caller is responsible for\r
+ having ownership of the data buffer and ensuring its\r
+ size not less than Count bytes.\r
+\r
+ @retval EFI_INVALID_PARAMETER The Address or the Data or the Count is not valid.\r
+ @retval EFI_SUCCESS The read/write operation succeeds.\r
+ @retval Others The read/write operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcPeimHcRwMmio (\r
+ IN UINTN Address,\r
+ IN BOOLEAN Read,\r
+ IN UINT8 Count,\r
+ IN OUT VOID *Data\r
+ )\r
+{\r
+ if ((Address == 0) || (Data == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ switch (Count) {\r
+ case 1:\r
+ if (Read) {\r
+ *(UINT8*)Data = MmioRead8 (Address);\r
+ } else {\r
+ MmioWrite8 (Address, *(UINT8*)Data);\r
+ }\r
+ break;\r
+ case 2:\r
+ if (Read) {\r
+ *(UINT16*)Data = MmioRead16 (Address);\r
+ } else {\r
+ MmioWrite16 (Address, *(UINT16*)Data);\r
+ }\r
+ break;\r
+ case 4:\r
+ if (Read) {\r
+ *(UINT32*)Data = MmioRead32 (Address);\r
+ } else {\r
+ MmioWrite32 (Address, *(UINT32*)Data);\r
+ }\r
+ break;\r
+ case 8:\r
+ if (Read) {\r
+ *(UINT64*)Data = MmioRead64 (Address);\r
+ } else {\r
+ MmioWrite64 (Address, *(UINT64*)Data);\r
+ }\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Do OR operation with the value of the specified EMMC host controller mmio register.\r
+\r
+ @param[in] Address The address of the mmio register to be read/written.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2 , 4 or 8 bytes.\r
+ @param[in] OrData The pointer to the data used to do OR operation.\r
+ The caller is responsible for having ownership of\r
+ the data buffer and ensuring its size not less than\r
+ Count bytes.\r
+\r
+ @retval EFI_INVALID_PARAMETER The Address or the OrData or the Count is not valid.\r
+ @retval EFI_SUCCESS The OR operation succeeds.\r
+ @retval Others The OR operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcPeimHcOrMmio (\r
+ IN UINTN Address,\r
+ IN UINT8 Count,\r
+ IN VOID *OrData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 Data;\r
+ UINT64 Or;\r
+\r
+ Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Data);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Count == 1) {\r
+ Or = *(UINT8*) OrData;\r
+ } else if (Count == 2) {\r
+ Or = *(UINT16*) OrData;\r
+ } else if (Count == 4) {\r
+ Or = *(UINT32*) OrData;\r
+ } else if (Count == 8) {\r
+ Or = *(UINT64*) OrData;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Data |= Or;\r
+ Status = EmmcPeimHcRwMmio (Address, FALSE, Count, &Data);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Do AND operation with the value of the specified EMMC host controller mmio register.\r
+\r
+ @param[in] Address The address of the mmio register to be read/written.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2 , 4 or 8 bytes.\r
+ @param[in] AndData The pointer to the data used to do AND operation.\r
+ The caller is responsible for having ownership of\r
+ the data buffer and ensuring its size not less than\r
+ Count bytes.\r
+\r
+ @retval EFI_INVALID_PARAMETER The Address or the AndData or the Count is not valid.\r
+ @retval EFI_SUCCESS The AND operation succeeds.\r
+ @retval Others The AND operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcPeimHcAndMmio (\r
+ IN UINTN Address,\r
+ IN UINT8 Count,\r
+ IN VOID *AndData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 Data;\r
+ UINT64 And;\r
+\r
+ Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Data);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Count == 1) {\r
+ And = *(UINT8*) AndData;\r
+ } else if (Count == 2) {\r
+ And = *(UINT16*) AndData;\r
+ } else if (Count == 4) {\r
+ And = *(UINT32*) AndData;\r
+ } else if (Count == 8) {\r
+ And = *(UINT64*) AndData;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Data &= And;\r
+ Status = EmmcPeimHcRwMmio (Address, FALSE, Count, &Data);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Wait for the value of the specified MMIO register set to the test value.\r
+\r
+ @param[in] Address The address of the mmio register to be checked.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2, 4 or 8 bytes.\r
+ @param[in] MaskValue The mask value of memory.\r
+ @param[in] TestValue The test value of memory.\r
+\r
+ @retval EFI_NOT_READY The MMIO register hasn't set to the expected value.\r
+ @retval EFI_SUCCESS The MMIO register has expected value.\r
+ @retval Others The MMIO operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcPeimHcCheckMmioSet (\r
+ IN UINTN Address,\r
+ IN UINT8 Count,\r
+ IN UINT64 MaskValue,\r
+ IN UINT64 TestValue\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 Value;\r
+\r
+ //\r
+ // Access PCI MMIO space to see if the value is the tested one.\r
+ //\r
+ Value = 0;\r
+ Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Value &= MaskValue;\r
+\r
+ if (Value == TestValue) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return EFI_NOT_READY;\r
+}\r
+\r
+/**\r
+ Wait for the value of the specified MMIO register set to the test value.\r
+\r
+ @param[in] Address The address of the mmio register to wait.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2, 4 or 8 bytes.\r
+ @param[in] MaskValue The mask value of memory.\r
+ @param[in] TestValue The test value of memory.\r
+ @param[in] Timeout The time out value for wait memory set, uses 1\r
+ microsecond as a unit.\r
+\r
+ @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout\r
+ range.\r
+ @retval EFI_SUCCESS The MMIO register has expected value.\r
+ @retval Others The MMIO operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcPeimHcWaitMmioSet (\r
+ IN UINTN Address,\r
+ IN UINT8 Count,\r
+ IN UINT64 MaskValue,\r
+ IN UINT64 TestValue,\r
+ IN UINT64 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN InfiniteWait;\r
+\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
+\r
+ while (InfiniteWait || (Timeout > 0)) {\r
+ Status = EmmcPeimHcCheckMmioSet (\r
+ Address,\r
+ Count,\r
+ MaskValue,\r
+ TestValue\r
+ );\r
+ if (Status != EFI_NOT_READY) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Stall for 1 microsecond.\r
+ //\r
+ MicroSecondDelay (1);\r
+\r
+ Timeout--;\r
+ }\r
+\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+ Software reset the specified EMMC host controller and enable all interrupts.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The software reset executes successfully.\r
+ @retval Others The software reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcReset (\r
+ IN UINTN Bar\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 SwReset;\r
+\r
+ SwReset = 0xFF;\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcPeimHcReset: write full 1 fails: %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ Status = EmmcPeimHcWaitMmioSet (\r
+ Bar + EMMC_HC_SW_RST,\r
+ sizeof (SwReset),\r
+ 0xFF,\r
+ 0x00,\r
+ EMMC_TIMEOUT\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "EmmcPeimHcReset: reset done with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Enable all interrupt after reset all.\r
+ //\r
+ Status = EmmcPeimHcEnableInterrupt (Bar);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set all interrupt status bits in Normal and Error Interrupt Status Enable\r
+ register.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The operation executes successfully.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcEnableInterrupt (\r
+ IN UINTN Bar\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 IntStatus;\r
+\r
+ //\r
+ // Enable all bits in Error Interrupt Status Enable Register\r
+ //\r
+ IntStatus = 0xFFFF;\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ERR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Enable all bits in Normal Interrupt Status Enable Register\r
+ //\r
+ IntStatus = 0xFFFF;\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get the capability data from the specified slot.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[out] Capability The buffer to store the capability data.\r
+\r
+ @retval EFI_SUCCESS The operation executes successfully.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcGetCapability (\r
+ IN UINTN Bar,\r
+ OUT EMMC_HC_SLOT_CAP *Capability\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 Cap;\r
+\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CAP, TRUE, sizeof (Cap), &Cap);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ CopyMem (Capability, &Cap, sizeof (Cap));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Detect whether there is a EMMC card attached at the specified EMMC host controller\r
+ slot.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS There is a EMMC card attached.\r
+ @retval EFI_NO_MEDIA There is not a EMMC card attached.\r
+ @retval Others The detection fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcCardDetect (\r
+ IN UINTN Bar\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 Data;\r
+ UINT32 PresentState;\r
+\r
+ //\r
+ // Check Normal Interrupt Status Register\r
+ //\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, TRUE, sizeof (Data), &Data);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((Data & (BIT6 | BIT7)) != 0) {\r
+ //\r
+ // Clear BIT6 and BIT7 by writing 1 to these two bits if set.\r
+ //\r
+ Data &= BIT6 | BIT7;\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, FALSE, sizeof (Data), &Data);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Check Present State Register to see if there is a card presented.\r
+ //\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((PresentState & BIT16) != 0) {\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ return EFI_NO_MEDIA;\r
+ }\r
+}\r
+\r
+/**\r
+ Stop EMMC card clock.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS Succeed to stop EMMC clock.\r
+ @retval Others Fail to stop EMMC clock.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcStopClock (\r
+ IN UINTN Bar\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 PresentState;\r
+ UINT16 ClockCtrl;\r
+\r
+ //\r
+ // Ensure no SD transactions are occurring on the SD Bus by\r
+ // waiting for Command Inhibit (DAT) and Command Inhibit (CMD)\r
+ // in the Present State register to be 0.\r
+ //\r
+ Status = EmmcPeimHcWaitMmioSet (\r
+ Bar + EMMC_HC_PRESENT_STATE,\r
+ sizeof (PresentState),\r
+ BIT0 | BIT1,\r
+ 0,\r
+ EMMC_TIMEOUT\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Set SD Clock Enable in the Clock Control register to 0\r
+ //\r
+ ClockCtrl = (UINT16)~BIT2;\r
+ Status = EmmcPeimHcAndMmio (Bar + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ EMMC card clock supply.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.\r
+\r
+ @retval EFI_SUCCESS The clock is supplied successfully.\r
+ @retval Others The clock isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcClockSupply (\r
+ IN UINTN Bar,\r
+ IN UINT64 ClockFreq\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_HC_SLOT_CAP Capability;\r
+ UINT32 BaseClkFreq;\r
+ UINT32 SettingFreq;\r
+ UINT32 Divisor;\r
+ UINT32 Remainder;\r
+ UINT16 ControllerVer;\r
+ UINT16 ClockCtrl;\r
+\r
+ //\r
+ // Calculate a divisor for SD clock frequency\r
+ //\r
+ Status = EmmcPeimHcGetCapability (Bar, &Capability);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ ASSERT (Capability.BaseClkFreq != 0);\r
+\r
+ BaseClkFreq = Capability.BaseClkFreq;\r
+ if ((ClockFreq > (BaseClkFreq * 1000)) || (ClockFreq == 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Calculate the divisor of base frequency.\r
+ //\r
+ Divisor = 0;\r
+ SettingFreq = BaseClkFreq * 1000;\r
+ while (ClockFreq < SettingFreq) {\r
+ Divisor++;\r
+\r
+ SettingFreq = (BaseClkFreq * 1000) / (2 * Divisor);\r
+ Remainder = (BaseClkFreq * 1000) % (2 * Divisor);\r
+ if ((ClockFreq == SettingFreq) && (Remainder == 0)) {\r
+ break;\r
+ }\r
+ if ((ClockFreq == SettingFreq) && (Remainder != 0)) {\r
+ SettingFreq ++;\r
+ }\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq));\r
+\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register.\r
+ //\r
+ if ((ControllerVer & 0xFF) == 2) {\r
+ ASSERT (Divisor <= 0x3FF);\r
+ ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2);\r
+ } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {\r
+ //\r
+ // Only the most significant bit can be used as divisor.\r
+ //\r
+ if (((Divisor - 1) & Divisor) != 0) {\r
+ Divisor = 1 << (HighBitSet32 (Divisor) + 1);\r
+ }\r
+ ASSERT (Divisor <= 0x80);\r
+ ClockCtrl = (Divisor & 0xFF) << 8;\r
+ } else {\r
+ DEBUG ((EFI_D_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Stop bus clock at first\r
+ //\r
+ Status = EmmcPeimHcStopClock (Bar);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Supply clock frequency with specified divisor\r
+ //\r
+ ClockCtrl |= BIT0;\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n"));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Wait Internal Clock Stable in the Clock Control register to be 1\r
+ //\r
+ Status = EmmcPeimHcWaitMmioSet (\r
+ Bar + EMMC_HC_CLOCK_CTRL,\r
+ sizeof (ClockCtrl),\r
+ BIT1,\r
+ BIT1,\r
+ EMMC_TIMEOUT\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Set SD Clock Enable in the Clock Control register to 1\r
+ //\r
+ ClockCtrl = BIT2;\r
+ Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ EMMC bus power control.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] PowerCtrl The value setting to the power control register.\r
+\r
+ @retval TRUE There is a EMMC card attached.\r
+ @retval FALSE There is no a EMMC card attached.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcPowerControl (\r
+ IN UINTN Bar,\r
+ IN UINT8 PowerCtrl\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Clr SD Bus Power\r
+ //\r
+ PowerCtrl &= (UINT8)~BIT0;\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register\r
+ //\r
+ PowerCtrl |= BIT0;\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set the EMMC bus width.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] BusWidth The bus width used by the EMMC device, it must be 1, 4 or 8.\r
+\r
+ @retval EFI_SUCCESS The bus width is set successfully.\r
+ @retval Others The bus width isn't set successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcSetBusWidth (\r
+ IN UINTN Bar,\r
+ IN UINT16 BusWidth\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 HostCtrl1;\r
+\r
+ if (BusWidth == 1) {\r
+ HostCtrl1 = (UINT8)~(BIT5 | BIT1);\r
+ Status = EmmcPeimHcAndMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ } else if (BusWidth == 4) {\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ HostCtrl1 |= BIT1;\r
+ HostCtrl1 &= (UINT8)~BIT5;\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);\r
+ } else if (BusWidth == 8) {\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ HostCtrl1 &= (UINT8)~BIT1;\r
+ HostCtrl1 |= BIT5;\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);\r
+ } else {\r
+ ASSERT (FALSE);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Supply EMMC card with lowest clock frequency at initialization.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The clock is supplied successfully.\r
+ @retval Others The clock isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcInitClockFreq (\r
+ IN UINTN Bar\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_HC_SLOT_CAP Capability;\r
+ UINT32 InitFreq;\r
+\r
+ //\r
+ // Calculate a divisor for SD clock frequency\r
+ //\r
+ Status = EmmcPeimHcGetCapability (Bar, &Capability);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Capability.BaseClkFreq == 0) {\r
+ //\r
+ // Don't support get Base Clock Frequency information via another method\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Supply 400KHz clock frequency at initialization phase.\r
+ //\r
+ InitFreq = 400;\r
+ Status = EmmcPeimHcClockSupply (Bar, InitFreq);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Supply EMMC card with maximum voltage at initialization.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The voltage is supplied successfully.\r
+ @retval Others The voltage isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcInitPowerVoltage (\r
+ IN UINTN Bar\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_HC_SLOT_CAP Capability;\r
+ UINT8 MaxVoltage;\r
+ UINT8 HostCtrl2;\r
+\r
+ //\r
+ // Get the support voltage of the Host Controller\r
+ //\r
+ Status = EmmcPeimHcGetCapability (Bar, &Capability);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Calculate supported maximum voltage according to SD Bus Voltage Select\r
+ //\r
+ if (Capability.Voltage33 != 0) {\r
+ //\r
+ // Support 3.3V\r
+ //\r
+ MaxVoltage = 0x0E;\r
+ } else if (Capability.Voltage30 != 0) {\r
+ //\r
+ // Support 3.0V\r
+ //\r
+ MaxVoltage = 0x0C;\r
+ } else if (Capability.Voltage18 != 0) {\r
+ //\r
+ // Support 1.8V\r
+ //\r
+ MaxVoltage = 0x0A;\r
+ HostCtrl2 = BIT3;\r
+ Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ MicroSecondDelay (5000);\r
+ } else {\r
+ ASSERT (FALSE);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register\r
+ //\r
+ Status = EmmcPeimHcPowerControl (Bar, MaxVoltage);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Initialize the Timeout Control register with most conservative value at initialization.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The timeout control register is configured successfully.\r
+ @retval Others The timeout control register isn't configured successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcInitTimeoutCtrl (\r
+ IN UINTN Bar\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Timeout;\r
+\r
+ Timeout = 0x0E;\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_TIMEOUT_CTRL, FALSE, sizeof (Timeout), &Timeout);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Initial EMMC host controller with lowest clock frequency, max power and max timeout value\r
+ at initialization.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The host controller is initialized successfully.\r
+ @retval Others The host controller isn't initialized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcInitHost (\r
+ IN UINTN Bar\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = EmmcPeimHcInitClockFreq (Bar);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = EmmcPeimHcInitPowerVoltage (Bar);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = EmmcPeimHcInitTimeoutCtrl (Bar);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Turn on/off LED.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] On The boolean to turn on/off LED.\r
+\r
+ @retval EFI_SUCCESS The LED is turned on/off successfully.\r
+ @retval Others The LED isn't turned on/off successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcLedOnOff (\r
+ IN UINTN Bar,\r
+ IN BOOLEAN On\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 HostCtrl1;\r
+\r
+ if (On) {\r
+ HostCtrl1 = BIT0;\r
+ Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ } else {\r
+ HostCtrl1 = (UINT8)~BIT0;\r
+ Status = EmmcPeimHcAndMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Build ADMA descriptor table for transfer.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details.\r
+\r
+ @param[in] Trb The pointer to the EMMC_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The ADMA descriptor table is created successfully.\r
+ @retval Others The ADMA descriptor table isn't created successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+BuildAdmaDescTable (\r
+ IN EMMC_TRB *Trb\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS Data;\r
+ UINT64 DataLen;\r
+ UINT64 Entries;\r
+ UINT32 Index;\r
+ UINT64 Remaining;\r
+ UINT32 Address;\r
+\r
+ Data = (EFI_PHYSICAL_ADDRESS)(UINTN)Trb->Data;\r
+ DataLen = Trb->DataLen;\r
+ //\r
+ // Only support 32bit ADMA Descriptor Table\r
+ //\r
+ if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)\r
+ // for 32-bit address descriptor table.\r
+ //\r
+ if ((Data & (BIT0 | BIT1)) != 0) {\r
+ DEBUG ((EFI_D_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));\r
+ }\r
+\r
+ Entries = DivU64x32 ((DataLen + ADMA_MAX_DATA_PER_LINE - 1), ADMA_MAX_DATA_PER_LINE);\r
+\r
+ Trb->AdmaDescSize = (UINTN)MultU64x32 (Entries, sizeof (EMMC_HC_ADMA_DESC_LINE));\r
+ Trb->AdmaDesc = EmmcPeimAllocateMem (Trb->Slot->Private->Pool, Trb->AdmaDescSize);\r
+ if (Trb->AdmaDesc == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Remaining = DataLen;\r
+ Address = (UINT32)Data;\r
+ for (Index = 0; Index < Entries; Index++) {\r
+ if (Remaining <= ADMA_MAX_DATA_PER_LINE) {\r
+ Trb->AdmaDesc[Index].Valid = 1;\r
+ Trb->AdmaDesc[Index].Act = 2;\r
+ Trb->AdmaDesc[Index].Length = (UINT16)Remaining;\r
+ Trb->AdmaDesc[Index].Address = Address;\r
+ break;\r
+ } else {\r
+ Trb->AdmaDesc[Index].Valid = 1;\r
+ Trb->AdmaDesc[Index].Act = 2;\r
+ Trb->AdmaDesc[Index].Length = 0;\r
+ Trb->AdmaDesc[Index].Address = Address;\r
+ }\r
+\r
+ Remaining -= ADMA_MAX_DATA_PER_LINE;\r
+ Address += ADMA_MAX_DATA_PER_LINE;\r
+ }\r
+\r
+ //\r
+ // Set the last descriptor line as end of descriptor table\r
+ //\r
+ Trb->AdmaDesc[Index].End = 1;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Create a new TRB for the EMMC cmd request.\r
+\r
+ @param[in] Slot The slot number of the EMMC card to send the command to.\r
+ @param[in] Packet A pointer to the SD command data structure.\r
+\r
+ @return Created Trb or NULL.\r
+\r
+**/\r
+EMMC_TRB *\r
+EmmcPeimCreateTrb (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN EMMC_COMMAND_PACKET *Packet\r
+ )\r
+{\r
+ EMMC_TRB *Trb;\r
+ EFI_STATUS Status;\r
+ EMMC_HC_SLOT_CAP Capability;\r
+\r
+ //\r
+ // Calculate a divisor for SD clock frequency\r
+ //\r
+ Status = EmmcPeimHcGetCapability (Slot->EmmcHcBase, &Capability);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ Trb = EmmcPeimAllocateMem (Slot->Private->Pool, sizeof (EMMC_TRB));\r
+ if (Trb == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Trb->Slot = Slot;\r
+ Trb->BlockSize = 0x200;\r
+ Trb->Packet = Packet;\r
+ Trb->Timeout = Packet->Timeout;\r
+\r
+ if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {\r
+ Trb->Data = Packet->InDataBuffer;\r
+ Trb->DataLen = Packet->InTransferLength;\r
+ Trb->Read = TRUE;\r
+ } else if ((Packet->OutTransferLength != 0) && (Packet->OutDataBuffer != NULL)) {\r
+ Trb->Data = Packet->OutDataBuffer;\r
+ Trb->DataLen = Packet->OutTransferLength;\r
+ Trb->Read = FALSE;\r
+ } else if ((Packet->InTransferLength == 0) && (Packet->OutTransferLength == 0)) {\r
+ Trb->Data = NULL;\r
+ Trb->DataLen = 0;\r
+ } else {\r
+ goto Error;\r
+ }\r
+\r
+ if ((Trb->DataLen % Trb->BlockSize) != 0) {\r
+ if (Trb->DataLen < Trb->BlockSize) {\r
+ Trb->BlockSize = (UINT16)Trb->DataLen;\r
+ }\r
+ }\r
+\r
+ if (Trb->DataLen == 0) {\r
+ Trb->Mode = EmmcNoData;\r
+ } else if (Capability.Adma2 != 0) {\r
+ Trb->Mode = EmmcAdmaMode;\r
+ Status = BuildAdmaDescTable (Trb);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ } else if (Capability.Sdma != 0) {\r
+ Trb->Mode = EmmcSdmaMode;\r
+ } else {\r
+ Trb->Mode = EmmcPioMode;\r
+ }\r
+\r
+ return Trb;\r
+\r
+Error:\r
+ EmmcPeimFreeTrb (Trb);\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Free the resource used by the TRB.\r
+\r
+ @param[in] Trb The pointer to the EMMC_TRB instance.\r
+\r
+**/\r
+VOID\r
+EmmcPeimFreeTrb (\r
+ IN EMMC_TRB *Trb\r
+ )\r
+{\r
+ if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) {\r
+ EmmcPeimFreeMem (Trb->Slot->Private->Pool, Trb->AdmaDesc, Trb->AdmaDescSize);\r
+ }\r
+\r
+ if (Trb != NULL) {\r
+ EmmcPeimFreeMem (Trb->Slot->Private->Pool, Trb, sizeof (EMMC_TRB));\r
+ }\r
+ return;\r
+}\r
+\r
+/**\r
+ Check if the env is ready for execute specified TRB.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] Trb The pointer to the EMMC_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The env is ready for TRB execution.\r
+ @retval EFI_NOT_READY The env is not ready for TRB execution.\r
+ @retval Others Some erros happen.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimCheckTrbEnv (\r
+ IN UINTN Bar,\r
+ IN EMMC_TRB *Trb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_COMMAND_PACKET *Packet;\r
+ UINT32 PresentState;\r
+\r
+ Packet = Trb->Packet;\r
+\r
+ if ((Packet->EmmcCmdBlk->CommandType == EmmcCommandTypeAdtc) ||\r
+ (Packet->EmmcCmdBlk->ResponseType == EmmcResponceTypeR1b) ||\r
+ (Packet->EmmcCmdBlk->ResponseType == EmmcResponceTypeR5b)) {\r
+ //\r
+ // Wait Command Inhibit (CMD) and Command Inhibit (DAT) in\r
+ // the Present State register to be 0\r
+ //\r
+ PresentState = BIT0 | BIT1;\r
+ if (Packet->EmmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK) {\r
+ PresentState = BIT0;\r
+ }\r
+ } else {\r
+ //\r
+ // Wait Command Inhibit (CMD) in the Present State register\r
+ // to be 0\r
+ //\r
+ PresentState = BIT0;\r
+ }\r
+\r
+ Status = EmmcPeimHcCheckMmioSet (\r
+ Bar + EMMC_HC_PRESENT_STATE,\r
+ sizeof (PresentState),\r
+ PresentState,\r
+ 0\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Wait for the env to be ready for execute specified TRB.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] Trb The pointer to the EMMC_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The env is ready for TRB execution.\r
+ @retval EFI_TIMEOUT The env is not ready for TRB execution in time.\r
+ @retval Others Some erros happen.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimWaitTrbEnv (\r
+ IN UINTN Bar,\r
+ IN EMMC_TRB *Trb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_COMMAND_PACKET *Packet;\r
+ UINT64 Timeout;\r
+ BOOLEAN InfiniteWait;\r
+\r
+ //\r
+ // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register\r
+ //\r
+ Packet = Trb->Packet;\r
+ Timeout = Packet->Timeout;\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
+\r
+ while (InfiniteWait || (Timeout > 0)) {\r
+ //\r
+ // Check Trb execution result by reading Normal Interrupt Status register.\r
+ //\r
+ Status = EmmcPeimCheckTrbEnv (Bar, Trb);\r
+ if (Status != EFI_NOT_READY) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Stall for 1 microsecond.\r
+ //\r
+ MicroSecondDelay (1);\r
+\r
+ Timeout--;\r
+ }\r
+\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+ Execute the specified TRB.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] Trb The pointer to the EMMC_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The TRB is sent to host controller successfully.\r
+ @retval Others Some erros happen when sending this request to the host controller.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimExecTrb (\r
+ IN UINTN Bar,\r
+ IN EMMC_TRB *Trb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_COMMAND_PACKET *Packet;\r
+ UINT16 Cmd;\r
+ UINT16 IntStatus;\r
+ UINT32 Argument;\r
+ UINT16 BlkCount;\r
+ UINT16 BlkSize;\r
+ UINT16 TransMode;\r
+ UINT8 HostCtrl1;\r
+ UINT32 SdmaAddr;\r
+ UINT64 AdmaAddr;\r
+\r
+ Packet = Trb->Packet;\r
+ //\r
+ // Clear all bits in Error Interrupt Status Register\r
+ //\r
+ IntStatus = 0xFFFF;\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ERR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Clear all bits in Normal Interrupt Status Register\r
+ //\r
+ IntStatus = 0xFFFF;\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set Host Control 1 register DMA Select field\r
+ //\r
+ if (Trb->Mode == EmmcAdmaMode) {\r
+ HostCtrl1 = BIT4;\r
+ Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ EmmcPeimHcLedOnOff (Bar, TRUE);\r
+\r
+ if (Trb->Mode == EmmcSdmaMode) {\r
+ if ((UINT64)(UINTN)Trb->Data >= 0x100000000ul) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ SdmaAddr = (UINT32)(UINTN)Trb->Data;\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ } else if (Trb->Mode == EmmcAdmaMode) {\r
+ AdmaAddr = (UINT64)(UINTN)Trb->AdmaDesc;\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ BlkSize = Trb->BlockSize;\r
+ if (Trb->Mode == EmmcSdmaMode) {\r
+ //\r
+ // Set SDMA boundary to be 512K bytes.\r
+ //\r
+ BlkSize |= 0x7000;\r
+ }\r
+\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_BLK_SIZE, FALSE, sizeof (BlkSize), &BlkSize);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Argument = Packet->EmmcCmdBlk->CommandArgument;\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ARG1, FALSE, sizeof (Argument), &Argument);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ TransMode = 0;\r
+ if (Trb->Mode != EmmcNoData) {\r
+ if (Trb->Mode != EmmcPioMode) {\r
+ TransMode |= BIT0;\r
+ }\r
+ if (Trb->Read) {\r
+ TransMode |= BIT4;\r
+ }\r
+ if (BlkCount != 0) {\r
+ TransMode |= BIT5 | BIT1;\r
+ }\r
+ }\r
+\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_TRANS_MOD, FALSE, sizeof (TransMode), &TransMode);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Cmd = (UINT16)LShiftU64(Packet->EmmcCmdBlk->CommandIndex, 8);\r
+ if (Packet->EmmcCmdBlk->CommandType == EmmcCommandTypeAdtc) {\r
+ Cmd |= BIT5;\r
+ }\r
+ //\r
+ // Convert ResponseType to value\r
+ //\r
+ if (Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeBc) {\r
+ switch (Packet->EmmcCmdBlk->ResponseType) {\r
+ case EmmcResponceTypeR1:\r
+ case EmmcResponceTypeR5:\r
+ case EmmcResponceTypeR6:\r
+ case EmmcResponceTypeR7:\r
+ Cmd |= (BIT1 | BIT3 | BIT4);\r
+ break;\r
+ case EmmcResponceTypeR2:\r
+ Cmd |= (BIT0 | BIT3);\r
+ break;\r
+ case EmmcResponceTypeR3:\r
+ case EmmcResponceTypeR4:\r
+ Cmd |= BIT1;\r
+ break;\r
+ case EmmcResponceTypeR1b:\r
+ case EmmcResponceTypeR5b:\r
+ Cmd |= (BIT0 | BIT1 | BIT3 | BIT4);\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // Execute cmd\r
+ //\r
+ Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Check the TRB execution result.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] Trb The pointer to the EMMC_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The TRB is executed successfully.\r
+ @retval EFI_NOT_READY The TRB is not completed for execution.\r
+ @retval Others Some erros happen when executing this request.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimCheckTrbResult (\r
+ IN UINTN Bar,\r
+ IN EMMC_TRB *Trb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_COMMAND_PACKET *Packet;\r
+ UINT16 IntStatus;\r
+ UINT32 Response[4];\r
+ UINT32 SdmaAddr;\r
+ UINT8 Index;\r
+ UINT8 SwReset;\r
+\r
+ SwReset = 0;\r
+ Packet = Trb->Packet;\r
+ //\r
+ // Check Trb execution result by reading Normal Interrupt Status register.\r
+ //\r
+ Status = EmmcPeimHcRwMmio (\r
+ Bar + EMMC_HC_NOR_INT_STS,\r
+ TRUE,\r
+ sizeof (IntStatus),\r
+ &IntStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Check Transfer Complete bit is set or not.\r
+ //\r
+ if ((IntStatus & BIT1) == BIT1) {\r
+ if ((IntStatus & BIT15) == BIT15) {\r
+ //\r
+ // Read Error Interrupt Status register to check if the error is\r
+ // Data Timeout Error.\r
+ // If yes, treat it as success as Transfer Complete has higher\r
+ // priority than Data Timeout Error.\r
+ //\r
+ Status = EmmcPeimHcRwMmio (\r
+ Bar + EMMC_HC_ERR_INT_STS,\r
+ TRUE,\r
+ sizeof (IntStatus),\r
+ &IntStatus\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ if ((IntStatus & BIT4) == BIT4) {\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+ }\r
+\r
+ goto Done;\r
+ }\r
+ //\r
+ // Check if there is a error happened during cmd execution.\r
+ // If yes, then do error recovery procedure to follow SD Host Controller\r
+ // Simplified Spec 3.0 section 3.10.1.\r
+ //\r
+ if ((IntStatus & BIT15) == BIT15) {\r
+ Status = EmmcPeimHcRwMmio (\r
+ Bar + EMMC_HC_ERR_INT_STS,\r
+ TRUE,\r
+ sizeof (IntStatus),\r
+ &IntStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ if ((IntStatus & 0x0F) != 0) {\r
+ SwReset |= BIT1;\r
+ }\r
+ if ((IntStatus & 0xF0) != 0) {\r
+ SwReset |= BIT2;\r
+ }\r
+\r
+ Status = EmmcPeimHcRwMmio (\r
+ Bar + EMMC_HC_SW_RST,\r
+ FALSE,\r
+ sizeof (SwReset),\r
+ &SwReset\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ Status = EmmcPeimHcWaitMmioSet (\r
+ Bar + EMMC_HC_SW_RST,\r
+ sizeof (SwReset),\r
+ 0xFF,\r
+ 0,\r
+ EMMC_TIMEOUT\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+ //\r
+ // Check if DMA interrupt is signalled for the SDMA transfer.\r
+ //\r
+ if ((Trb->Mode == EmmcSdmaMode) && ((IntStatus & BIT3) == BIT3)) {\r
+ //\r
+ // Clear DMA interrupt bit.\r
+ //\r
+ IntStatus = BIT3;\r
+ Status = EmmcPeimHcRwMmio (\r
+ Bar + EMMC_HC_NOR_INT_STS,\r
+ FALSE,\r
+ sizeof (IntStatus),\r
+ &IntStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Update SDMA Address register.\r
+ //\r
+ SdmaAddr = EMMC_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->Data, EMMC_SDMA_BOUNDARY);\r
+ Status = EmmcPeimHcRwMmio (\r
+ Bar + EMMC_HC_SDMA_ADDR,\r
+ FALSE,\r
+ sizeof (UINT32),\r
+ &SdmaAddr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ Trb->Data = (VOID*)(UINTN)SdmaAddr;\r
+ }\r
+\r
+ if ((Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeAdtc) &&\r
+ (Packet->EmmcCmdBlk->ResponseType != EmmcResponceTypeR1b) &&\r
+ (Packet->EmmcCmdBlk->ResponseType != EmmcResponceTypeR5b)) {\r
+ if ((IntStatus & BIT0) == BIT0) {\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ if (Packet->EmmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK) {\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+ Status = EFI_NOT_READY;\r
+Done:\r
+ //\r
+ // Get response data when the cmd is executed successfully.\r
+ //\r
+ if (!EFI_ERROR (Status)) {\r
+ if (Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeBc) {\r
+ for (Index = 0; Index < 4; Index++) {\r
+ Status = EmmcPeimHcRwMmio (\r
+ Bar + EMMC_HC_RESPONSE + Index * 4,\r
+ TRUE,\r
+ sizeof (UINT32),\r
+ &Response[Index]\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ EmmcPeimHcLedOnOff (Bar, FALSE);\r
+ return Status;\r
+ }\r
+ }\r
+ CopyMem (Packet->EmmcStatusBlk, Response, sizeof (Response));\r
+ }\r
+ }\r
+\r
+ if (Status != EFI_NOT_READY) {\r
+ EmmcPeimHcLedOnOff (Bar, FALSE);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Wait for the TRB execution result.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] Trb The pointer to the EMMC_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The TRB is executed successfully.\r
+ @retval Others Some erros happen when executing this request.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimWaitTrbResult (\r
+ IN UINTN Bar,\r
+ IN EMMC_TRB *Trb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_COMMAND_PACKET *Packet;\r
+ UINT64 Timeout;\r
+ BOOLEAN InfiniteWait;\r
+\r
+ Packet = Trb->Packet;\r
+ //\r
+ // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register\r
+ //\r
+ Timeout = Packet->Timeout;\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
+\r
+ while (InfiniteWait || (Timeout > 0)) {\r
+ //\r
+ // Check Trb execution result by reading Normal Interrupt Status register.\r
+ //\r
+ Status = EmmcPeimCheckTrbResult (Bar, Trb);\r
+ if (Status != EFI_NOT_READY) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Stall for 1 microsecond.\r
+ //\r
+ MicroSecondDelay (1);\r
+\r
+ Timeout--;\r
+ }\r
+\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+ Sends EMMC command to an EMMC card that is attached to the EMMC controller.\r
+\r
+ If Packet is successfully sent to the EMMC card, then EFI_SUCCESS is returned.\r
+\r
+ If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.\r
+\r
+ If Slot is not in a valid range for the EMMC controller, then EFI_INVALID_PARAMETER\r
+ is returned.\r
+\r
+ If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,\r
+ EFI_INVALID_PARAMETER is returned.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in,out] Packet A pointer to the EMMC command data structure.\r
+\r
+ @retval EFI_SUCCESS The EMMC Command Packet was sent by the host.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD\r
+ command Packet.\r
+ @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.\r
+ @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and\r
+ OutDataBuffer are NULL.\r
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.\r
+ @retval EFI_UNSUPPORTED The command described by the EMMC Command Packet is not\r
+ supported by the host controller.\r
+ @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the\r
+ limit supported by EMMC card ( i.e. if the number of bytes\r
+ exceed the Last LBA).\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcPeimExecCmd (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN OUT EMMC_COMMAND_PACKET *Packet\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_TRB *Trb;\r
+\r
+ if (Packet == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Packet->EmmcCmdBlk == NULL) || (Packet->EmmcStatusBlk == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Trb = EmmcPeimCreateTrb (Slot, Packet);\r
+ if (Trb == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = EmmcPeimWaitTrbEnv (Slot->EmmcHcBase, Trb);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = EmmcPeimExecTrb (Slot->EmmcHcBase, Trb);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = EmmcPeimWaitTrbResult (Slot->EmmcHcBase, Trb);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+Done:\r
+ EmmcPeimFreeTrb (Trb);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command GO_IDLE_STATE (CMD0 with argument of 0x00000000) to the device to\r
+ make it go to Idle State.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The EMMC device is reset correctly.\r
+ @retval Others The device reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimReset (\r
+ IN EMMC_PEIM_HC_SLOT *Slot\r
+ )\r
+{\r
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
+ EMMC_STATUS_BLOCK EmmcStatusBlk;\r
+ EMMC_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+ Packet.Timeout = EMMC_TIMEOUT;\r
+\r
+ EmmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE;\r
+ EmmcCmdBlk.CommandType = EmmcCommandTypeBc;\r
+ EmmcCmdBlk.ResponseType = 0;\r
+ EmmcCmdBlk.CommandArgument = 0;\r
+\r
+ Status = EmmcPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_OP_COND to the EMMC device to get the data of the OCR register.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in, out] Argument On input, the argument of SEND_OP_COND is to send to the device.\r
+ On output, the argument is the value of OCR register.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimGetOcr (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN OUT UINT32 *Argument\r
+ )\r
+{\r
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
+ EMMC_STATUS_BLOCK EmmcStatusBlk;\r
+ EMMC_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+ Packet.Timeout = EMMC_TIMEOUT;\r
+\r
+ EmmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND;\r
+ EmmcCmdBlk.CommandType = EmmcCommandTypeBcr;\r
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR3;\r
+ EmmcCmdBlk.CommandArgument = *Argument;\r
+\r
+ Status = EmmcPeimExecCmd (Slot, &Packet);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+ //\r
+ *Argument = EmmcStatusBlk.Resp0;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Broadcast command ALL_SEND_CID to the bus to ask all the EMMC devices to send the\r
+ data of their CID registers.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimGetAllCid (\r
+ IN EMMC_PEIM_HC_SLOT *Slot\r
+ )\r
+{\r
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
+ EMMC_STATUS_BLOCK EmmcStatusBlk;\r
+ EMMC_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+ Packet.Timeout = EMMC_TIMEOUT;\r
+\r
+ EmmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID;\r
+ EmmcCmdBlk.CommandType = EmmcCommandTypeBcr;\r
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR2;\r
+ EmmcCmdBlk.CommandArgument = 0;\r
+\r
+ Status = EmmcPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SET_RELATIVE_ADDR to the EMMC device to assign a Relative device\r
+ Address (RCA).\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSetRca (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN UINT32 Rca\r
+ )\r
+{\r
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
+ EMMC_STATUS_BLOCK EmmcStatusBlk;\r
+ EMMC_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+ Packet.Timeout = EMMC_TIMEOUT;\r
+\r
+ EmmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR;\r
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAc;\r
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
+ EmmcCmdBlk.CommandArgument = Rca << 16;\r
+\r
+ Status = EmmcPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_CSD to the EMMC device to get the data of the CSD register.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] Rca The relative device address of selected device.\r
+ @param[out] Csd The buffer to store the content of the CSD register.\r
+ Note the caller should ignore the lowest byte of this\r
+ buffer as the content of this byte is meaningless even\r
+ if the operation succeeds.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimGetCsd (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN UINT32 Rca,\r
+ OUT EMMC_CSD *Csd\r
+ )\r
+{\r
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
+ EMMC_STATUS_BLOCK EmmcStatusBlk;\r
+ EMMC_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+ Packet.Timeout = EMMC_TIMEOUT;\r
+\r
+ EmmcCmdBlk.CommandIndex = EMMC_SEND_CSD;\r
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAc;\r
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR2;\r
+ EmmcCmdBlk.CommandArgument = Rca << 16;\r
+\r
+ Status = EmmcPeimExecCmd (Slot, &Packet);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+ //\r
+ CopyMem (((UINT8*)Csd) + 1, &EmmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SELECT_DESELECT_CARD to the EMMC device to select/deselect it.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] Rca The relative device address of selected device.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSelect (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN UINT32 Rca\r
+ )\r
+{\r
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
+ EMMC_STATUS_BLOCK EmmcStatusBlk;\r
+ EMMC_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+ Packet.Timeout = EMMC_TIMEOUT;\r
+\r
+ EmmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;\r
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAc;\r
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
+ EmmcCmdBlk.CommandArgument = Rca << 16;\r
+\r
+ Status = EmmcPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_EXT_CSD to the EMMC device to get the data of the EXT_CSD register.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[out] ExtCsd The buffer to store the content of the EXT_CSD register.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimGetExtCsd (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ OUT EMMC_EXT_CSD *ExtCsd\r
+ )\r
+{\r
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
+ EMMC_STATUS_BLOCK EmmcStatusBlk;\r
+ EMMC_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+ Packet.Timeout = EMMC_TIMEOUT;\r
+\r
+ EmmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;\r
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc;\r
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
+ EmmcCmdBlk.CommandArgument = 0x00000000;\r
+\r
+ Packet.InDataBuffer = ExtCsd;\r
+ Packet.InTransferLength = sizeof (EMMC_EXT_CSD);\r
+\r
+ Status = EmmcPeimExecCmd (Slot, &Packet);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SWITCH to the EMMC device to switch the mode of operation of the\r
+ selected Device or modifies the EXT_CSD registers.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] Access The access mode of SWTICH command.\r
+ @param[in] Index The offset of the field to be access.\r
+ @param[in] Value The value to be set to the specified field of EXT_CSD register.\r
+ @param[in] CmdSet The value of CmdSet field of EXT_CSD register.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSwitch (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN UINT8 Access,\r
+ IN UINT8 Index,\r
+ IN UINT8 Value,\r
+ IN UINT8 CmdSet\r
+ )\r
+{\r
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
+ EMMC_STATUS_BLOCK EmmcStatusBlk;\r
+ EMMC_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+ Packet.Timeout = EMMC_TIMEOUT;\r
+\r
+ EmmcCmdBlk.CommandIndex = EMMC_SWITCH;\r
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAc;\r
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1b;\r
+ EmmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | (Value << 8) | CmdSet;\r
+\r
+ Status = EmmcPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_STATUS to the addressed EMMC device to get its status register.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] Rca The relative device address of addressed device.\r
+ @param[out] DevStatus The returned device status.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSendStatus (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN UINT32 Rca,\r
+ OUT UINT32 *DevStatus\r
+ )\r
+{\r
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
+ EMMC_STATUS_BLOCK EmmcStatusBlk;\r
+ EMMC_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+ Packet.Timeout = EMMC_TIMEOUT;\r
+\r
+ EmmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;\r
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAc;\r
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
+ EmmcCmdBlk.CommandArgument = Rca << 16;\r
+\r
+ Status = EmmcPeimExecCmd (Slot, &Packet);\r
+ if (!EFI_ERROR (Status)) {\r
+ *DevStatus = EmmcStatusBlk.Resp0;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SET_BLOCK_COUNT to the addressed EMMC device to set the number of\r
+ blocks for the following block read/write cmd.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] BlockCount The number of the logical block to access.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSetBlkCount (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN UINT16 BlockCount\r
+ )\r
+{\r
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
+ EMMC_STATUS_BLOCK EmmcStatusBlk;\r
+ EMMC_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+ Packet.Timeout = EMMC_TIMEOUT;\r
+\r
+ EmmcCmdBlk.CommandIndex = EMMC_SET_BLOCK_COUNT;\r
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAc;\r
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
+ EmmcCmdBlk.CommandArgument = BlockCount;\r
+\r
+ Status = EmmcPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed EMMC device\r
+ to read/write the specified number of blocks.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] Lba The logical block address of starting access.\r
+ @param[in] BlockSize The block size of specified EMMC device partition.\r
+ @param[in] Buffer The pointer to the transfer buffer.\r
+ @param[in] BufferSize The size of transfer buffer.\r
+ @param[in] IsRead Boolean to show the operation direction.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimRwMultiBlocks (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN EFI_LBA Lba,\r
+ IN UINT32 BlockSize,\r
+ IN VOID *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN BOOLEAN IsRead\r
+ )\r
+{\r
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
+ EMMC_STATUS_BLOCK EmmcStatusBlk;\r
+ EMMC_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+ //\r
+ // Calculate timeout value through the below formula.\r
+ // Timeout = (transfer size) / (2MB/s).\r
+ // Taking 2MB/s as divisor is because it's nearest to the eMMC lowest\r
+ // transfer speed (2.4MB/s).\r
+ // Refer to eMMC 5.0 spec section 6.9.1 for details.\r
+ //\r
+ Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;;\r
+\r
+ if (IsRead) {\r
+ Packet.InDataBuffer = Buffer;\r
+ Packet.InTransferLength = (UINT32)BufferSize;\r
+\r
+ EmmcCmdBlk.CommandIndex = EMMC_READ_MULTIPLE_BLOCK;\r
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc;\r
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
+ } else {\r
+ Packet.OutDataBuffer = Buffer;\r
+ Packet.OutTransferLength = (UINT32)BufferSize;\r
+\r
+ EmmcCmdBlk.CommandIndex = EMMC_WRITE_MULTIPLE_BLOCK;\r
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc;\r
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
+ }\r
+\r
+ if (Slot->SectorAddressing) {\r
+ EmmcCmdBlk.CommandArgument = (UINT32)Lba;\r
+ } else {\r
+ EmmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, BlockSize);\r
+ }\r
+\r
+ Status = EmmcPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_TUNING_BLOCK to the EMMC device for HS200 optimal sampling point\r
+ detection.\r
+\r
+ It may be sent up to 40 times until the host finishes the tuning procedure.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] BusWidth The bus width to work.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSendTuningBlk (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN UINT8 BusWidth\r
+ )\r
+{\r
+ EMMC_COMMAND_BLOCK EmmcCmdBlk;\r
+ EMMC_STATUS_BLOCK EmmcStatusBlk;\r
+ EMMC_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+ UINT8 TuningBlock[128];\r
+\r
+ ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+ ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.EmmcCmdBlk = &EmmcCmdBlk;\r
+ Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+ Packet.Timeout = EMMC_TIMEOUT;\r
+\r
+ EmmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK;\r
+ EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc;\r
+ EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
+ EmmcCmdBlk.CommandArgument = 0;\r
+\r
+ Packet.InDataBuffer = TuningBlock;\r
+ if (BusWidth == 8) {\r
+ Packet.InTransferLength = sizeof (TuningBlock);\r
+ } else {\r
+ Packet.InTransferLength = 64;\r
+ }\r
+\r
+ Status = EmmcPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Tunning the clock to get HS200 optimal sampling point.\r
+\r
+ Command SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the\r
+ tuning procedure.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+ Simplified Spec 3.0 section Figure 2-29 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] BusWidth The bus width to work.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimTuningClkForHs200 (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN UINT8 BusWidth\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 HostCtrl2;\r
+ UINT8 Retry;\r
+\r
+ //\r
+ // Notify the host that the sampling clock tuning procedure starts.\r
+ //\r
+ HostCtrl2 = BIT6;\r
+ Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.\r
+ //\r
+ Retry = 0;\r
+ do {\r
+ Status = EmmcPeimSendTuningBlk (Slot, BusWidth);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = EmmcPeimHcRwMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
+ break;\r
+ }\r
+ } while (++Retry < 40);\r
+\r
+ if (Retry == 40) {\r
+ Status = EFI_TIMEOUT;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Switch the bus width to specified width.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9 and SD Host Controller\r
+ Simplified Spec 3.0 section Figure 3-7 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+ @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise\r
+ use single data rate data simpling method.\r
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSwitchBusWidth (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN UINT32 Rca,\r
+ IN BOOLEAN IsDdr,\r
+ IN UINT8 BusWidth\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Access;\r
+ UINT8 Index;\r
+ UINT8 Value;\r
+ UINT8 CmdSet;\r
+ UINT32 DevStatus;\r
+\r
+ //\r
+ // Write Byte, the Value field is written into the byte pointed by Index.\r
+ //\r
+ Access = 0x03;\r
+ Index = OFFSET_OF (EMMC_EXT_CSD, BusWidth);\r
+ if (BusWidth == 4) {\r
+ Value = 1;\r
+ } else if (BusWidth == 8) {\r
+ Value = 2;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (IsDdr) {\r
+ Value += 4;\r
+ }\r
+\r
+ CmdSet = 0;\r
+ Status = EmmcPeimSwitch (Slot, Access, Index, Value, CmdSet);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = EmmcPeimSendStatus (Slot, Rca, &DevStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Check the switch operation is really successful or not.\r
+ //\r
+ if ((DevStatus & BIT7) != 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Status = EmmcPeimHcSetBusWidth (Slot->EmmcHcBase, BusWidth);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Switch the clock frequency to the specified value.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6 and SD Host Controller\r
+ Simplified Spec 3.0 section Figure 3-3 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+ @param[in] HsTiming The value to be written to HS_TIMING field of EXT_CSD register.\r
+ @param[in] ClockFreq The max clock frequency to be set, the unit is MHz.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSwitchClockFreq (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN UINT32 Rca,\r
+ IN UINT8 HsTiming,\r
+ IN UINT32 ClockFreq\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Access;\r
+ UINT8 Index;\r
+ UINT8 Value;\r
+ UINT8 CmdSet;\r
+ UINT32 DevStatus;\r
+\r
+ //\r
+ // Write Byte, the Value field is written into the byte pointed by Index.\r
+ //\r
+ Access = 0x03;\r
+ Index = OFFSET_OF (EMMC_EXT_CSD, HsTiming);\r
+ Value = HsTiming;\r
+ CmdSet = 0;\r
+\r
+ Status = EmmcPeimSwitch (Slot, Access, Index, Value, CmdSet);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = EmmcPeimSendStatus (Slot, Rca, &DevStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Check the switch operation is really successful or not.\r
+ //\r
+ if ((DevStatus & BIT7) != 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Convert the clock freq unit from MHz to KHz.\r
+ //\r
+ Status = EmmcPeimHcClockSupply (Slot->EmmcHcBase, ClockFreq * 1000);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Switch to the High Speed timing according to request.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+ Simplified Spec 3.0 section Figure 2-29 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+ @param[in] ClockFreq The max clock frequency to be set.\r
+ @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise\r
+ use single data rate data simpling method.\r
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSwitchToHighSpeed (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN UINT32 Rca,\r
+ IN UINT32 ClockFreq,\r
+ IN BOOLEAN IsDdr,\r
+ IN UINT8 BusWidth\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 HsTiming;\r
+ UINT8 HostCtrl1;\r
+ UINT8 HostCtrl2;\r
+\r
+ Status = EmmcPeimSwitchBusWidth (Slot, Rca, IsDdr, BusWidth);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set to Hight Speed timing\r
+ //\r
+ HostCtrl1 = BIT2;\r
+ Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ HostCtrl2 = (UINT8)~0x7;\r
+ Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (IsDdr) {\r
+ HostCtrl2 = BIT2;\r
+ } else if (ClockFreq == 52) {\r
+ HostCtrl2 = BIT0;\r
+ } else {\r
+ HostCtrl2 = 0;\r
+ }\r
+ Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ HsTiming = 1;\r
+ Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Switch to the HS200 timing according to request.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+ Simplified Spec 3.0 section Figure 2-29 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+ @param[in] ClockFreq The max clock frequency to be set.\r
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSwitchToHS200 (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN UINT32 Rca,\r
+ IN UINT32 ClockFreq,\r
+ IN UINT8 BusWidth\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 HsTiming;\r
+ UINT8 HostCtrl2;\r
+ UINT16 ClockCtrl;\r
+\r
+ if ((BusWidth != 4) && (BusWidth != 8)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = EmmcPeimSwitchBusWidth (Slot, Rca, FALSE, BusWidth);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set to HS200/SDR104 timing\r
+ //\r
+ //\r
+ // Stop bus clock at first\r
+ //\r
+ Status = EmmcPeimHcStopClock (Slot->EmmcHcBase);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ HostCtrl2 = (UINT8)~0x7;\r
+ Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ HostCtrl2 = BIT0 | BIT1;\r
+ Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Wait Internal Clock Stable in the Clock Control register to be 1 before set SD Clock Enable bit\r
+ //\r
+ Status = EmmcPeimHcWaitMmioSet (\r
+ Slot->EmmcHcBase + EMMC_HC_CLOCK_CTRL,\r
+ sizeof (ClockCtrl),\r
+ BIT1,\r
+ BIT1,\r
+ EMMC_TIMEOUT\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set SD Clock Enable in the Clock Control register to 1\r
+ //\r
+ ClockCtrl = BIT2;\r
+ Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+\r
+ HsTiming = 2;\r
+ Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = EmmcPeimTuningClkForHs200 (Slot, BusWidth);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Switch to the HS400 timing according to request.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+ Simplified Spec 3.0 section Figure 2-29 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+ @param[in] ClockFreq The max clock frequency to be set.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSwitchToHS400 (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN UINT32 Rca,\r
+ IN UINT32 ClockFreq\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 HsTiming;\r
+ UINT8 HostCtrl2;\r
+\r
+ Status = EmmcPeimSwitchToHS200 (Slot, Rca, ClockFreq, 8);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set to Hight Speed timing and set the clock frequency to a value less than 52MHz.\r
+ //\r
+ HsTiming = 1;\r
+ Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, 52);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // HS400 mode must use 8 data lines.\r
+ //\r
+ Status = EmmcPeimSwitchBusWidth (Slot, Rca, TRUE, 8);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set to HS400 timing\r
+ //\r
+ HostCtrl2 = (UINT8)~0x7;\r
+ Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ HostCtrl2 = BIT0 | BIT2;\r
+ Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ HsTiming = 3;\r
+ Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Switch the high speed timing according to request.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+ Simplified Spec 3.0 section Figure 2-29 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSetBusMode (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN UINT32 Rca\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_HC_SLOT_CAP Capability;\r
+ UINT8 HsTiming;\r
+ BOOLEAN IsDdr;\r
+ UINT32 ClockFreq;\r
+ UINT8 BusWidth;\r
+\r
+ Status = EmmcPeimGetCsd (Slot, Rca, &Slot->Csd);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcPeimSetBusMode: EmmcPeimGetCsd fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ if ((Slot->Csd.CSizeLow | Slot->Csd.CSizeHigh << 2) == 0xFFF) {\r
+ Slot->SectorAddressing = TRUE;\r
+ } else {\r
+ Slot->SectorAddressing = FALSE;\r
+ }\r
+\r
+ Status = EmmcPeimSelect (Slot, Rca);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcPeimSetBusMode: EmmcPeimSelect fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ Status = EmmcPeimHcGetCapability (Slot->EmmcHcBase, &Capability);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcPeimSetBusMode: EmmcPeimHcGetCapability fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ ASSERT (Capability.BaseClkFreq != 0);\r
+ //\r
+ // Check if the Host Controller support 8bits bus width.\r
+ //\r
+ if (Capability.BusWidth8 != 0) {\r
+ BusWidth = 8;\r
+ } else {\r
+ BusWidth = 4;\r
+ }\r
+ //\r
+ // Get Deivce_Type from EXT_CSD register.\r
+ //\r
+ Status = EmmcPeimGetExtCsd (Slot, &Slot->ExtCsd);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcPeimSetBusMode: EmmcPeimGetExtCsd fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Calculate supported bus speed/bus width/clock frequency.\r
+ //\r
+ HsTiming = 0;\r
+ IsDdr = FALSE;\r
+ ClockFreq = 0;\r
+ if (((Slot->ExtCsd.DeviceType & (BIT4 | BIT5)) != 0) && (Capability.Sdr104 != 0)) {\r
+ HsTiming = 2;\r
+ IsDdr = FALSE;\r
+ ClockFreq = 200;\r
+ } else if (((Slot->ExtCsd.DeviceType & (BIT2 | BIT3)) != 0) && (Capability.Ddr50 != 0)) {\r
+ HsTiming = 1;\r
+ IsDdr = TRUE;\r
+ ClockFreq = 52;\r
+ } else if (((Slot->ExtCsd.DeviceType & BIT1) != 0) && (Capability.HighSpeed != 0)) {\r
+ HsTiming = 1;\r
+ IsDdr = FALSE;\r
+ ClockFreq = 52;\r
+ } else if (((Slot->ExtCsd.DeviceType & BIT0) != 0) && (Capability.HighSpeed != 0)) {\r
+ HsTiming = 1;\r
+ IsDdr = FALSE;\r
+ ClockFreq = 26;\r
+ }\r
+ //\r
+ // Check if both of the device and the host controller support HS400 DDR mode.\r
+ //\r
+ if (((Slot->ExtCsd.DeviceType & (BIT6 | BIT7)) != 0) && (Capability.Hs400 != 0)) {\r
+ //\r
+ // The host controller supports 8bits bus.\r
+ //\r
+ ASSERT (BusWidth == 8);\r
+ HsTiming = 3;\r
+ IsDdr = TRUE;\r
+ ClockFreq = 200;\r
+ }\r
+\r
+ if ((ClockFreq == 0) || (HsTiming == 0)) {\r
+ //\r
+ // Continue using default setting.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "HsTiming %d ClockFreq %d BusWidth %d Ddr %a\n", HsTiming, ClockFreq, BusWidth, IsDdr ? "TRUE":"FALSE"));\r
+\r
+ if (HsTiming == 3) {\r
+ //\r
+ // Execute HS400 timing switch procedure\r
+ //\r
+ Status = EmmcPeimSwitchToHS400 (Slot, Rca, ClockFreq);\r
+ } else if (HsTiming == 2) {\r
+ //\r
+ // Execute HS200 timing switch procedure\r
+ //\r
+ Status = EmmcPeimSwitchToHS200 (Slot, Rca, ClockFreq, BusWidth);\r
+ } else {\r
+ //\r
+ // Execute High Speed timing switch procedure\r
+ //\r
+ Status = EmmcPeimSwitchToHighSpeed (Slot, Rca, ClockFreq, BusWidth, IsDdr);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Execute EMMC device identification procedure.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+\r
+ @retval EFI_SUCCESS There is a EMMC card.\r
+ @retval Others There is not a EMMC card.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimIdentification (\r
+ IN EMMC_PEIM_HC_SLOT *Slot\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Ocr;\r
+ UINT32 Rca;\r
+\r
+ Status = EmmcPeimReset (Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcPeimIdentification: EmmcPeimReset fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ Ocr = 0;\r
+ do {\r
+ Status = EmmcPeimGetOcr (Slot, &Ocr);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcPeimIdentification: EmmcPeimGetOcr fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ } while ((Ocr & BIT31) == 0);\r
+\r
+ Status = EmmcPeimGetAllCid (Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcPeimIdentification: EmmcPeimGetAllCid fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Don't support multiple devices on the slot, that is\r
+ // shared bus slot feature.\r
+ //\r
+ Rca = 1;\r
+ Status = EmmcPeimSetRca (Slot, Rca);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcPeimIdentification: EmmcPeimSetRca fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Enter Data Tranfer Mode.\r
+ //\r
+ DEBUG ((EFI_D_INFO, "Found a EMMC device at slot [%d], RCA [%d]\n", Slot, Rca));\r
+\r
+ Status = EmmcPeimSetBusMode (Slot, Rca);\r
+\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EMMC_HCI_H_\r
+#define _EMMC_HCI_H_\r
+\r
+//\r
+// EMMC Host Controller MMIO Register Offset\r
+//\r
+#define EMMC_HC_SDMA_ADDR 0x00\r
+#define EMMC_HC_ARG2 0x00\r
+#define EMMC_HC_BLK_SIZE 0x04\r
+#define EMMC_HC_BLK_COUNT 0x06\r
+#define EMMC_HC_ARG1 0x08\r
+#define EMMC_HC_TRANS_MOD 0x0C\r
+#define EMMC_HC_COMMAND 0x0E\r
+#define EMMC_HC_RESPONSE 0x10\r
+#define EMMC_HC_BUF_DAT_PORT 0x20\r
+#define EMMC_HC_PRESENT_STATE 0x24\r
+#define EMMC_HC_HOST_CTRL1 0x28\r
+#define EMMC_HC_POWER_CTRL 0x29\r
+#define EMMC_HC_BLK_GAP_CTRL 0x2A\r
+#define EMMC_HC_WAKEUP_CTRL 0x2B\r
+#define EMMC_HC_CLOCK_CTRL 0x2C\r
+#define EMMC_HC_TIMEOUT_CTRL 0x2E\r
+#define EMMC_HC_SW_RST 0x2F\r
+#define EMMC_HC_NOR_INT_STS 0x30\r
+#define EMMC_HC_ERR_INT_STS 0x32\r
+#define EMMC_HC_NOR_INT_STS_EN 0x34\r
+#define EMMC_HC_ERR_INT_STS_EN 0x36\r
+#define EMMC_HC_NOR_INT_SIG_EN 0x38\r
+#define EMMC_HC_ERR_INT_SIG_EN 0x3A\r
+#define EMMC_HC_AUTO_CMD_ERR_STS 0x3C\r
+#define EMMC_HC_HOST_CTRL2 0x3E\r
+#define EMMC_HC_CAP 0x40\r
+#define EMMC_HC_MAX_CURRENT_CAP 0x48\r
+#define EMMC_HC_FORCE_EVT_AUTO_CMD 0x50\r
+#define EMMC_HC_FORCE_EVT_ERR_INT 0x52\r
+#define EMMC_HC_ADMA_ERR_STS 0x54\r
+#define EMMC_HC_ADMA_SYS_ADDR 0x58\r
+#define EMMC_HC_PRESET_VAL 0x60\r
+#define EMMC_HC_SHARED_BUS_CTRL 0xE0\r
+#define EMMC_HC_SLOT_INT_STS 0xFC\r
+#define EMMC_HC_CTRL_VER 0xFE\r
+\r
+//\r
+// The transfer modes supported by SD Host Controller\r
+// Simplified Spec 3.0 Table 1-2\r
+//\r
+typedef enum {\r
+ EmmcNoData,\r
+ EmmcPioMode,\r
+ EmmcSdmaMode,\r
+ EmmcAdmaMode\r
+} EMMC_HC_TRANSFER_MODE;\r
+\r
+//\r
+// The maximum data length of each descriptor line\r
+//\r
+#define ADMA_MAX_DATA_PER_LINE 0x10000\r
+#define EMMC_SDMA_BOUNDARY 512 * 1024\r
+#define EMMC_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1))\r
+\r
+typedef enum {\r
+ EmmcCommandTypeBc, // Broadcast commands, no response\r
+ EmmcCommandTypeBcr, // Broadcast commands with response\r
+ EmmcCommandTypeAc, // Addressed(point-to-point) commands\r
+ EmmcCommandTypeAdtc // Addressed(point-to-point) data transfer commands\r
+} EMMC_COMMAND_TYPE;\r
+\r
+typedef enum {\r
+ EmmcResponceTypeR1,\r
+ EmmcResponceTypeR1b,\r
+ EmmcResponceTypeR2,\r
+ EmmcResponceTypeR3,\r
+ EmmcResponceTypeR4,\r
+ EmmcResponceTypeR5,\r
+ EmmcResponceTypeR5b,\r
+ EmmcResponceTypeR6,\r
+ EmmcResponceTypeR7\r
+} EMMC_RESPONSE_TYPE;\r
+\r
+typedef struct _EMMC_COMMAND_BLOCK {\r
+ UINT16 CommandIndex;\r
+ UINT32 CommandArgument;\r
+ UINT32 CommandType; // One of the EMMC_COMMAND_TYPE values\r
+ UINT32 ResponseType; // One of the EMMC_RESPONSE_TYPE values\r
+} EMMC_COMMAND_BLOCK;\r
+\r
+typedef struct _EMMC_STATUS_BLOCK {\r
+ UINT32 Resp0;\r
+ UINT32 Resp1;\r
+ UINT32 Resp2;\r
+ UINT32 Resp3;\r
+} EMMC_STATUS_BLOCK;\r
+\r
+typedef struct _EMMC_COMMAND_PACKET {\r
+ UINT64 Timeout;\r
+ EMMC_COMMAND_BLOCK *EmmcCmdBlk;\r
+ EMMC_STATUS_BLOCK *EmmcStatusBlk;\r
+ VOID *InDataBuffer;\r
+ VOID *OutDataBuffer;\r
+ UINT32 InTransferLength;\r
+ UINT32 OutTransferLength;\r
+} EMMC_COMMAND_PACKET;\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+ UINT32 Valid:1;\r
+ UINT32 End:1;\r
+ UINT32 Int:1;\r
+ UINT32 Reserved:1;\r
+ UINT32 Act:2;\r
+ UINT32 Reserved1:10;\r
+ UINT32 Length:16;\r
+ UINT32 Address;\r
+} EMMC_HC_ADMA_DESC_LINE;\r
+\r
+typedef struct {\r
+ UINT32 TimeoutFreq:6; // bit 0:5\r
+ UINT32 Reserved:1; // bit 6\r
+ UINT32 TimeoutUnit:1; // bit 7\r
+ UINT32 BaseClkFreq:8; // bit 8:15\r
+ UINT32 MaxBlkLen:2; // bit 16:17\r
+ UINT32 BusWidth8:1; // bit 18\r
+ UINT32 Adma2:1; // bit 19\r
+ UINT32 Reserved2:1; // bit 20\r
+ UINT32 HighSpeed:1; // bit 21\r
+ UINT32 Sdma:1; // bit 22\r
+ UINT32 SuspRes:1; // bit 23\r
+ UINT32 Voltage33:1; // bit 24\r
+ UINT32 Voltage30:1; // bit 25\r
+ UINT32 Voltage18:1; // bit 26\r
+ UINT32 Reserved3:1; // bit 27\r
+ UINT32 SysBus64:1; // bit 28\r
+ UINT32 AsyncInt:1; // bit 29\r
+ UINT32 SlotType:2; // bit 30:31\r
+ UINT32 Sdr50:1; // bit 32\r
+ UINT32 Sdr104:1; // bit 33\r
+ UINT32 Ddr50:1; // bit 34\r
+ UINT32 Reserved4:1; // bit 35\r
+ UINT32 DriverTypeA:1; // bit 36\r
+ UINT32 DriverTypeC:1; // bit 37\r
+ UINT32 DriverTypeD:1; // bit 38\r
+ UINT32 DriverType4:1; // bit 39\r
+ UINT32 TimerCount:4; // bit 40:43\r
+ UINT32 Reserved5:1; // bit 44\r
+ UINT32 TuningSDR50:1; // bit 45\r
+ UINT32 RetuningMod:2; // bit 46:47\r
+ UINT32 ClkMultiplier:8; // bit 48:55\r
+ UINT32 Reserved6:7; // bit 56:62\r
+ UINT32 Hs400:1; // bit 63\r
+} EMMC_HC_SLOT_CAP;\r
+\r
+#pragma pack()\r
+\r
+/**\r
+ Software reset the specified EMMC host controller and enable all interrupts.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The software reset executes successfully.\r
+ @retval Others The software reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcReset (\r
+ IN UINTN Bar\r
+ );\r
+\r
+/**\r
+ Set all interrupt status bits in Normal and Error Interrupt Status Enable\r
+ register.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The operation executes successfully.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcEnableInterrupt (\r
+ IN UINTN Bar\r
+ );\r
+\r
+/**\r
+ Get the capability data from the specified slot.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[out] Capability The buffer to store the capability data.\r
+\r
+ @retval EFI_SUCCESS The operation executes successfully.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcGetCapability (\r
+ IN UINTN Bar,\r
+ OUT EMMC_HC_SLOT_CAP *Capability\r
+ );\r
+\r
+/**\r
+ Detect whether there is a EMMC card attached at the specified EMMC host controller\r
+ slot.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS There is a EMMC card attached.\r
+ @retval EFI_NO_MEDIA There is not a EMMC card attached.\r
+ @retval Others The detection fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcCardDetect (\r
+ IN UINTN Bar\r
+ );\r
+\r
+/**\r
+ Initial EMMC host controller with lowest clock frequency, max power and max timeout value\r
+ at initialization.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The host controller is initialized successfully.\r
+ @retval Others The host controller isn't initialized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcInitHost (\r
+ IN UINTN Bar\r
+ );\r
+\r
+/**\r
+ Send command SWITCH to the EMMC device to switch the mode of operation of the\r
+ selected Device or modifies the EXT_CSD registers.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] Access The access mode of SWTICH command.\r
+ @param[in] Index The offset of the field to be access.\r
+ @param[in] Value The value to be set to the specified field of EXT_CSD register.\r
+ @param[in] CmdSet The value of CmdSet field of EXT_CSD register.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSwitch (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN UINT8 Access,\r
+ IN UINT8 Index,\r
+ IN UINT8 Value,\r
+ IN UINT8 CmdSet\r
+ );\r
+\r
+/**\r
+ Send command SET_BLOCK_COUNT to the addressed EMMC device to set the number of\r
+ blocks for the following block read/write cmd.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] BlockCount The number of the logical block to access.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSetBlkCount (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN UINT16 BlockCount\r
+ );\r
+\r
+/**\r
+ Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed EMMC device\r
+ to read/write the specified number of blocks.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+ @param[in] Lba The logical block address of starting access.\r
+ @param[in] BlockSize The block size of specified EMMC device partition.\r
+ @param[in] Buffer The pointer to the transfer buffer.\r
+ @param[in] BufferSize The size of transfer buffer.\r
+ @param[in] IsRead Boolean to show the operation direction.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimRwMultiBlocks (\r
+ IN EMMC_PEIM_HC_SLOT *Slot,\r
+ IN EFI_LBA Lba,\r
+ IN UINT32 BlockSize,\r
+ IN VOID *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN BOOLEAN IsRead\r
+ );\r
+\r
+/**\r
+ Execute EMMC device identification procedure.\r
+\r
+ Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Emmc card to send the command to.\r
+\r
+ @retval EFI_SUCCESS There is a EMMC card.\r
+ @retval Others There is not a EMMC card.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimIdentification (\r
+ IN EMMC_PEIM_HC_SLOT *Slot\r
+ );\r
+\r
+/**\r
+ Free the resource used by the TRB.\r
+\r
+ @param[in] Trb The pointer to the EMMC_TRB instance.\r
+\r
+**/\r
+VOID\r
+EmmcPeimFreeTrb (\r
+ IN EMMC_TRB *Trb\r
+ );\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+ UEFI Component Name(2) protocol implementation for EmmcDxe driver.\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "EmmcDxe.h"\r
+\r
+//\r
+// Driver name table\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mEmmcDxeDriverNameTable[] = {\r
+ { "eng;en", L"Edkii Emmc Device Driver" },\r
+ { NULL , NULL }\r
+};\r
+\r
+//\r
+// Controller name table\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mEmmcDxeControllerNameTable[] = {\r
+ { "eng;en", L"Edkii Emmc Host Controller" },\r
+ { NULL , NULL }\r
+};\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gEmmcDxeComponentName = {\r
+ EmmcDxeComponentNameGetDriverName,\r
+ EmmcDxeComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gEmmcDxeComponentName2 = {\r
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) EmmcDxeComponentNameGetDriverName,\r
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) EmmcDxeComponentNameGetControllerName,\r
+ "en"\r
+};\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+{\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ mEmmcDxeDriverNameTable,\r
+ DriverName,\r
+ (BOOLEAN)(This == &gEmmcDxeComponentName)\r
+ );\r
+\r
+}\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ EMMC_DEVICE *Device;\r
+ EMMC_PARTITION *Partition;\r
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;\r
+\r
+ //\r
+ // Make sure this driver is currently managing ControllHandle\r
+ //\r
+ Status = EfiTestManagedDevice (\r
+ ControllerHandle,\r
+ gEmmcDxeDriverBinding.DriverBindingHandle,\r
+ &gEfiSdMmcPassThruProtocolGuid\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ ControllerNameTable = mEmmcDxeControllerNameTable;\r
+ if (ChildHandle != NULL) {\r
+ Status = EfiTestChildHandle (\r
+ ControllerHandle,\r
+ ChildHandle,\r
+ &gEfiSdMmcPassThruProtocolGuid\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Get the child context\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlockIo,\r
+ gEmmcDxeDriverBinding.DriverBindingHandle,\r
+ ChildHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO (BlockIo);\r
+ Device = Partition->Device;\r
+ ControllerNameTable = Device->ControllerNameTable;\r
+ }\r
+\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ ControllerNameTable,\r
+ ControllerName,\r
+ (BOOLEAN)(This == &gEmmcDxeComponentName)\r
+ );}\r
+\r
--- /dev/null
+/** @file\r
+ The helper functions for BlockIo and BlockIo2 protocol.\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "EmmcDxe.h"\r
+\r
+/**\r
+ Nonblocking I/O callback funtion when the event is signaled.\r
+\r
+ @param[in] Event The Event this notify function registered to.\r
+ @param[in] Context Pointer to the context data registered to the\r
+ Event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AsyncIoCallback (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EMMC_REQUEST *Request;\r
+ EFI_STATUS Status;\r
+\r
+ Status = gBS->CloseEvent (Event);\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+\r
+ Request = (EMMC_REQUEST *) Context;\r
+\r
+ DEBUG_CODE_BEGIN ();\r
+ DEBUG ((EFI_D_INFO, "Emmc Async Request: CmdIndex[%d] Arg[%08x] %r\n",\r
+ Request->SdMmcCmdBlk.CommandIndex, Request->SdMmcCmdBlk.CommandArgument,\r
+ Request->Packet.TransactionStatus));\r
+ DEBUG_CODE_END ();\r
+\r
+ if (EFI_ERROR (Request->Packet.TransactionStatus)) {\r
+ Request->Token->TransactionStatus = Request->Packet.TransactionStatus;\r
+ }\r
+\r
+ RemoveEntryList (&Request->Link);\r
+\r
+ if (Request->IsEnd) {\r
+ gBS->SignalEvent (Request->Token->Event);\r
+ }\r
+\r
+ FreePool (Request);\r
+}\r
+\r
+/**\r
+ Send command SELECT to the device to select/deselect the device.\r
+\r
+ @param[in] Device A pointer to the EMMC_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSelect (\r
+ IN EMMC_DEVICE *Device,\r
+ IN UINT16 Rca\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = EMMC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_STATUS to the device to get device status.\r
+\r
+ @param[in] Device A pointer to the EMMC_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+ @param[out] DevStatus The buffer to store the device status.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSendStatus (\r
+ IN EMMC_DEVICE *Device,\r
+ IN UINT16 Rca,\r
+ OUT UINT32 *DevStatus\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = EMMC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ CopyMem (DevStatus, &SdMmcStatusBlk.Resp0, sizeof (UINT32));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_CSD to the device to get the CSD register data.\r
+\r
+ @param[in] Device A pointer to the EMMC_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+ @param[out] Csd The buffer to store the EMMC_CSD register data.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetCsd (\r
+ IN EMMC_DEVICE *Device,\r
+ IN UINT16 Rca,\r
+ OUT EMMC_CSD *Csd\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ ZeroMem (Csd, sizeof (EMMC_CSD));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = EMMC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+ //\r
+ CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_CID to the device to get the CID register data.\r
+\r
+ @param[in] Device A pointer to the EMMC_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+ @param[out] Cid The buffer to store the EMMC_CID register data.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetCid (\r
+ IN EMMC_DEVICE *Device,\r
+ IN UINT16 Rca,\r
+ OUT EMMC_CID *Cid\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ ZeroMem (Cid, sizeof (EMMC_CID));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = EMMC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_CID;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+ //\r
+ CopyMem (((UINT8*)Cid) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CID) - 1);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_EXT_CSD to the device to get the EXT_CSD register data.\r
+\r
+ @param[in] Device A pointer to the EMMC_DEVICE instance.\r
+ @param[out] ExtCsd The buffer to store the EXT_CSD register data.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetExtCsd (\r
+ IN EMMC_DEVICE *Device,\r
+ OUT EMMC_EXT_CSD *ExtCsd\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ ZeroMem (ExtCsd, sizeof (EMMC_EXT_CSD));\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = EMMC_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ SdMmcCmdBlk.CommandArgument = 0x00000000;\r
+ Packet.InDataBuffer = ExtCsd;\r
+ Packet.InTransferLength = sizeof (EMMC_EXT_CSD);\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set the specified EXT_CSD register field through sync or async I/O request.\r
+\r
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.\r
+ @param[in] Offset The offset of the specified field in EXT_CSD register.\r
+ @param[in] Value The byte value written to the field specified by Offset.\r
+ @param[in] Token A pointer to the token associated with the transaction.\r
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
+ This parameter is only meaningful in async I/O request.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSetExtCsd (\r
+ IN EMMC_PARTITION *Partition,\r
+ IN UINT8 Offset,\r
+ IN UINT8 Value,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN BOOLEAN IsEnd\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_DEVICE *Device;\r
+ EMMC_REQUEST *SetExtCsdReq;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ UINT32 CommandArgument;\r
+ EFI_TPL OldTpl;\r
+\r
+ SetExtCsdReq = NULL;\r
+\r
+ Device = Partition->Device;\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ SetExtCsdReq = AllocateZeroPool (sizeof (EMMC_REQUEST));\r
+ if (SetExtCsdReq == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ SetExtCsdReq->Signature = EMMC_REQUEST_SIGNATURE;\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ InsertTailList (&Partition->Queue, &SetExtCsdReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ SetExtCsdReq->Packet.SdMmcCmdBlk = &SetExtCsdReq->SdMmcCmdBlk;\r
+ SetExtCsdReq->Packet.SdMmcStatusBlk = &SetExtCsdReq->SdMmcStatusBlk;\r
+ SetExtCsdReq->Packet.Timeout = EMMC_GENERIC_TIMEOUT;\r
+\r
+ SetExtCsdReq->SdMmcCmdBlk.CommandIndex = EMMC_SWITCH;\r
+ SetExtCsdReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SetExtCsdReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
+ //\r
+ // Write the Value to the field specified by Offset.\r
+ //\r
+ CommandArgument = (Value << 8) | (Offset << 16) | BIT24 | BIT25;\r
+ SetExtCsdReq->SdMmcCmdBlk.CommandArgument = CommandArgument;\r
+\r
+ SetExtCsdReq->IsEnd = IsEnd;\r
+ SetExtCsdReq->Token = Token;\r
+\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ AsyncIoCallback,\r
+ SetExtCsdReq,\r
+ &SetExtCsdReq->Event\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ } else {\r
+ SetExtCsdReq->Event = NULL;\r
+ }\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &SetExtCsdReq->Packet, SetExtCsdReq->Event);\r
+\r
+Error:\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ //\r
+ // For asynchronous operation, only free request and event in error case.\r
+ // The request and event will be freed in asynchronous callback for success case.\r
+ //\r
+ if (EFI_ERROR (Status) && (SetExtCsdReq != NULL)) {\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ RemoveEntryList (&SetExtCsdReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ if (SetExtCsdReq->Event != NULL) {\r
+ gBS->CloseEvent (SetExtCsdReq->Event);\r
+ }\r
+ FreePool (SetExtCsdReq);\r
+ }\r
+ } else {\r
+ //\r
+ // For synchronous operation, free request whatever the execution result is.\r
+ //\r
+ if (SetExtCsdReq != NULL) {\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ RemoveEntryList (&SetExtCsdReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ FreePool (SetExtCsdReq);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set the number of blocks for a block read/write cmd through sync or async I/O request.\r
+\r
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.\r
+ @param[in] BlockNum The number of blocks for transfer.\r
+ @param[in] Token A pointer to the token associated with the transaction.\r
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
+ This parameter is only meaningful in async I/O request.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSetBlkCount (\r
+ IN EMMC_PARTITION *Partition,\r
+ IN UINT16 BlockNum,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN BOOLEAN IsEnd\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_DEVICE *Device;\r
+ EMMC_REQUEST *SetBlkCntReq;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_TPL OldTpl;\r
+\r
+ SetBlkCntReq = NULL;\r
+\r
+ Device = Partition->Device;\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ SetBlkCntReq = AllocateZeroPool (sizeof (EMMC_REQUEST));\r
+ if (SetBlkCntReq == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ SetBlkCntReq->Signature = EMMC_REQUEST_SIGNATURE;\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ InsertTailList (&Partition->Queue, &SetBlkCntReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ SetBlkCntReq->Packet.SdMmcCmdBlk = &SetBlkCntReq->SdMmcCmdBlk;\r
+ SetBlkCntReq->Packet.SdMmcStatusBlk = &SetBlkCntReq->SdMmcStatusBlk;\r
+ SetBlkCntReq->Packet.Timeout = EMMC_GENERIC_TIMEOUT;\r
+\r
+ SetBlkCntReq->SdMmcCmdBlk.CommandIndex = EMMC_SET_BLOCK_COUNT;\r
+ SetBlkCntReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SetBlkCntReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ SetBlkCntReq->SdMmcCmdBlk.CommandArgument = BlockNum;\r
+\r
+ SetBlkCntReq->IsEnd = IsEnd;\r
+ SetBlkCntReq->Token = Token;\r
+\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ AsyncIoCallback,\r
+ SetBlkCntReq,\r
+ &SetBlkCntReq->Event\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ } else {\r
+ SetBlkCntReq->Event = NULL;\r
+ }\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &SetBlkCntReq->Packet, SetBlkCntReq->Event);\r
+\r
+Error:\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ //\r
+ // For asynchronous operation, only free request and event in error case.\r
+ // The request and event will be freed in asynchronous callback for success case.\r
+ //\r
+ if (EFI_ERROR (Status) && (SetBlkCntReq != NULL)) {\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ RemoveEntryList (&SetBlkCntReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ if (SetBlkCntReq->Event != NULL) {\r
+ gBS->CloseEvent (SetBlkCntReq->Event);\r
+ }\r
+ FreePool (SetBlkCntReq);\r
+ }\r
+ } else {\r
+ //\r
+ // For synchronous operation, free request whatever the execution result is.\r
+ //\r
+ if (SetBlkCntReq != NULL) {\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ RemoveEntryList (&SetBlkCntReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ FreePool (SetBlkCntReq);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read blocks through security protocol cmds with the way of sync or async I/O request.\r
+\r
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.\r
+ @param[in] SecurityProtocolId The value of the "Security Protocol" parameter of\r
+ the security protocol command to be sent.\r
+ @param[in] SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
+ of the security protocol command to be sent.\r
+ @param[in] PayloadBufferSize Size in bytes of the payload data buffer.\r
+ @param[out] PayloadBuffer A pointer to a destination buffer to store the security\r
+ protocol command specific payload data for the security\r
+ protocol command. The caller is responsible for having\r
+ either implicit or explicit ownership of the buffer.\r
+ @param[in] IsRead Indicates it is a read or write operation.\r
+ @param[in] Timeout The timeout value, in 100ns units.\r
+ @param[in] Token A pointer to the token associated with the transaction.\r
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
+ This parameter is only meaningful in async I/O request.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcProtocolInOut (\r
+ IN EMMC_PARTITION *Partition,\r
+ IN UINT8 SecurityProtocol,\r
+ IN UINT16 SecurityProtocolSpecificData,\r
+ IN UINTN PayloadBufferSize,\r
+ OUT VOID *PayloadBuffer,\r
+ IN BOOLEAN IsRead,\r
+ IN UINT64 Timeout,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN BOOLEAN IsEnd\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_DEVICE *Device;\r
+ EMMC_REQUEST *ProtocolReq;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_TPL OldTpl;\r
+\r
+ ProtocolReq = NULL;\r
+\r
+ Device = Partition->Device;\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ ProtocolReq = AllocateZeroPool (sizeof (EMMC_REQUEST));\r
+ if (ProtocolReq == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ ProtocolReq->Signature = EMMC_REQUEST_SIGNATURE;\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ InsertTailList (&Partition->Queue, &ProtocolReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ ProtocolReq->Packet.SdMmcCmdBlk = &ProtocolReq->SdMmcCmdBlk;\r
+ ProtocolReq->Packet.SdMmcStatusBlk = &ProtocolReq->SdMmcStatusBlk;\r
+\r
+ if (IsRead) {\r
+ ProtocolReq->Packet.InDataBuffer = PayloadBuffer;\r
+ ProtocolReq->Packet.InTransferLength = (UINT32)PayloadBufferSize;\r
+\r
+ ProtocolReq->SdMmcCmdBlk.CommandIndex = EMMC_PROTOCOL_RD;\r
+ ProtocolReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ ProtocolReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ } else {\r
+ ProtocolReq->Packet.OutDataBuffer = PayloadBuffer;\r
+ ProtocolReq->Packet.OutTransferLength = (UINT32)PayloadBufferSize;\r
+\r
+ ProtocolReq->SdMmcCmdBlk.CommandIndex = EMMC_PROTOCOL_WR;\r
+ ProtocolReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ ProtocolReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ }\r
+\r
+ ProtocolReq->SdMmcCmdBlk.CommandArgument = (SecurityProtocol << 8) | (SecurityProtocolSpecificData << 16);\r
+ //\r
+ // Convert to 1 microsecond unit.\r
+ //\r
+ ProtocolReq->Packet.Timeout = DivU64x32 (Timeout, 10) + 1;\r
+\r
+ ProtocolReq->IsEnd = IsEnd;\r
+ ProtocolReq->Token = Token;\r
+\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ AsyncIoCallback,\r
+ ProtocolReq,\r
+ &ProtocolReq->Event\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ } else {\r
+ ProtocolReq->Event = NULL;\r
+ }\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &ProtocolReq->Packet, ProtocolReq->Event);\r
+\r
+Error:\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ //\r
+ // For asynchronous operation, only free request and event in error case.\r
+ // The request and event will be freed in asynchronous callback for success case.\r
+ //\r
+ if (EFI_ERROR (Status) && (ProtocolReq != NULL)) {\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ RemoveEntryList (&ProtocolReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ if (ProtocolReq->Event != NULL) {\r
+ gBS->CloseEvent (ProtocolReq->Event);\r
+ }\r
+ FreePool (ProtocolReq);\r
+ }\r
+ } else {\r
+ //\r
+ // For synchronous operation, free request whatever the execution result is.\r
+ //\r
+ if (ProtocolReq != NULL) {\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ RemoveEntryList (&ProtocolReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ FreePool (ProtocolReq);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read/write multiple blocks through sync or async I/O request.\r
+\r
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.\r
+ @param[in] Lba The starting logical block address to be read/written.\r
+ The caller is responsible for reading/writing to only\r
+ legitimate locations.\r
+ @param[in] Buffer A pointer to the destination/source buffer for the data.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[in] IsRead Indicates it is a read or write operation.\r
+ @param[in] Token A pointer to the token associated with the transaction.\r
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
+ This parameter is only meaningful in async I/O request.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcRwMultiBlocks (\r
+ IN EMMC_PARTITION *Partition,\r
+ IN EFI_LBA Lba,\r
+ IN VOID *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN BOOLEAN IsRead,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN BOOLEAN IsEnd\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_DEVICE *Device;\r
+ EMMC_REQUEST *RwMultiBlkReq;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_TPL OldTpl;\r
+\r
+ RwMultiBlkReq = NULL;\r
+\r
+ Device = Partition->Device;\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ RwMultiBlkReq = AllocateZeroPool (sizeof (EMMC_REQUEST));\r
+ if (RwMultiBlkReq == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ RwMultiBlkReq->Signature = EMMC_REQUEST_SIGNATURE;\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ InsertTailList (&Partition->Queue, &RwMultiBlkReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ RwMultiBlkReq->Packet.SdMmcCmdBlk = &RwMultiBlkReq->SdMmcCmdBlk;\r
+ RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk;\r
+ //\r
+ // Calculate timeout value through the below formula.\r
+ // Timeout = (transfer size) / (2MB/s).\r
+ // Taking 2MB/s as divisor is because it's nearest to the eMMC lowest\r
+ // transfer speed (2.4MB/s).\r
+ // Refer to eMMC 5.0 spec section 6.9.1 for details.\r
+ //\r
+ RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;\r
+\r
+ if (IsRead) {\r
+ RwMultiBlkReq->Packet.InDataBuffer = Buffer;\r
+ RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;\r
+\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = EMMC_READ_MULTIPLE_BLOCK;\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ } else {\r
+ RwMultiBlkReq->Packet.OutDataBuffer = Buffer;\r
+ RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;\r
+\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = EMMC_WRITE_MULTIPLE_BLOCK;\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ }\r
+\r
+ if (Partition->Device->SectorAddressing) {\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;\r
+ } else {\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Partition->BlockMedia.BlockSize);\r
+ }\r
+\r
+ RwMultiBlkReq->IsEnd = IsEnd;\r
+ RwMultiBlkReq->Token = Token;\r
+\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ AsyncIoCallback,\r
+ RwMultiBlkReq,\r
+ &RwMultiBlkReq->Event\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ } else {\r
+ RwMultiBlkReq->Event = NULL;\r
+ }\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);\r
+\r
+Error:\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ //\r
+ // For asynchronous operation, only free request and event in error case.\r
+ // The request and event will be freed in asynchronous callback for success case.\r
+ //\r
+ if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ RemoveEntryList (&RwMultiBlkReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ if (RwMultiBlkReq->Event != NULL) {\r
+ gBS->CloseEvent (RwMultiBlkReq->Event);\r
+ }\r
+ FreePool (RwMultiBlkReq);\r
+ }\r
+ } else {\r
+ //\r
+ // For synchronous operation, free request whatever the execution result is.\r
+ //\r
+ if (RwMultiBlkReq != NULL) {\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ RemoveEntryList (&RwMultiBlkReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ FreePool (RwMultiBlkReq);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function transfers data from/to EMMC device.\r
+\r
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.\r
+ @param[in] MediaId The media ID that the read/write request is for.\r
+ @param[in] Lba The starting logical block address to be read/written.\r
+ The caller is responsible for reading/writing to only\r
+ legitimate locations.\r
+ @param[in, out] Buffer A pointer to the destination/source buffer for the data.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[in] IsRead Indicates it is a read or write operation.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+\r
+ @retval EFI_SUCCESS The data was read/written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device can not be read/written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcReadWrite (\r
+ IN EMMC_PARTITION *Partition,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT VOID *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN BOOLEAN IsRead,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_DEVICE *Device;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ UINTN BlockSize;\r
+ UINTN BlockNum;\r
+ UINTN IoAlign;\r
+ UINT8 PartitionConfig;\r
+ UINTN Remaining;\r
+ UINT32 MaxBlock;\r
+ BOOLEAN LastRw;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Device = Partition->Device;\r
+ Media = &Partition->BlockMedia;\r
+ LastRw = FALSE;\r
+\r
+ if (MediaId != Media->MediaId) {\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ if (!IsRead && Media->ReadOnly) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
+ //\r
+ // Check parameters.\r
+ //\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ gBS->SignalEvent (Token->Event);\r
+ }\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ BlockSize = Media->BlockSize;\r
+ if ((BufferSize % BlockSize) != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ BlockNum = BufferSize / BlockSize;\r
+ if ((Lba + BlockNum - 1) > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ IoAlign = Media->IoAlign;\r
+ if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ }\r
+ //\r
+ // Check if needs to switch partition access.\r
+ //\r
+ PartitionConfig = Device->ExtCsd.PartitionConfig;\r
+ if ((PartitionConfig & 0x7) != Partition->PartitionType) {\r
+ PartitionConfig &= (UINT8)~0x7;\r
+ PartitionConfig |= Partition->PartitionType;\r
+ Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, Token, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ Device->ExtCsd.PartitionConfig = PartitionConfig;\r
+ }\r
+ //\r
+ // Start to execute data transfer. The max block number in single cmd is 65535 blocks.\r
+ //\r
+ Remaining = BlockNum;\r
+ MaxBlock = 0xFFFF;\r
+\r
+ while (Remaining > 0) {\r
+ if (Remaining <= MaxBlock) {\r
+ BlockNum = Remaining;\r
+ LastRw = TRUE;\r
+ } else {\r
+ BlockNum = MaxBlock;\r
+ }\r
+ Status = EmmcSetBlkCount (Partition, (UINT16)BlockNum, Token, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ BufferSize = BlockNum * BlockSize;\r
+ Status = EmmcRwMultiBlocks (Partition, Lba, Buffer, BufferSize, IsRead, Token, LastRw);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ DEBUG ((EFI_D_INFO, "Emmc%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", IsRead ? "Read" : "Write", Lba, BlockNum, Token->Event, Status));\r
+\r
+ Lba += BlockNum;\r
+ Buffer = (UINT8*)Buffer + BufferSize;\r
+ Remaining -= BlockNum;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Reset the Block Device.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
+ not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcReset (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_PARTITION *Partition;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+\r
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);\r
+\r
+ PassThru = Partition->Device->Private->PassThru;\r
+ Status = PassThru->ResetDevice (PassThru, Partition->Device->Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId Id of the media, changes every time the media is replaced.\r
+ @param Lba The starting Logical Block Address to read from\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller is\r
+ responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcReadBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_PARTITION *Partition;\r
+\r
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);\r
+\r
+ Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Write BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId The media ID that the write request is for.\r
+ @param Lba The starting logical block address to be written. The caller is\r
+ responsible for writing to only legitimate locations.\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the source buffer for the data.\r
+\r
+ @retval EFI_SUCCESS The data was written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device can not be written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcWriteBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_PARTITION *Partition;\r
+\r
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);\r
+\r
+ Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Flush the Block Device.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+\r
+ @retval EFI_SUCCESS All outstanding data was written to the device\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcFlushBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This\r
+ )\r
+{\r
+ //\r
+ // return directly\r
+ //\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Reset the Block Device.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
+ not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcResetEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ EMMC_PARTITION *Partition;\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *NextLink;\r
+ EMMC_REQUEST *Request;\r
+ EFI_TPL OldTpl;\r
+\r
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ for (Link = GetFirstNode (&Partition->Queue);\r
+ !IsNull (&Partition->Queue, Link);\r
+ Link = NextLink) {\r
+ NextLink = GetNextNode (&Partition->Queue, Link);\r
+ RemoveEntryList (Link);\r
+\r
+ Request = EMMC_REQUEST_FROM_LINK (Link);\r
+\r
+ gBS->CloseEvent (Request->Event);\r
+ Request->Token->TransactionStatus = EFI_ABORTED;\r
+\r
+ if (Request->IsEnd) {\r
+ gBS->SignalEvent (Request->Token->Event);\r
+ }\r
+\r
+ FreePool (Request);\r
+ }\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read BufferSize bytes from Lba into Buffer.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] MediaId Id of the media, changes every time the media is replaced.\r
+ @param[in] Lba The starting Logical Block Address to read from.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[out] Buffer A pointer to the destination buffer for the data. The caller is\r
+ responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+ @retval EFI_SUCCESS The read request was queued if Event is not NULL.\r
+ The data was read correctly from the device if\r
+ the Event is NULL.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing\r
+ the read.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r
+ intrinsic block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
+ of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcReadBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_PARTITION *Partition;\r
+\r
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);\r
+\r
+ Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, TRUE, Token);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Write BufferSize bytes from Lba into Buffer.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] MediaId The media ID that the write request is for.\r
+ @param[in] Lba The starting logical block address to be written. The\r
+ caller is responsible for writing to only legitimate\r
+ locations.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[in] Buffer A pointer to the source buffer for the data.\r
+\r
+ @retval EFI_SUCCESS The data was written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device can not be written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcWriteBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_PARTITION *Partition;\r
+\r
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);\r
+\r
+ Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, FALSE, Token);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Flush the Block Device.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+\r
+ @retval EFI_SUCCESS All outstanding data was written to the device\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcFlushBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
+ )\r
+{\r
+ //\r
+ // Signal event and return directly.\r
+ //\r
+ if (Token != NULL && Token->Event != NULL) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ gBS->SignalEvent (Token->Event);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Send a security protocol command to a device that receives data and/or the result\r
+ of one or more commands sent by SendData.\r
+\r
+ The ReceiveData function sends a security protocol command to the given MediaId.\r
+ The security protocol command sent is defined by SecurityProtocolId and contains\r
+ the security protocol specific data SecurityProtocolSpecificData. The function\r
+ returns the data from the security protocol command in PayloadBuffer.\r
+\r
+ For devices supporting the SCSI command set, the security protocol command is sent\r
+ using the SECURITY PROTOCOL IN command defined in SPC-4.\r
+\r
+ For devices supporting the ATA command set, the security protocol command is sent\r
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize\r
+ is non-zero.\r
+\r
+ If the PayloadBufferSize is zero, the security protocol command is sent using the\r
+ Trusted Non-Data command defined in ATA8-ACS.\r
+\r
+ If PayloadBufferSize is too small to store the available data from the security\r
+ protocol command, the function shall copy PayloadBufferSize bytes into the\r
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.\r
+\r
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,\r
+ the function shall return EFI_INVALID_PARAMETER.\r
+\r
+ If the given MediaId does not support security protocol commands, the function shall\r
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns\r
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,\r
+ the function returns EFI_MEDIA_CHANGED.\r
+\r
+ If the security protocol fails to complete within the Timeout period, the function\r
+ shall return EFI_TIMEOUT.\r
+\r
+ If the security protocol command completes without an error, the function shall\r
+ return EFI_SUCCESS. If the security protocol command completes with an error, the\r
+ function shall return EFI_DEVICE_ERROR.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] MediaId ID of the medium to receive data from.\r
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution\r
+ of the security protocol command. A Timeout value of 0\r
+ means that this function will wait indefinitely for the\r
+ security protocol command to execute. If Timeout is greater\r
+ than zero, then this function will return EFI_TIMEOUT\r
+ if the time required to execute the receive data command\r
+ is greater than Timeout.\r
+ @param[in] SecurityProtocolId The value of the "Security Protocol" parameter of\r
+ the security protocol command to be sent.\r
+ @param[in] SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
+ of the security protocol command to be sent.\r
+ @param[in] PayloadBufferSize Size in bytes of the payload data buffer.\r
+ @param[out] PayloadBuffer A pointer to a destination buffer to store the security\r
+ protocol command specific payload data for the security\r
+ protocol command. The caller is responsible for having\r
+ either implicit or explicit ownership of the buffer.\r
+ @param[out] PayloadTransferSize A pointer to a buffer to store the size in bytes of the\r
+ data written to the payload data buffer.\r
+ @param[in] IsRead Indicates it is a read or write operation.\r
+\r
+ @retval EFI_SUCCESS The security protocol command completed successfully.\r
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available\r
+ data from the device. The PayloadBuffer contains the truncated data.\r
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.\r
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and\r
+ PayloadBufferSize is non-zero.\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security\r
+ protocol command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcSecurityProtocolInOut (\r
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN UINT64 Timeout,\r
+ IN UINT8 SecurityProtocolId,\r
+ IN UINT16 SecurityProtocolSpecificData,\r
+ IN UINTN PayloadBufferSize,\r
+ OUT VOID *PayloadBuffer,\r
+ OUT UINTN *PayloadTransferSize,\r
+ IN BOOLEAN IsRead\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_PARTITION *Partition;\r
+ EMMC_DEVICE *Device;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ UINTN BlockSize;\r
+ UINTN BlockNum;\r
+ UINTN IoAlign;\r
+ UINTN Remaining;\r
+ UINT32 MaxBlock;\r
+ UINT8 PartitionConfig;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Partition = EMMC_PARTITION_DATA_FROM_SSP (This);\r
+ Device = Partition->Device;\r
+ Media = &Partition->BlockMedia;\r
+\r
+ if (PayloadTransferSize != NULL) {\r
+ *PayloadTransferSize = 0;\r
+ }\r
+\r
+ if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (MediaId != Media->MediaId) {\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ if (PayloadBufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ BlockSize = Media->BlockSize;\r
+ if ((PayloadBufferSize % BlockSize) != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ BlockNum = PayloadBufferSize / BlockSize;\r
+\r
+ IoAlign = Media->IoAlign;\r
+ if (IoAlign > 0 && (((UINTN) PayloadBuffer & (IoAlign - 1)) != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Security protocol interface is synchronous transfer.\r
+ // Waiting for async I/O list to be empty before any operation.\r
+ //\r
+ while (!IsListEmpty (&Partition->Queue));\r
+\r
+ //\r
+ // Check if needs to switch partition access.\r
+ //\r
+ PartitionConfig = Device->ExtCsd.PartitionConfig;\r
+ if ((PartitionConfig & 0x7) != Partition->PartitionType) {\r
+ PartitionConfig &= (UINT8)~0x7;\r
+ PartitionConfig |= Partition->PartitionType;\r
+ Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, NULL, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ Device->ExtCsd.PartitionConfig = PartitionConfig;\r
+ }\r
+ //\r
+ // Start to execute data transfer. The max block number in single cmd is 65535 blocks.\r
+ //\r
+ Remaining = BlockNum;\r
+ MaxBlock = 0xFFFF;\r
+\r
+ while (Remaining > 0) {\r
+ if (Remaining <= MaxBlock) {\r
+ BlockNum = Remaining;\r
+ } else {\r
+ BlockNum = MaxBlock;\r
+ }\r
+\r
+ Status = EmmcSetBlkCount (Partition, (UINT16)BlockNum, NULL, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ PayloadBufferSize = BlockNum * BlockSize;\r
+ Status = EmmcProtocolInOut (Partition, SecurityProtocolId, SecurityProtocolSpecificData, PayloadBufferSize, PayloadBuffer, IsRead, Timeout, NULL, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ PayloadBuffer = (UINT8*)PayloadBuffer + PayloadBufferSize;\r
+ Remaining -= BlockNum;\r
+ if (PayloadTransferSize != NULL) {\r
+ *PayloadTransferSize += PayloadBufferSize;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send a security protocol command to a device that receives data and/or the result\r
+ of one or more commands sent by SendData.\r
+\r
+ The ReceiveData function sends a security protocol command to the given MediaId.\r
+ The security protocol command sent is defined by SecurityProtocolId and contains\r
+ the security protocol specific data SecurityProtocolSpecificData. The function\r
+ returns the data from the security protocol command in PayloadBuffer.\r
+\r
+ For devices supporting the SCSI command set, the security protocol command is sent\r
+ using the SECURITY PROTOCOL IN command defined in SPC-4.\r
+\r
+ For devices supporting the ATA command set, the security protocol command is sent\r
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize\r
+ is non-zero.\r
+\r
+ If the PayloadBufferSize is zero, the security protocol command is sent using the\r
+ Trusted Non-Data command defined in ATA8-ACS.\r
+\r
+ If PayloadBufferSize is too small to store the available data from the security\r
+ protocol command, the function shall copy PayloadBufferSize bytes into the\r
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.\r
+\r
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,\r
+ the function shall return EFI_INVALID_PARAMETER.\r
+\r
+ If the given MediaId does not support security protocol commands, the function shall\r
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns\r
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,\r
+ the function returns EFI_MEDIA_CHANGED.\r
+\r
+ If the security protocol fails to complete within the Timeout period, the function\r
+ shall return EFI_TIMEOUT.\r
+\r
+ If the security protocol command completes without an error, the function shall\r
+ return EFI_SUCCESS. If the security protocol command completes with an error, the\r
+ function shall return EFI_DEVICE_ERROR.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId ID of the medium to receive data from.\r
+ @param Timeout The timeout, in 100ns units, to use for the execution\r
+ of the security protocol command. A Timeout value of 0\r
+ means that this function will wait indefinitely for the\r
+ security protocol command to execute. If Timeout is greater\r
+ than zero, then this function will return EFI_TIMEOUT\r
+ if the time required to execute the receive data command\r
+ is greater than Timeout.\r
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of\r
+ the security protocol command to be sent.\r
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
+ of the security protocol command to be sent.\r
+ @param PayloadBufferSize Size in bytes of the payload data buffer.\r
+ @param PayloadBuffer A pointer to a destination buffer to store the security\r
+ protocol command specific payload data for the security\r
+ protocol command. The caller is responsible for having\r
+ either implicit or explicit ownership of the buffer.\r
+ @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the\r
+ data written to the payload data buffer.\r
+\r
+ @retval EFI_SUCCESS The security protocol command completed successfully.\r
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available\r
+ data from the device. The PayloadBuffer contains the truncated data.\r
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.\r
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and\r
+ PayloadBufferSize is non-zero.\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security\r
+ protocol command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcSecurityProtocolIn (\r
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN UINT64 Timeout,\r
+ IN UINT8 SecurityProtocolId,\r
+ IN UINT16 SecurityProtocolSpecificData,\r
+ IN UINTN PayloadBufferSize,\r
+ OUT VOID *PayloadBuffer,\r
+ OUT UINTN *PayloadTransferSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if ((PayloadTransferSize == NULL) && PayloadBufferSize != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = EmmcSecurityProtocolInOut (\r
+ This,\r
+ MediaId,\r
+ Timeout,\r
+ SecurityProtocolId,\r
+ SecurityProtocolSpecificData,\r
+ PayloadBufferSize,\r
+ PayloadBuffer,\r
+ PayloadTransferSize,\r
+ TRUE\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send a security protocol command to a device.\r
+\r
+ The SendData function sends a security protocol command containing the payload\r
+ PayloadBuffer to the given MediaId. The security protocol command sent is\r
+ defined by SecurityProtocolId and contains the security protocol specific data\r
+ SecurityProtocolSpecificData. If the underlying protocol command requires a\r
+ specific padding for the command payload, the SendData function shall add padding\r
+ bytes to the command payload to satisfy the padding requirements.\r
+\r
+ For devices supporting the SCSI command set, the security protocol command is sent\r
+ using the SECURITY PROTOCOL OUT command defined in SPC-4.\r
+\r
+ For devices supporting the ATA command set, the security protocol command is sent\r
+ using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize\r
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command is\r
+ sent using the Trusted Non-Data command defined in ATA8-ACS.\r
+\r
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall\r
+ return EFI_INVALID_PARAMETER.\r
+\r
+ If the given MediaId does not support security protocol commands, the function\r
+ shall return EFI_UNSUPPORTED. If there is no media in the device, the function\r
+ returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the\r
+ device, the function returns EFI_MEDIA_CHANGED.\r
+\r
+ If the security protocol fails to complete within the Timeout period, the function\r
+ shall return EFI_TIMEOUT.\r
+\r
+ If the security protocol command completes without an error, the function shall return\r
+ EFI_SUCCESS. If the security protocol command completes with an error, the function\r
+ shall return EFI_DEVICE_ERROR.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId ID of the medium to receive data from.\r
+ @param Timeout The timeout, in 100ns units, to use for the execution\r
+ of the security protocol command. A Timeout value of 0\r
+ means that this function will wait indefinitely for the\r
+ security protocol command to execute. If Timeout is greater\r
+ than zero, then this function will return EFI_TIMEOUT\r
+ if the time required to execute the receive data command\r
+ is greater than Timeout.\r
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of\r
+ the security protocol command to be sent.\r
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
+ of the security protocol command to be sent.\r
+ @param PayloadBufferSize Size in bytes of the payload data buffer.\r
+ @param PayloadBuffer A pointer to a destination buffer to store the security\r
+ protocol command specific payload data for the security\r
+ protocol command.\r
+\r
+ @retval EFI_SUCCESS The security protocol command completed successfully.\r
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.\r
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security\r
+ protocol command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcSecurityProtocolOut (\r
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN UINT64 Timeout,\r
+ IN UINT8 SecurityProtocolId,\r
+ IN UINT16 SecurityProtocolSpecificData,\r
+ IN UINTN PayloadBufferSize,\r
+ IN VOID *PayloadBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = EmmcSecurityProtocolInOut (\r
+ This,\r
+ MediaId,\r
+ Timeout,\r
+ SecurityProtocolId,\r
+ SecurityProtocolSpecificData,\r
+ PayloadBufferSize,\r
+ PayloadBuffer,\r
+ NULL,\r
+ FALSE\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ Header file for EmmcDxe Driver.\r
+\r
+ This file defines common data structures, macro definitions and some module\r
+ internal function header files.\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EMMC_BLOCK_IO_H_\r
+#define _EMMC_BLOCK_IO_H_\r
+\r
+/**\r
+ Reset the Block Device.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
+ not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcReset (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ );\r
+\r
+/**\r
+ Read BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId Id of the media, changes every time the media is replaced.\r
+ @param Lba The starting Logical Block Address to read from\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller is\r
+ responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcReadBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Write BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId The media ID that the write request is for.\r
+ @param Lba The starting logical block address to be written. The caller is\r
+ responsible for writing to only legitimate locations.\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the source buffer for the data.\r
+\r
+ @retval EFI_SUCCESS The data was written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device can not be written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcWriteBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Flush the Block Device.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+\r
+ @retval EFI_SUCCESS All outstanding data was written to the device\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcFlushBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This\r
+ );\r
+\r
+/**\r
+ Reset the Block Device.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
+ not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcResetEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ );\r
+\r
+/**\r
+ Read BufferSize bytes from Lba into Buffer.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] MediaId Id of the media, changes every time the media is replaced.\r
+ @param[in] Lba The starting Logical Block Address to read from.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[out] Buffer A pointer to the destination buffer for the data. The caller is\r
+ responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+ @retval EFI_SUCCESS The read request was queued if Event is not NULL.\r
+ The data was read correctly from the device if\r
+ the Event is NULL.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing\r
+ the read.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r
+ intrinsic block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
+ of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcReadBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Write BufferSize bytes from Lba into Buffer.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] MediaId The media ID that the write request is for.\r
+ @param[in] Lba The starting logical block address to be written. The\r
+ caller is responsible for writing to only legitimate\r
+ locations.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[in] Buffer A pointer to the source buffer for the data.\r
+\r
+ @retval EFI_SUCCESS The data was written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device can not be written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcWriteBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Flush the Block Device.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+\r
+ @retval EFI_SUCCESS All outstanding data was written to the device\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcFlushBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
+ );\r
+\r
+/**\r
+ Send a security protocol command to a device that receives data and/or the result\r
+ of one or more commands sent by SendData.\r
+\r
+ The ReceiveData function sends a security protocol command to the given MediaId.\r
+ The security protocol command sent is defined by SecurityProtocolId and contains\r
+ the security protocol specific data SecurityProtocolSpecificData. The function\r
+ returns the data from the security protocol command in PayloadBuffer.\r
+\r
+ For devices supporting the SCSI command set, the security protocol command is sent\r
+ using the SECURITY PROTOCOL IN command defined in SPC-4.\r
+\r
+ For devices supporting the ATA command set, the security protocol command is sent\r
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize\r
+ is non-zero.\r
+\r
+ If the PayloadBufferSize is zero, the security protocol command is sent using the\r
+ Trusted Non-Data command defined in ATA8-ACS.\r
+\r
+ If PayloadBufferSize is too small to store the available data from the security\r
+ protocol command, the function shall copy PayloadBufferSize bytes into the\r
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.\r
+\r
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,\r
+ the function shall return EFI_INVALID_PARAMETER.\r
+\r
+ If the given MediaId does not support security protocol commands, the function shall\r
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns\r
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,\r
+ the function returns EFI_MEDIA_CHANGED.\r
+\r
+ If the security protocol fails to complete within the Timeout period, the function\r
+ shall return EFI_TIMEOUT.\r
+\r
+ If the security protocol command completes without an error, the function shall\r
+ return EFI_SUCCESS. If the security protocol command completes with an error, the\r
+ function shall return EFI_DEVICE_ERROR.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] MediaId ID of the medium to receive data from.\r
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution\r
+ of the security protocol command. A Timeout value of 0\r
+ means that this function will wait indefinitely for the\r
+ security protocol command to execute. If Timeout is greater\r
+ than zero, then this function will return EFI_TIMEOUT\r
+ if the time required to execute the receive data command\r
+ is greater than Timeout.\r
+ @param[in] SecurityProtocolId The value of the "Security Protocol" parameter of\r
+ the security protocol command to be sent.\r
+ @param[in] SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
+ of the security protocol command to be sent.\r
+ @param[in] PayloadBufferSize Size in bytes of the payload data buffer.\r
+ @param[out] PayloadBuffer A pointer to a destination buffer to store the security\r
+ protocol command specific payload data for the security\r
+ protocol command. The caller is responsible for having\r
+ either implicit or explicit ownership of the buffer.\r
+ @param[out] PayloadTransferSize A pointer to a buffer to store the size in bytes of the\r
+ data written to the payload data buffer.\r
+ @param[in] IsRead Indicates it is a read or write operation.\r
+\r
+ @retval EFI_SUCCESS The security protocol command completed successfully.\r
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available\r
+ data from the device. The PayloadBuffer contains the truncated data.\r
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.\r
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and\r
+ PayloadBufferSize is non-zero.\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security\r
+ protocol command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcSecurityProtocolInOut (\r
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN UINT64 Timeout,\r
+ IN UINT8 SecurityProtocolId,\r
+ IN UINT16 SecurityProtocolSpecificData,\r
+ IN UINTN PayloadBufferSize,\r
+ OUT VOID *PayloadBuffer,\r
+ OUT UINTN *PayloadTransferSize,\r
+ IN BOOLEAN IsRead\r
+ );\r
+\r
+/**\r
+ Send a security protocol command to a device that receives data and/or the result\r
+ of one or more commands sent by SendData.\r
+\r
+ The ReceiveData function sends a security protocol command to the given MediaId.\r
+ The security protocol command sent is defined by SecurityProtocolId and contains\r
+ the security protocol specific data SecurityProtocolSpecificData. The function\r
+ returns the data from the security protocol command in PayloadBuffer.\r
+\r
+ For devices supporting the SCSI command set, the security protocol command is sent\r
+ using the SECURITY PROTOCOL IN command defined in SPC-4.\r
+\r
+ For devices supporting the ATA command set, the security protocol command is sent\r
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize\r
+ is non-zero.\r
+\r
+ If the PayloadBufferSize is zero, the security protocol command is sent using the\r
+ Trusted Non-Data command defined in ATA8-ACS.\r
+\r
+ If PayloadBufferSize is too small to store the available data from the security\r
+ protocol command, the function shall copy PayloadBufferSize bytes into the\r
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.\r
+\r
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,\r
+ the function shall return EFI_INVALID_PARAMETER.\r
+\r
+ If the given MediaId does not support security protocol commands, the function shall\r
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns\r
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,\r
+ the function returns EFI_MEDIA_CHANGED.\r
+\r
+ If the security protocol fails to complete within the Timeout period, the function\r
+ shall return EFI_TIMEOUT.\r
+\r
+ If the security protocol command completes without an error, the function shall\r
+ return EFI_SUCCESS. If the security protocol command completes with an error, the\r
+ function shall return EFI_DEVICE_ERROR.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId ID of the medium to receive data from.\r
+ @param Timeout The timeout, in 100ns units, to use for the execution\r
+ of the security protocol command. A Timeout value of 0\r
+ means that this function will wait indefinitely for the\r
+ security protocol command to execute. If Timeout is greater\r
+ than zero, then this function will return EFI_TIMEOUT\r
+ if the time required to execute the receive data command\r
+ is greater than Timeout.\r
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of\r
+ the security protocol command to be sent.\r
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
+ of the security protocol command to be sent.\r
+ @param PayloadBufferSize Size in bytes of the payload data buffer.\r
+ @param PayloadBuffer A pointer to a destination buffer to store the security\r
+ protocol command specific payload data for the security\r
+ protocol command. The caller is responsible for having\r
+ either implicit or explicit ownership of the buffer.\r
+ @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the\r
+ data written to the payload data buffer.\r
+\r
+ @retval EFI_SUCCESS The security protocol command completed successfully.\r
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available\r
+ data from the device. The PayloadBuffer contains the truncated data.\r
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.\r
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and\r
+ PayloadBufferSize is non-zero.\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security\r
+ protocol command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcSecurityProtocolIn (\r
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN UINT64 Timeout,\r
+ IN UINT8 SecurityProtocolId,\r
+ IN UINT16 SecurityProtocolSpecificData,\r
+ IN UINTN PayloadBufferSize,\r
+ OUT VOID *PayloadBuffer,\r
+ OUT UINTN *PayloadTransferSize\r
+ );\r
+\r
+/**\r
+ Send a security protocol command to a device.\r
+\r
+ The SendData function sends a security protocol command containing the payload\r
+ PayloadBuffer to the given MediaId. The security protocol command sent is\r
+ defined by SecurityProtocolId and contains the security protocol specific data\r
+ SecurityProtocolSpecificData. If the underlying protocol command requires a\r
+ specific padding for the command payload, the SendData function shall add padding\r
+ bytes to the command payload to satisfy the padding requirements.\r
+\r
+ For devices supporting the SCSI command set, the security protocol command is sent\r
+ using the SECURITY PROTOCOL OUT command defined in SPC-4.\r
+\r
+ For devices supporting the ATA command set, the security protocol command is sent\r
+ using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize\r
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command is\r
+ sent using the Trusted Non-Data command defined in ATA8-ACS.\r
+\r
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall\r
+ return EFI_INVALID_PARAMETER.\r
+\r
+ If the given MediaId does not support security protocol commands, the function\r
+ shall return EFI_UNSUPPORTED. If there is no media in the device, the function\r
+ returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the\r
+ device, the function returns EFI_MEDIA_CHANGED.\r
+\r
+ If the security protocol fails to complete within the Timeout period, the function\r
+ shall return EFI_TIMEOUT.\r
+\r
+ If the security protocol command completes without an error, the function shall return\r
+ EFI_SUCCESS. If the security protocol command completes with an error, the function\r
+ shall return EFI_DEVICE_ERROR.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId ID of the medium to receive data from.\r
+ @param Timeout The timeout, in 100ns units, to use for the execution\r
+ of the security protocol command. A Timeout value of 0\r
+ means that this function will wait indefinitely for the\r
+ security protocol command to execute. If Timeout is greater\r
+ than zero, then this function will return EFI_TIMEOUT\r
+ if the time required to execute the receive data command\r
+ is greater than Timeout.\r
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of\r
+ the security protocol command to be sent.\r
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
+ of the security protocol command to be sent.\r
+ @param PayloadBufferSize Size in bytes of the payload data buffer.\r
+ @param PayloadBuffer A pointer to a destination buffer to store the security\r
+ protocol command specific payload data for the security\r
+ protocol command.\r
+\r
+ @retval EFI_SUCCESS The security protocol command completed successfully.\r
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.\r
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security\r
+ protocol command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcSecurityProtocolOut (\r
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN UINT64 Timeout,\r
+ IN UINT8 SecurityProtocolId,\r
+ IN UINT16 SecurityProtocolSpecificData,\r
+ IN UINTN PayloadBufferSize,\r
+ IN VOID *PayloadBuffer\r
+ );\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+ The EmmcDxe driver is used to manage the EMMC device.\r
+\r
+ It produces BlockIo, BlockIo2 and StorageSecurity protocols to allow upper layer\r
+ access the EMMC device.\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "EmmcDxe.h"\r
+\r
+//\r
+// EmmcDxe Driver Binding Protocol Instance\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gEmmcDxeDriverBinding = {\r
+ EmmcDxeDriverBindingSupported,\r
+ EmmcDxeDriverBindingStart,\r
+ EmmcDxeDriverBindingStop,\r
+ 0x10,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+//\r
+// Template for Emmc Partitions.\r
+//\r
+EMMC_PARTITION mEmmcPartitionTemplate = {\r
+ EMMC_PARTITION_SIGNATURE, // Signature\r
+ FALSE, // Enable\r
+ EmmcPartitionUnknown, // PartitionType\r
+ NULL, // Handle\r
+ NULL, // DevicePath\r
+ { // BlockIo\r
+ EFI_BLOCK_IO_PROTOCOL_REVISION,\r
+ NULL,\r
+ EmmcReset,\r
+ EmmcReadBlocks,\r
+ EmmcWriteBlocks,\r
+ EmmcFlushBlocks\r
+ },\r
+ { // BlockIo2\r
+ NULL,\r
+ EmmcResetEx,\r
+ EmmcReadBlocksEx,\r
+ EmmcWriteBlocksEx,\r
+ EmmcFlushBlocksEx\r
+ },\r
+ { // BlockMedia\r
+ 0, // MediaId\r
+ FALSE, // RemovableMedia\r
+ TRUE, // MediaPresent\r
+ FALSE, // LogicPartition\r
+ FALSE, // ReadOnly\r
+ FALSE, // WritingCache\r
+ 0x200, // BlockSize\r
+ 0, // IoAlign\r
+ 0 // LastBlock\r
+ },\r
+ { // StorageSecurity\r
+ EmmcSecurityProtocolIn,\r
+ EmmcSecurityProtocolOut\r
+ },\r
+ {\r
+ NULL,\r
+ NULL\r
+ },\r
+ NULL // Device\r
+};\r
+\r
+/**\r
+ Decode and print EMMC CSD Register content.\r
+\r
+ @param[in] Csd Pointer to EMMC_CSD data structure.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully\r
+**/\r
+EFI_STATUS\r
+DumpCsd (\r
+ IN EMMC_CSD *Csd\r
+ )\r
+{\r
+ DEBUG((DEBUG_INFO, "== Dump Emmc Csd Register==\n"));\r
+ DEBUG((DEBUG_INFO, " CSD structure 0x%x\n", Csd->CsdStructure));\r
+ DEBUG((DEBUG_INFO, " System specification version 0x%x\n", Csd->SpecVers));\r
+ DEBUG((DEBUG_INFO, " Data read access-time 1 0x%x\n", Csd->Taac));\r
+ DEBUG((DEBUG_INFO, " Data read access-time 2 0x%x\n", Csd->Nsac));\r
+ DEBUG((DEBUG_INFO, " Max. bus clock frequency 0x%x\n", Csd->TranSpeed));\r
+ DEBUG((DEBUG_INFO, " Device command classes 0x%x\n", Csd->Ccc));\r
+ DEBUG((DEBUG_INFO, " Max. read data block length 0x%x\n", Csd->ReadBlLen));\r
+ DEBUG((DEBUG_INFO, " Partial blocks for read allowed 0x%x\n", Csd->ReadBlPartial));\r
+ DEBUG((DEBUG_INFO, " Write block misalignment 0x%x\n", Csd->WriteBlkMisalign));\r
+ DEBUG((DEBUG_INFO, " Read block misalignment 0x%x\n", Csd->ReadBlkMisalign));\r
+ DEBUG((DEBUG_INFO, " DSR implemented 0x%x\n", Csd->DsrImp));\r
+ DEBUG((DEBUG_INFO, " Device size 0x%x\n", Csd->CSizeLow | (Csd->CSizeHigh << 2)));\r
+ DEBUG((DEBUG_INFO, " Max. read current @ VDD min 0x%x\n", Csd->VddRCurrMin));\r
+ DEBUG((DEBUG_INFO, " Max. read current @ VDD max 0x%x\n", Csd->VddRCurrMax));\r
+ DEBUG((DEBUG_INFO, " Max. write current @ VDD min 0x%x\n", Csd->VddWCurrMin));\r
+ DEBUG((DEBUG_INFO, " Max. write current @ VDD max 0x%x\n", Csd->VddWCurrMax));\r
+ DEBUG((DEBUG_INFO, " Device size multiplier 0x%x\n", Csd->CSizeMult));\r
+ DEBUG((DEBUG_INFO, " Erase group size 0x%x\n", Csd->EraseGrpSize));\r
+ DEBUG((DEBUG_INFO, " Erase group size multiplier 0x%x\n", Csd->EraseGrpMult));\r
+ DEBUG((DEBUG_INFO, " Write protect group size 0x%x\n", Csd->WpGrpSize));\r
+ DEBUG((DEBUG_INFO, " Write protect group enable 0x%x\n", Csd->WpGrpEnable));\r
+ DEBUG((DEBUG_INFO, " Manufacturer default ECC 0x%x\n", Csd->DefaultEcc));\r
+ DEBUG((DEBUG_INFO, " Write speed factor 0x%x\n", Csd->R2WFactor));\r
+ DEBUG((DEBUG_INFO, " Max. write data block length 0x%x\n", Csd->WriteBlLen));\r
+ DEBUG((DEBUG_INFO, " Partial blocks for write allowed 0x%x\n", Csd->WriteBlPartial));\r
+ DEBUG((DEBUG_INFO, " Content protection application 0x%x\n", Csd->ContentProtApp));\r
+ DEBUG((DEBUG_INFO, " File format group 0x%x\n", Csd->FileFormatGrp));\r
+ DEBUG((DEBUG_INFO, " Copy flag (OTP) 0x%x\n", Csd->Copy));\r
+ DEBUG((DEBUG_INFO, " Permanent write protection 0x%x\n", Csd->PermWriteProtect));\r
+ DEBUG((DEBUG_INFO, " Temporary write protection 0x%x\n", Csd->TmpWriteProtect));\r
+ DEBUG((DEBUG_INFO, " File format 0x%x\n", Csd->FileFormat));\r
+ DEBUG((DEBUG_INFO, " ECC code 0x%x\n", Csd->Ecc));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Decode and print EMMC EXT_CSD Register content.\r
+\r
+ @param[in] ExtCsd Pointer to the EMMC_EXT_CSD data structure.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully\r
+**/\r
+EFI_STATUS\r
+DumpExtCsd (\r
+ IN EMMC_EXT_CSD *ExtCsd\r
+ )\r
+{\r
+ DEBUG((DEBUG_INFO, "==Dump Emmc ExtCsd Register==\n"));\r
+ DEBUG((DEBUG_INFO, " Supported Command Sets 0x%x\n", ExtCsd->CmdSet));\r
+ DEBUG((DEBUG_INFO, " HPI features 0x%x\n", ExtCsd->HpiFeatures));\r
+ DEBUG((DEBUG_INFO, " Background operations support 0x%x\n", ExtCsd->BkOpsSupport));\r
+ DEBUG((DEBUG_INFO, " Background operations status 0x%x\n", ExtCsd->BkopsStatus));\r
+ DEBUG((DEBUG_INFO, " Number of correctly programmed sectors 0x%x\n", *((UINT32*)&ExtCsd->CorrectlyPrgSectorsNum[0])));\r
+ DEBUG((DEBUG_INFO, " Initialization time after partitioning 0x%x\n", ExtCsd->IniTimeoutAp));\r
+ DEBUG((DEBUG_INFO, " TRIM Multiplier 0x%x\n", ExtCsd->TrimMult));\r
+ DEBUG((DEBUG_INFO, " Secure Feature support 0x%x\n", ExtCsd->SecFeatureSupport));\r
+ DEBUG((DEBUG_INFO, " Secure Erase Multiplier 0x%x\n", ExtCsd->SecEraseMult));\r
+ DEBUG((DEBUG_INFO, " Secure TRIM Multiplier 0x%x\n", ExtCsd->SecTrimMult));\r
+ DEBUG((DEBUG_INFO, " Boot information 0x%x\n", ExtCsd->BootInfo));\r
+ DEBUG((DEBUG_INFO, " Boot partition size 0x%x\n", ExtCsd->BootSizeMult));\r
+ DEBUG((DEBUG_INFO, " Access size 0x%x\n", ExtCsd->AccSize));\r
+ DEBUG((DEBUG_INFO, " High-capacity erase unit size 0x%x\n", ExtCsd->HcEraseGrpSize));\r
+ DEBUG((DEBUG_INFO, " High-capacity erase timeout 0x%x\n", ExtCsd->EraseTimeoutMult));\r
+ DEBUG((DEBUG_INFO, " Reliable write sector count 0x%x\n", ExtCsd->RelWrSecC));\r
+ DEBUG((DEBUG_INFO, " High-capacity write protect group size 0x%x\n", ExtCsd->HcWpGrpSize));\r
+ DEBUG((DEBUG_INFO, " Sleep/awake timeout 0x%x\n", ExtCsd->SATimeout));\r
+ DEBUG((DEBUG_INFO, " Sector Count 0x%x\n", *((UINT32*)&ExtCsd->SecCount[0])));\r
+ DEBUG((DEBUG_INFO, " Partition switching timing 0x%x\n", ExtCsd->PartitionSwitchTime));\r
+ DEBUG((DEBUG_INFO, " Out-of-interrupt busy timing 0x%x\n", ExtCsd->OutOfInterruptTime));\r
+ DEBUG((DEBUG_INFO, " I/O Driver Strength 0x%x\n", ExtCsd->DriverStrength));\r
+ DEBUG((DEBUG_INFO, " Device type 0x%x\n", ExtCsd->DeviceType));\r
+ DEBUG((DEBUG_INFO, " CSD STRUCTURE 0x%x\n", ExtCsd->CsdStructure));\r
+ DEBUG((DEBUG_INFO, " Extended CSD revision 0x%x\n", ExtCsd->ExtCsdRev));\r
+ DEBUG((DEBUG_INFO, " Command set 0x%x\n", ExtCsd->CmdSet));\r
+ DEBUG((DEBUG_INFO, " Command set revision 0x%x\n", ExtCsd->CmdSetRev));\r
+ DEBUG((DEBUG_INFO, " Power class 0x%x\n", ExtCsd->PowerClass));\r
+ DEBUG((DEBUG_INFO, " High-speed interface timing 0x%x\n", ExtCsd->HsTiming));\r
+ DEBUG((DEBUG_INFO, " Bus width mode 0x%x\n", ExtCsd->BusWidth));\r
+ DEBUG((DEBUG_INFO, " Erased memory content 0x%x\n", ExtCsd->ErasedMemCont));\r
+ DEBUG((DEBUG_INFO, " Partition configuration 0x%x\n", ExtCsd->PartitionConfig));\r
+ DEBUG((DEBUG_INFO, " Boot config protection 0x%x\n", ExtCsd->BootConfigProt));\r
+ DEBUG((DEBUG_INFO, " Boot bus Conditions 0x%x\n", ExtCsd->BootBusConditions));\r
+ DEBUG((DEBUG_INFO, " High-density erase group definition 0x%x\n", ExtCsd->EraseGroupDef));\r
+ DEBUG((DEBUG_INFO, " Boot write protection status register 0x%x\n", ExtCsd->BootWpStatus));\r
+ DEBUG((DEBUG_INFO, " Boot area write protection register 0x%x\n", ExtCsd->BootWp));\r
+ DEBUG((DEBUG_INFO, " User area write protection register 0x%x\n", ExtCsd->UserWp));\r
+ DEBUG((DEBUG_INFO, " FW configuration 0x%x\n", ExtCsd->FwConfig));\r
+ DEBUG((DEBUG_INFO, " RPMB Size 0x%x\n", ExtCsd->RpmbSizeMult));\r
+ DEBUG((DEBUG_INFO, " H/W reset function 0x%x\n", ExtCsd->RstFunction));\r
+ DEBUG((DEBUG_INFO, " Partitioning Support 0x%x\n", ExtCsd->PartitioningSupport));\r
+ DEBUG((DEBUG_INFO, " Max Enhanced Area Size 0x%02x%02x%02x\n", \\r
+ ExtCsd->MaxEnhSizeMult[2], ExtCsd->MaxEnhSizeMult[1], ExtCsd->MaxEnhSizeMult[0]));\r
+ DEBUG((DEBUG_INFO, " Partitions attribute 0x%x\n", ExtCsd->PartitionsAttribute));\r
+ DEBUG((DEBUG_INFO, " Partitioning Setting 0x%x\n", ExtCsd->PartitionSettingCompleted));\r
+ DEBUG((DEBUG_INFO, " General Purpose Partition 1 Size 0x%02x%02x%02x\n", \\r
+ ExtCsd->GpSizeMult[2], ExtCsd->GpSizeMult[1], ExtCsd->GpSizeMult[0]));\r
+ DEBUG((DEBUG_INFO, " General Purpose Partition 2 Size 0x%02x%02x%02x\n", \\r
+ ExtCsd->GpSizeMult[5], ExtCsd->GpSizeMult[4], ExtCsd->GpSizeMult[3]));\r
+ DEBUG((DEBUG_INFO, " General Purpose Partition 3 Size 0x%02x%02x%02x\n", \\r
+ ExtCsd->GpSizeMult[8], ExtCsd->GpSizeMult[7], ExtCsd->GpSizeMult[6]));\r
+ DEBUG((DEBUG_INFO, " General Purpose Partition 4 Size 0x%02x%02x%02x\n", \\r
+ ExtCsd->GpSizeMult[11], ExtCsd->GpSizeMult[10], ExtCsd->GpSizeMult[9]));\r
+ DEBUG((DEBUG_INFO, " Enhanced User Data Area Size 0x%02x%02x%02x\n", \\r
+ ExtCsd->EnhSizeMult[2], ExtCsd->EnhSizeMult[1], ExtCsd->EnhSizeMult[0]));\r
+ DEBUG((DEBUG_INFO, " Enhanced User Data Start Address 0x%x\n", *((UINT32*)&ExtCsd->EnhStartAddr[0])));\r
+ DEBUG((DEBUG_INFO, " Bad Block Management mode 0x%x\n", ExtCsd->SecBadBlkMgmnt));\r
+ DEBUG((DEBUG_INFO, " Native sector size 0x%x\n", ExtCsd->NativeSectorSize));\r
+ DEBUG((DEBUG_INFO, " Sector size emulation 0x%x\n", ExtCsd->UseNativeSector));\r
+ DEBUG((DEBUG_INFO, " Sector size 0x%x\n", ExtCsd->DataSectorSize));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get EMMC device model name.\r
+\r
+ @param[in, out] Device The pointer to the EMMC_DEVICE data structure.\r
+ @param[in] Cid Pointer to EMMC_CID data structure.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully\r
+\r
+**/\r
+EFI_STATUS\r
+GetEmmcModelName (\r
+ IN OUT EMMC_DEVICE *Device,\r
+ IN EMMC_CID *Cid\r
+ )\r
+{\r
+ CHAR8 String[EMMC_MODEL_NAME_MAX_LEN];\r
+\r
+ ZeroMem (String, sizeof (String));\r
+ CopyMem (String, &Cid->OemId, sizeof (Cid->OemId));\r
+ String[sizeof (Cid->OemId)] = ' ';\r
+ CopyMem (String + sizeof (Cid->OemId) + 1, Cid->ProductName, sizeof (Cid->ProductName));\r
+ String[sizeof (Cid->OemId) + sizeof (Cid->ProductName)] = ' ';\r
+ CopyMem (String + sizeof (Cid->OemId) + sizeof (Cid->ProductName) + 1, Cid->ProductSerialNumber, sizeof (Cid->ProductSerialNumber));\r
+\r
+ AsciiStrToUnicodeStr (String, Device->ModelName);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Discover all partitions in the EMMC device.\r
+\r
+ @param[in] Device The pointer to the EMMC_DEVICE data structure.\r
+\r
+ @retval EFI_SUCCESS All the partitions in the device are successfully enumerated.\r
+ @return Others Some error occurs when enumerating the partitions.\r
+\r
+**/\r
+EFI_STATUS\r
+DiscoverAllPartitions (\r
+ IN EMMC_DEVICE *Device\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EMMC_PARTITION *Partition;\r
+ EMMC_CSD *Csd;\r
+ EMMC_CID *Cid;\r
+ EMMC_EXT_CSD *ExtCsd;\r
+ UINT8 Slot;\r
+ UINT64 Capacity;\r
+ UINT32 DevStatus;\r
+ UINT8 Index;\r
+ UINT32 SecCount;\r
+ UINT32 GpSizeMult;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+ Slot = Device->Slot;\r
+\r
+ Status = EmmcSendStatus (Device, Slot + 1, &DevStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Deselect the device to force it enter stby mode before getting CSD\r
+ // register content.\r
+ // Note here we don't judge return status as some EMMC devices return\r
+ // error but the state has been stby.\r
+ //\r
+ EmmcSelect (Device, 0);\r
+\r
+ Status = EmmcSendStatus (Device, Slot + 1, &DevStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Csd = &Device->Csd;\r
+ Status = EmmcGetCsd (Device, Slot + 1, Csd);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ DumpCsd (Csd);\r
+\r
+ if ((Csd->CSizeLow | Csd->CSizeHigh << 2) == 0xFFF) {\r
+ Device->SectorAddressing = TRUE;\r
+ } else {\r
+ Device->SectorAddressing = FALSE;\r
+ }\r
+\r
+ Cid = &Device->Cid;\r
+ Status = EmmcGetCid (Device, Slot + 1, Cid);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = EmmcSelect (Device, Slot + 1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ ExtCsd = &Device->ExtCsd;\r
+ Status = EmmcGetExtCsd (Device, ExtCsd);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ DumpExtCsd (ExtCsd);\r
+\r
+ if (ExtCsd->ExtCsdRev < 5) {\r
+ DEBUG ((EFI_D_ERROR, "The EMMC device version is too low, we don't support!!!\n"));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if ((ExtCsd->PartitioningSupport & BIT0) != BIT0) {\r
+ DEBUG ((EFI_D_ERROR, "The EMMC device doesn't support Partition Feature!!!\n"));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ for (Index = 0; Index < EMMC_MAX_PARTITIONS; Index++) {\r
+ Partition = &Device->Partition[Index];\r
+ CopyMem (Partition, &mEmmcPartitionTemplate, sizeof (EMMC_PARTITION));\r
+ Partition->Device = Device;\r
+ InitializeListHead (&Partition->Queue);\r
+ Partition->BlockIo.Media = &Partition->BlockMedia;\r
+ Partition->BlockIo2.Media = &Partition->BlockMedia;\r
+ Partition->PartitionType = Index;\r
+ Partition->BlockMedia.IoAlign = Device->Private->PassThru->IoAlign;\r
+ Partition->BlockMedia.BlockSize = 0x200;\r
+ Partition->BlockMedia.LastBlock = 0x00;\r
+ Partition->BlockMedia.RemovableMedia = FALSE;\r
+ Partition->BlockMedia.MediaPresent = TRUE;\r
+ Partition->BlockMedia.LogicalPartition = FALSE;\r
+\r
+ switch (Index) {\r
+ case EmmcPartitionUserData:\r
+ SecCount = *(UINT32*)&ExtCsd->SecCount;\r
+ Capacity = MultU64x32 ((UINT64) SecCount, 0x200);\r
+ break;\r
+ case EmmcPartitionBoot1:\r
+ case EmmcPartitionBoot2:\r
+ Capacity = ExtCsd->BootSizeMult * SIZE_128KB;\r
+ break;\r
+ case EmmcPartitionRPMB:\r
+ Capacity = ExtCsd->RpmbSizeMult * SIZE_128KB;\r
+ break;\r
+ case EmmcPartitionGP1:\r
+ GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[0] | (ExtCsd->GpSizeMult[1] << 8) | (ExtCsd->GpSizeMult[2] << 16));\r
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
+ break;\r
+ case EmmcPartitionGP2:\r
+ GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[3] | (ExtCsd->GpSizeMult[4] << 8) | (ExtCsd->GpSizeMult[5] << 16));\r
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
+ break;\r
+ case EmmcPartitionGP3:\r
+ GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[6] | (ExtCsd->GpSizeMult[7] << 8) | (ExtCsd->GpSizeMult[8] << 16));\r
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
+ break;\r
+ case EmmcPartitionGP4:\r
+ GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[9] | (ExtCsd->GpSizeMult[10] << 8) | (ExtCsd->GpSizeMult[11] << 16));\r
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Capacity != 0) {\r
+ Partition->Enable = TRUE;\r
+ Partition->BlockMedia.LastBlock = DivU64x32 (Capacity, Partition->BlockMedia.BlockSize) - 1;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Install BlkIo, BlkIo2 and Ssp protocols for the specified partition in the EMMC device.\r
+\r
+ @param[in] Device The pointer to the EMMC_DEVICE data structure.\r
+ @param[in] Index The index of the partition.\r
+\r
+ @retval EFI_SUCCESS The protocols are installed successfully.\r
+ @retval Others Some error occurs when installing the protocols.\r
+\r
+**/\r
+EFI_STATUS\r
+InstallProtocolOnPartition (\r
+ IN EMMC_DEVICE *Device,\r
+ IN UINT8 Index\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_PARTITION *Partition;\r
+ CONTROLLER_DEVICE_PATH ControlNode;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;\r
+ EFI_HANDLE DeviceHandle;\r
+\r
+ //\r
+ // Build device path\r
+ //\r
+ ParentDevicePath = Device->DevicePath;\r
+\r
+ ControlNode.Header.Type = HARDWARE_DEVICE_PATH;\r
+ ControlNode.Header.SubType = HW_CONTROLLER_DP;\r
+ SetDevicePathNodeLength (&ControlNode.Header, sizeof (CONTROLLER_DEVICE_PATH));\r
+ ControlNode.ControllerNumber = Index;\r
+\r
+ DevicePath = AppendDevicePathNode (ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*)&ControlNode);\r
+ if (DevicePath == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ DeviceHandle = NULL;\r
+ RemainingDevicePath = DevicePath;\r
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);\r
+ if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {\r
+ Status = EFI_ALREADY_STARTED;\r
+ goto Error;\r
+ }\r
+\r
+ Partition = &Device->Partition[Index];\r
+ Partition->DevicePath = DevicePath;\r
+ if (Partition->Enable) {\r
+ //\r
+ // Install BlkIo/BlkIo2/Ssp for the specified partition\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Partition->Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ Partition->DevicePath,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &Partition->BlockIo,\r
+ &gEfiBlockIo2ProtocolGuid,\r
+ &Partition->BlockIo2,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+\r
+ if (((Partition->PartitionType == EmmcPartitionUserData) ||\r
+ (Partition->PartitionType == EmmcPartitionBoot1) ||\r
+ (Partition->PartitionType == EmmcPartitionBoot2)) &&\r
+ ((Device->Csd.Ccc & BIT10) != 0)) {\r
+ Status = gBS->InstallProtocolInterface (\r
+ &Partition->Handle,\r
+ &gEfiStorageSecurityCommandProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &Partition->StorageSecurity\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ &Partition->Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ Partition->DevicePath,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &Partition->BlockIo,\r
+ &gEfiBlockIo2ProtocolGuid,\r
+ &Partition->BlockIo2,\r
+ NULL\r
+ );\r
+ goto Error;\r
+ }\r
+ }\r
+\r
+ gBS->OpenProtocol (\r
+ Device->Private->Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ (VOID **) &(Device->Private->PassThru),\r
+ Device->Private->DriverBindingHandle,\r
+ Partition->Handle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ } else {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+Error:\r
+ if (EFI_ERROR (Status) && (DevicePath != NULL)) {\r
+ FreePool (DevicePath);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Scan EMMC Bus to discover the device.\r
+\r
+ @param[in] Private The EMMC driver private data structure.\r
+ @param[in] Slot The slot number to check device present.\r
+\r
+ @retval EFI_SUCCESS Successfully to discover the device and attach\r
+ SdMmcIoProtocol to it.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
+ of resources.\r
+ @retval EFI_ALREADY_STARTED The device was discovered before.\r
+ @retval Others Fail to discover the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DiscoverEmmcDevice (\r
+ IN EMMC_DRIVER_PRIVATE_DATA *Private,\r
+ IN UINT8 Slot,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMMC_DEVICE *Device;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *RemainingEmmcDevPath;\r
+ EFI_DEV_PATH *Node;\r
+ EFI_HANDLE DeviceHandle;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ UINT8 Index;\r
+\r
+ Device = NULL;\r
+ DevicePath = NULL;\r
+ NewDevicePath = NULL;\r
+ RemainingDevicePath = NULL;\r
+ PassThru = Private->PassThru;\r
+ Device = &Private->Device[Slot];\r
+\r
+ //\r
+ // Build Device Path to check if the EMMC device present at the slot.\r
+ //\r
+ Status = PassThru->BuildDevicePath (\r
+ PassThru,\r
+ Slot,\r
+ &DevicePath\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (DevicePath->SubType != MSG_EMMC_DP) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Error;\r
+ }\r
+\r
+ NewDevicePath = AppendDevicePathNode (\r
+ Private->ParentDevicePath,\r
+ DevicePath\r
+ );\r
+ if (NewDevicePath == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ DeviceHandle = NULL;\r
+ RemainingEmmcDevPath = NewDevicePath;\r
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingEmmcDevPath, &DeviceHandle);\r
+ //\r
+ // The device path to the EMMC device doesn't exist. It means the corresponding device private data hasn't been initialized.\r
+ //\r
+ if (EFI_ERROR (Status) || (DeviceHandle == NULL) || !IsDevicePathEnd (RemainingEmmcDevPath)) {\r
+ Device->DevicePath = NewDevicePath;\r
+ Device->Slot = Slot;\r
+ Device->Private = Private;\r
+ //\r
+ // Expose user area in the Sd memory card to upper layer.\r
+ //\r
+ Status = DiscoverAllPartitions (Device);\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool (NewDevicePath);\r
+ goto Error;\r
+ }\r
+\r
+ Status = gBS->InstallProtocolInterface (\r
+ &Device->Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ Device->DevicePath\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool (NewDevicePath);\r
+ goto Error;\r
+ }\r
+\r
+ Device->ControllerNameTable = NULL;\r
+ GetEmmcModelName (Device, &Device->Cid);\r
+ AddUnicodeString2 (\r
+ "eng",\r
+ gEmmcDxeComponentName.SupportedLanguages,\r
+ &Device->ControllerNameTable,\r
+ Device->ModelName,\r
+ TRUE\r
+ );\r
+ AddUnicodeString2 (\r
+ "en",\r
+ gEmmcDxeComponentName.SupportedLanguages,\r
+ &Device->ControllerNameTable,\r
+ Device->ModelName,\r
+ FALSE\r
+ );\r
+ }\r
+\r
+ if (RemainingDevicePath == NULL) {\r
+ //\r
+ // Expose all partitions in the Emmc device to upper layer.\r
+ //\r
+ for (Index = 0; Index < EMMC_MAX_PARTITIONS; Index++) {\r
+ InstallProtocolOnPartition (Device, Index);\r
+ }\r
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
+ //\r
+ // Enumerate the specified partition\r
+ //\r
+ Node = (EFI_DEV_PATH *) RemainingDevicePath;\r
+ if ((DevicePathType (&Node->DevPath) != HARDWARE_DEVICE_PATH) ||\r
+ (DevicePathSubType (&Node->DevPath) != HW_CONTROLLER_DP) ||\r
+ (DevicePathNodeLength (&Node->DevPath) != sizeof (CONTROLLER_DEVICE_PATH))) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Error;\r
+ }\r
+\r
+ Index = (UINT8)Node->Controller.ControllerNumber;\r
+ if (Index >= EMMC_MAX_PARTITIONS) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Error;\r
+ }\r
+\r
+ Status = InstallProtocolOnPartition (Device, Index);\r
+ }\r
+\r
+Error:\r
+ FreePool (DevicePath);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Tests to see if this driver supports a given controller. If a child device is provided,\r
+ it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+ This function checks to see if the driver specified by This supports the device specified by\r
+ ControllerHandle. Drivers will typically use the device path attached to\r
+ ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+ ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+ may be called many times during platform initialization. In order to reduce boot times, the tests\r
+ performed by this function must be very small, and take as little time as possible to execute. This\r
+ function must not change the state of any hardware devices, and this function must be aware that the\r
+ device specified by ControllerHandle may already be managed by the same driver or a\r
+ different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+ to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to test. This handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For bus drivers, if this parameter is not NULL, then\r
+ the bus driver must determine if the bus controller specified\r
+ by ControllerHandle and the child controller specified\r
+ by RemainingDevicePath are both supported by this\r
+ bus driver.\r
+\r
+ @retval EFI_SUCCESS The device specified by ControllerHandle and\r
+ RemainingDevicePath is supported by the driver specified by This.\r
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by the driver\r
+ specified by This.\r
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by a different\r
+ driver or an application that requires exclusive access.\r
+ Currently not implemented.\r
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ UINT8 Slot;\r
+\r
+ //\r
+ // Test EFI_SD_MMC_PASS_THRU_PROTOCOL on the controller handle.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ (VOID**) &PassThru,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Test RemainingDevicePath is valid or not.\r
+ //\r
+ if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {\r
+ Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Close the I/O Abstraction(s) used to perform the supported test\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Close the I/O Abstraction(s) used to perform the supported test\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ //\r
+ // Open the EFI Device Path protocol needed to perform the supported test\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &ParentDevicePath,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Starts a device controller or a bus controller.\r
+\r
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+ As a result, much of the error checking on the parameters to Start() has been moved into this\r
+ common boot service. It is legal to call Start() from other locations,\r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE.\r
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+ EFI_DEVICE_PATH_PROTOCOL.\r
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to start. This handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For a bus driver, if this parameter is NULL, then handles\r
+ for all the children of Controller are created by this driver.\r
+ If this parameter is not NULL and the first Device Path Node is\r
+ not the End of Device Path Node, then only the handle for the\r
+ child device specified by the first Device Path Node of\r
+ RemainingDevicePath is created by this driver.\r
+ If the first Device Path Node of RemainingDevicePath is\r
+ the End of Device Path Node, no child handle is created by this\r
+ driver.\r
+\r
+ @retval EFI_SUCCESS The device was started.\r
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval Others The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ EMMC_DRIVER_PRIVATE_DATA *Private;\r
+ UINT8 Slot;\r
+\r
+ Private = NULL;\r
+ PassThru = NULL;\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ (VOID **) &PassThru,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Check EFI_ALREADY_STARTED to reuse the original EMMC_DRIVER_PRIVATE_DATA.\r
+ //\r
+ if (Status != EFI_ALREADY_STARTED) {\r
+ Private = AllocateZeroPool (sizeof (EMMC_DRIVER_PRIVATE_DATA));\r
+ if (Private == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &ParentDevicePath,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ Private->PassThru = PassThru;\r
+ Private->Controller = Controller;\r
+ Private->ParentDevicePath = ParentDevicePath;\r
+ Private->DriverBindingHandle = This->DriverBindingHandle;\r
+\r
+ Status = gBS->InstallProtocolInterface (\r
+ &Controller,\r
+ &gEfiCallerIdGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ Private\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ } else {\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiCallerIdGuid,\r
+ (VOID **) &Private,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ }\r
+\r
+ if (RemainingDevicePath == NULL) {\r
+ Slot = 0xFF;\r
+ while (TRUE) {\r
+ Status = PassThru->GetNextSlot (PassThru, &Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Cannot find more legal slots.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+ }\r
+\r
+ Status = DiscoverEmmcDevice (Private, Slot, NULL);\r
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+ break;\r
+ }\r
+ }\r
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
+ Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = DiscoverEmmcDevice (Private, Slot, NextDevicePathNode (RemainingDevicePath));\r
+ }\r
+ }\r
+\r
+Error:\r
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ if (Private != NULL) {\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ Controller,\r
+ &gEfiCallerIdGuid,\r
+ Private,\r
+ NULL\r
+ );\r
+ FreePool (Private);\r
+ }\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Stops a device controller or a bus controller.\r
+\r
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+ As a result, much of the error checking on the parameters to Stop() has been moved\r
+ into this common boot service. It is legal to call Stop() from other locations,\r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+ same driver's Start() function.\r
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+ Start() function, and the Start() function must have called OpenProtocol() on\r
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must\r
+ support a bus specific I/O protocol for the driver\r
+ to use to stop the device.\r
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+ if NumberOfChildren is 0.\r
+\r
+ @retval EFI_SUCCESS The device was stopped.\r
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN AllChildrenStopped;\r
+ UINTN Index;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EMMC_DRIVER_PRIVATE_DATA *Private;\r
+ EMMC_DEVICE *Device;\r
+ EMMC_PARTITION *Partition;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;\r
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity;\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *NextLink;\r
+ EMMC_REQUEST *Request;\r
+\r
+ BlockIo = NULL;\r
+ BlockIo2 = NULL;\r
+ if (NumberOfChildren == 0) {\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiCallerIdGuid,\r
+ (VOID **) &Private,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ for (Index = 0; Index < EMMC_MAX_DEVICES; Index++) {\r
+ Device = &Private->Device[Index];\r
+ Status = gBS->OpenProtocol (\r
+ Device->Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &DevicePath,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ ASSERT (DevicePath == Device->DevicePath);\r
+ gBS->UninstallProtocolInterface (\r
+ Device->Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ DevicePath\r
+ );\r
+ FreePool (Device->DevicePath);\r
+ }\r
+\r
+ gBS->UninstallProtocolInterface (\r
+ Controller,\r
+ &gEfiCallerIdGuid,\r
+ Private\r
+ );\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ FreePool (Private);\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ AllChildrenStopped = TRUE;\r
+\r
+ for (Index = 0; Index < NumberOfChildren; Index++) {\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandleBuffer[Index],\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlockIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandleBuffer[Index],\r
+ &gEfiBlockIo2ProtocolGuid,\r
+ (VOID **) &BlockIo2,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ AllChildrenStopped = FALSE;\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if (BlockIo != NULL) {\r
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO (BlockIo);\r
+ } else {\r
+ ASSERT (BlockIo2 != NULL);\r
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (BlockIo2);\r
+ }\r
+\r
+ for (Link = GetFirstNode (&Partition->Queue);\r
+ !IsNull (&Partition->Queue, Link);\r
+ Link = NextLink) {\r
+ NextLink = GetNextNode (&Partition->Queue, Link);\r
+\r
+ RemoveEntryList (Link);\r
+ Request = EMMC_REQUEST_FROM_LINK (Link);\r
+\r
+ gBS->CloseEvent (Request->Event);\r
+ Request->Token->TransactionStatus = EFI_ABORTED;\r
+\r
+ if (Request->IsEnd) {\r
+ gBS->SignalEvent (Request->Token->Event);\r
+ }\r
+\r
+ FreePool (Request);\r
+ }\r
+\r
+ //\r
+ // Close the child handle\r
+ //\r
+ Status = gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index]\r
+ );\r
+\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ ChildHandleBuffer[Index],\r
+ &gEfiDevicePathProtocolGuid,\r
+ Partition->DevicePath,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &Partition->BlockIo,\r
+ &gEfiBlockIo2ProtocolGuid,\r
+ &Partition->BlockIo2,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ AllChildrenStopped = FALSE;\r
+ gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ (VOID **)&Partition->Device->Private->PassThru,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index],\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // If Storage Security Command Protocol is installed, then uninstall this protocol.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandleBuffer[Index],\r
+ &gEfiStorageSecurityCommandProtocolGuid,\r
+ (VOID **) &StorageSecurity,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = gBS->UninstallProtocolInterface (\r
+ ChildHandleBuffer[Index],\r
+ &gEfiStorageSecurityCommandProtocolGuid,\r
+ &Partition->StorageSecurity\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ (VOID **) &Partition->Device->Private->PassThru,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index],\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ AllChildrenStopped = FALSE;\r
+ continue;\r
+ }\r
+ }\r
+\r
+ FreePool (Partition->DevicePath);\r
+ }\r
+\r
+ if (!AllChildrenStopped) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ The user Entry Point for module EmmcDxe. The user code starts with this function.\r
+\r
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
+ @param[in] SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The entry point is executed successfully.\r
+ @retval other Some errors occur when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeEmmcDxe (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Install driver model protocol(s).\r
+ //\r
+ Status = EfiLibInstallDriverBindingComponentName2 (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gEmmcDxeDriverBinding,\r
+ ImageHandle,\r
+ &gEmmcDxeComponentName,\r
+ &gEmmcDxeComponentName2\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ Header file for EmmcDxe Driver.\r
+\r
+ This file defines common data structures, macro definitions and some module\r
+ internal function header files.\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EMMC_DXE_H_\r
+#define _EMMC_DXE_H_\r
+\r
+#include <Uefi.h>\r
+#include <IndustryStandard/Emmc.h>\r
+\r
+#include <Protocol/SdMmcPassThru.h>\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/BlockIo2.h>\r
+#include <Protocol/StorageSecurityCommand.h>\r
+\r
+#include <Protocol/DevicePath.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+\r
+#include "EmmcBlockIo.h"\r
+//\r
+// Global Variables\r
+//\r
+extern EFI_DRIVER_BINDING_PROTOCOL gEmmcDxeDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL gEmmcDxeComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL gEmmcDxeComponentName2;\r
+\r
+#define EMMC_PARTITION_SIGNATURE SIGNATURE_32 ('E', 'm', 'm', 'P')\r
+\r
+#define EMMC_PARTITION_DATA_FROM_BLKIO(a) \\r
+ CR(a, EMMC_PARTITION, BlockIo, EMMC_PARTITION_SIGNATURE)\r
+\r
+#define EMMC_PARTITION_DATA_FROM_BLKIO2(a) \\r
+ CR(a, EMMC_PARTITION, BlockIo2, EMMC_PARTITION_SIGNATURE)\r
+\r
+#define EMMC_PARTITION_DATA_FROM_SSP(a) \\r
+ CR(a, EMMC_PARTITION, StorageSecurity, EMMC_PARTITION_SIGNATURE)\r
+\r
+//\r
+// Take 2.5 seconds as generic time out value, 1 microsecond as unit.\r
+//\r
+#define EMMC_GENERIC_TIMEOUT 2500 * 1000\r
+\r
+#define EMMC_REQUEST_SIGNATURE SIGNATURE_32 ('E', 'm', 'R', 'e')\r
+\r
+typedef struct _EMMC_DEVICE EMMC_DEVICE;\r
+typedef struct _EMMC_DRIVER_PRIVATE_DATA EMMC_DRIVER_PRIVATE_DATA;\r
+\r
+//\r
+// Asynchronous I/O request.\r
+//\r
+typedef struct {\r
+ UINT32 Signature;\r
+ LIST_ENTRY Link;\r
+\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ BOOLEAN IsEnd;\r
+\r
+ EFI_BLOCK_IO2_TOKEN *Token;\r
+ EFI_EVENT Event;\r
+} EMMC_REQUEST;\r
+\r
+#define EMMC_REQUEST_FROM_LINK(a) \\r
+ CR(a, EMMC_REQUEST, Link, EMMC_REQUEST_SIGNATURE)\r
+\r
+typedef struct {\r
+ UINT32 Signature;\r
+ BOOLEAN Enable;\r
+ EMMC_PARTITION_TYPE PartitionType;\r
+ EFI_HANDLE Handle;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_BLOCK_IO_PROTOCOL BlockIo;\r
+ EFI_BLOCK_IO2_PROTOCOL BlockIo2;\r
+ EFI_BLOCK_IO_MEDIA BlockMedia;\r
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL StorageSecurity;\r
+\r
+ LIST_ENTRY Queue;\r
+\r
+ EMMC_DEVICE *Device;\r
+} EMMC_PARTITION;\r
+\r
+//\r
+// Up to 6 slots per EMMC PCI host controller\r
+//\r
+#define EMMC_MAX_DEVICES 6\r
+//\r
+// Up to 8 partitions per EMMC device.\r
+//\r
+#define EMMC_MAX_PARTITIONS 8\r
+#define EMMC_MODEL_NAME_MAX_LEN 32\r
+\r
+struct _EMMC_DEVICE {\r
+ EFI_HANDLE Handle;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ UINT8 Slot;\r
+ BOOLEAN SectorAddressing;\r
+\r
+ EMMC_PARTITION Partition[EMMC_MAX_PARTITIONS];\r
+ EMMC_CSD Csd;\r
+ EMMC_CID Cid;\r
+ EMMC_EXT_CSD ExtCsd;\r
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;\r
+ //\r
+ // The model name consists of three fields in CID register\r
+ // 1) OEM/Application ID (2 bytes)\r
+ // 2) Product Name (5 bytes)\r
+ // 3) Product Serial Number (4 bytes)\r
+ // The delimiters of these fields are whitespace.\r
+ //\r
+ CHAR16 ModelName[EMMC_MODEL_NAME_MAX_LEN];\r
+ EMMC_DRIVER_PRIVATE_DATA *Private;\r
+} ;\r
+\r
+//\r
+// EMMC DXE driver private data structure\r
+//\r
+struct _EMMC_DRIVER_PRIVATE_DATA {\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_HANDLE Controller;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ EFI_HANDLE DriverBindingHandle;\r
+\r
+ EMMC_DEVICE Device[EMMC_MAX_DEVICES];\r
+} ;\r
+\r
+/**\r
+ Tests to see if this driver supports a given controller. If a child device is provided,\r
+ it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+ This function checks to see if the driver specified by This supports the device specified by\r
+ ControllerHandle. Drivers will typically use the device path attached to\r
+ ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+ ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+ may be called many times during platform initialization. In order to reduce boot times, the tests\r
+ performed by this function must be very small, and take as little time as possible to execute. This\r
+ function must not change the state of any hardware devices, and this function must be aware that the\r
+ device specified by ControllerHandle may already be managed by the same driver or a\r
+ different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+ to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to test. This handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For bus drivers, if this parameter is not NULL, then\r
+ the bus driver must determine if the bus controller specified\r
+ by ControllerHandle and the child controller specified\r
+ by RemainingDevicePath are both supported by this\r
+ bus driver.\r
+\r
+ @retval EFI_SUCCESS The device specified by ControllerHandle and\r
+ RemainingDevicePath is supported by the driver specified by This.\r
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by the driver\r
+ specified by This.\r
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by a different\r
+ driver or an application that requires exclusive access.\r
+ Currently not implemented.\r
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Starts a device controller or a bus controller.\r
+\r
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+ As a result, much of the error checking on the parameters to Start() has been moved into this\r
+ common boot service. It is legal to call Start() from other locations,\r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE.\r
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+ EFI_DEVICE_PATH_PROTOCOL.\r
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to start. This handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For a bus driver, if this parameter is NULL, then handles\r
+ for all the children of Controller are created by this driver.\r
+ If this parameter is not NULL and the first Device Path Node is\r
+ not the End of Device Path Node, then only the handle for the\r
+ child device specified by the first Device Path Node of\r
+ RemainingDevicePath is created by this driver.\r
+ If the first Device Path Node of RemainingDevicePath is\r
+ the End of Device Path Node, no child handle is created by this\r
+ driver.\r
+\r
+ @retval EFI_SUCCESS The device was started.\r
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval Others The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Stops a device controller or a bus controller.\r
+\r
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+ As a result, much of the error checking on the parameters to Stop() has been moved\r
+ into this common boot service. It is legal to call Stop() from other locations,\r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+ same driver's Start() function.\r
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+ Start() function, and the Start() function must have called OpenProtocol() on\r
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must\r
+ support a bus specific I/O protocol for the driver\r
+ to use to stop the device.\r
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+ if NumberOfChildren is 0.\r
+\r
+ @retval EFI_SUCCESS The device was stopped.\r
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ );\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ );\r
+\r
+/**\r
+ Send command SELECT to the device to select/deselect the device.\r
+\r
+ @param[in] Device A pointer to the EMMC_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSelect (\r
+ IN EMMC_DEVICE *Device,\r
+ IN UINT16 Rca\r
+ );\r
+\r
+/**\r
+ Send command SEND_STATUS to the device to get device status.\r
+\r
+ @param[in] Device A pointer to the EMMC_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+ @param[out] DevStatus The buffer to store the device status.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSendStatus (\r
+ IN EMMC_DEVICE *Device,\r
+ IN UINT16 Rca,\r
+ OUT UINT32 *DevStatus\r
+ );\r
+\r
+/**\r
+ Send command SEND_CSD to the device to get the CSD register data.\r
+\r
+ @param[in] Device A pointer to the EMMC_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+ @param[out] Csd The buffer to store the EMMC_CSD register data.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetCsd (\r
+ IN EMMC_DEVICE *Device,\r
+ IN UINT16 Rca,\r
+ OUT EMMC_CSD *Csd\r
+ );\r
+\r
+/**\r
+ Send command SEND_CID to the device to get the CID register data.\r
+\r
+ @param[in] Device A pointer to the EMMC_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+ @param[out] Csd The buffer to store the EMMC_CSD register data.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetCid (\r
+ IN EMMC_DEVICE *Device,\r
+ IN UINT16 Rca,\r
+ OUT EMMC_CID *Cid\r
+ );\r
+\r
+/**\r
+ Send command SEND_EXT_CSD to the device to get the EXT_CSD register data.\r
+\r
+ @param[in] Device A pointer to the EMMC_DEVICE instance.\r
+ @param[out] ExtCsd The buffer to store the EXT_CSD register data.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetExtCsd (\r
+ IN EMMC_DEVICE *Device,\r
+ OUT EMMC_EXT_CSD *ExtCsd\r
+ );\r
+\r
+#endif\r
+\r
--- /dev/null
+## @file\r
+# EmmcDxe driver is used to manage the EMMC device.\r
+#\r
+# It produces BlockIo, BlockIo2 and StorageSecurity protocols to allow upper layer\r
+# access the EMMC device.\r
+#\r
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = EmmcDxe\r
+ MODULE_UNI_FILE = EmmcDxe.uni\r
+ FILE_GUID = 2145F72F-E6F1-4440-A828-59DC9AAB5F89\r
+ MODULE_TYPE = UEFI_DRIVER\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = InitializeEmmcDxe\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+# DRIVER_BINDING = gEmmcDxeDriverBinding\r
+# COMPONENT_NAME = gEmmcDxeComponentName\r
+# COMPONENT_NAME2 = gEmmcDxeComponentName2\r
+#\r
+\r
+[Sources.common]\r
+ ComponentName.c\r
+ EmmcDxe.c\r
+ EmmcDxe.h\r
+ EmmcBlockIo.c\r
+ EmmcBlockIo.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+ DevicePathLib\r
+ UefiBootServicesTableLib\r
+ MemoryAllocationLib\r
+ BaseMemoryLib\r
+ UefiLib\r
+ BaseLib\r
+ UefiDriverEntryPoint\r
+ DebugLib\r
+\r
+[Protocols]\r
+ gEfiSdMmcPassThruProtocolGuid ## TO_START\r
+ gEfiBlockIoProtocolGuid ## BY_START\r
+ gEfiBlockIo2ProtocolGuid ## BY_START\r
+ gEfiStorageSecurityCommandProtocolGuid ## SOMETIMES_PRODUCES\r
+ ## TO_START\r
+ ## BY_START\r
+ gEfiDevicePathProtocolGuid\r
+\r
--- /dev/null
+// /** @file\r
+// EMMC device driver to manage the EMMC device and provide interface for upper layer\r
+// access.\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "EMMC device driver to manage the EMMC device and provide interface for upper layer access"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "This driver follows the UEFI driver model and layers on the SdMmcPassThru protocol. It installs BlockIo/BlockIo2/StorageSecurity protocols for the EMMC device partitions."\r
+\r
--- /dev/null
+// /** @file\r
+// EmmcDxe Localized Strings and Content\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+#string STR_PROPERTIES_MODULE_NAME\r
+#language en-US\r
+"EMMC Device Driver"\r
+\r
+\r
--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdBlockIoPei.h"\r
+\r
+//\r
+// Template for SD HC Slot Data.\r
+//\r
+SD_PEIM_HC_SLOT gSdHcSlotTemplate = {\r
+ SD_PEIM_SLOT_SIG, // Signature\r
+ { // Media\r
+ MSG_SD_DP,\r
+ FALSE,\r
+ TRUE,\r
+ FALSE,\r
+ 0x200,\r
+ 0\r
+ },\r
+ 0, // SdHcBase\r
+ { // Capability\r
+ 0,\r
+ },\r
+ { // Csd\r
+ 0,\r
+ },\r
+ TRUE, // SectorAddressing\r
+ NULL // Private\r
+};\r
+\r
+//\r
+// Template for SD HC Private Data.\r
+//\r
+SD_PEIM_HC_PRIVATE_DATA gSdHcPrivateTemplate = {\r
+ SD_PEIM_SIG, // Signature\r
+ NULL, // Pool\r
+ { // BlkIoPpi\r
+ SdBlockIoPeimGetDeviceNo,\r
+ SdBlockIoPeimGetMediaInfo,\r
+ SdBlockIoPeimReadBlocks\r
+ },\r
+ { // BlkIo2Ppi\r
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,\r
+ SdBlockIoPeimGetDeviceNo2,\r
+ SdBlockIoPeimGetMediaInfo2,\r
+ SdBlockIoPeimReadBlocks2\r
+ },\r
+ { // BlkIoPpiList\r
+ EFI_PEI_PPI_DESCRIPTOR_PPI,\r
+ &gEfiPeiVirtualBlockIoPpiGuid,\r
+ NULL\r
+ },\r
+ { // BlkIo2PpiList\r
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
+ &gEfiPeiVirtualBlockIo2PpiGuid,\r
+ NULL\r
+ },\r
+ { // Slot\r
+ {\r
+ 0,\r
+ },\r
+ {\r
+ 0,\r
+ },\r
+ {\r
+ 0,\r
+ },\r
+ {\r
+ 0,\r
+ },\r
+ {\r
+ 0,\r
+ },\r
+ {\r
+ 0,\r
+ }\r
+ },\r
+ 0, // SlotNum\r
+ 0 // TotalBlkIoDevices\r
+};\r
+/**\r
+ Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+ This function is used for getting the count of block I/O devices that one\r
+ specific block driver detects. To the PEI ATAPI driver, it returns the number\r
+ of all the detected ATAPI devices it detects during the enumeration process.\r
+ To the PEI legacy floppy driver, it returns the number of all the legacy\r
+ devices it finds during its enumeration process. If no device is detected,\r
+ then the function will return zero.\r
+\r
+ @param[in] PeiServices General-purpose services that are available\r
+ to every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI\r
+ instance.\r
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.\r
+\r
+ @retval EFI_SUCCESS The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimGetDeviceNo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ OUT UINTN *NumberBlockDevices\r
+ )\r
+{\r
+ SD_PEIM_HC_PRIVATE_DATA *Private;\r
+\r
+ Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);\r
+ *NumberBlockDevices = Private->TotalBlkIoDevices;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Gets a block device's media information.\r
+\r
+ This function will provide the caller with the specified block device's media\r
+ information. If the media changes, calling this function will update the media\r
+ information accordingly.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, the PPIs that\r
+ want to talk to a single device must specify the\r
+ device index that was assigned during the enumeration\r
+ process. This index is a number from one to\r
+ NumberBlockDevices.\r
+ @param[out] MediaInfo The media information of the specified block media.\r
+ The caller is responsible for the ownership of this\r
+ data structure.\r
+\r
+ @par Note:\r
+ The MediaInfo structure describes an enumeration of possible block device\r
+ types. This enumeration exists because no device paths are actually passed\r
+ across interfaces that describe the type or class of hardware that is publishing\r
+ the block I/O interface. This enumeration will allow for policy decisions\r
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+ by a given device type, they should be reported in ascending order; this\r
+ order also applies to nested partitions, such as legacy MBR, where the\r
+ outermost partitions would have precedence in the reporting order. The\r
+ same logic applies to systems such as IDE that have precedence relationships\r
+ like "Master/Slave" or "Primary/Secondary". The master device should be\r
+ reported first, the slave second.\r
+\r
+ @retval EFI_SUCCESS Media information about the specified block device\r
+ was obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware\r
+ error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimGetMediaInfo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo\r
+ )\r
+{\r
+ SD_PEIM_HC_PRIVATE_DATA *Private;\r
+\r
+ Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ MediaInfo->DeviceType = SD;\r
+ MediaInfo->MediaPresent = TRUE;\r
+ MediaInfo->LastBlock = (UINTN)Private->Slot[DeviceIndex - 1].Media.LastBlock;\r
+ MediaInfo->BlockSize = Private->Slot[DeviceIndex - 1].Media.BlockSize;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Reads the requested number of blocks from the specified block device.\r
+\r
+ The function reads the requested number of blocks from the device. All the\r
+ blocks are read, or an error is returned. If there is no media in the device,\r
+ the function returns EFI_NO_MEDIA.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to\r
+ every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, PPIs that\r
+ want to talk to a single device must specify the device\r
+ index that was assigned during the enumeration process.\r
+ This index is a number from one to NumberBlockDevices.\r
+ @param[in] StartLBA The starting logical block address (LBA) to read from\r
+ on the device\r
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be\r
+ a multiple of the intrinsic block size of the device.\r
+ @param[out] Buffer A pointer to the destination buffer for the data.\r
+ The caller is responsible for the ownership of the\r
+ buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
+ to perform the read operation.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
+ valid, or the buffer is not properly aligned.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
+ the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimReadBlocks (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ IN EFI_PEI_LBA StartLBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+ UINTN NumberOfBlocks;\r
+ SD_PEIM_HC_PRIVATE_DATA *Private;\r
+ UINTN Remaining;\r
+ UINT32 MaxBlock;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ //\r
+ // Check parameters\r
+ //\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ BlockSize = Private->Slot[DeviceIndex - 1].Media.BlockSize;\r
+ if (BufferSize % BlockSize != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ if (StartLBA > Private->Slot[DeviceIndex - 1].Media.LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ NumberOfBlocks = BufferSize / BlockSize;\r
+\r
+ //\r
+ // Start to execute data transfer. The max block number in single cmd is 65535 blocks.\r
+ //\r
+ Remaining = NumberOfBlocks;\r
+ MaxBlock = 0xFFFF;\r
+\r
+ while (Remaining > 0) {\r
+ if (Remaining <= MaxBlock) {\r
+ NumberOfBlocks = Remaining;\r
+ } else {\r
+ NumberOfBlocks = MaxBlock;\r
+ }\r
+\r
+ BufferSize = NumberOfBlocks * BlockSize;\r
+ if (NumberOfBlocks != 1) {\r
+ Status = SdPeimRwMultiBlocks (&Private->Slot[DeviceIndex - 1], StartLBA, BlockSize, Buffer, BufferSize, TRUE);\r
+ } else {\r
+ Status = SdPeimRwSingleBlock (&Private->Slot[DeviceIndex - 1], StartLBA, BlockSize, Buffer, BufferSize, TRUE);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ StartLBA += NumberOfBlocks;\r
+ Buffer = (UINT8*)Buffer + BufferSize;\r
+ Remaining -= NumberOfBlocks;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+ This function is used for getting the count of block I/O devices that one\r
+ specific block driver detects. To the PEI ATAPI driver, it returns the number\r
+ of all the detected ATAPI devices it detects during the enumeration process.\r
+ To the PEI legacy floppy driver, it returns the number of all the legacy\r
+ devices it finds during its enumeration process. If no device is detected,\r
+ then the function will return zero.\r
+\r
+ @param[in] PeiServices General-purpose services that are available\r
+ to every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI\r
+ instance.\r
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.\r
+\r
+ @retval EFI_SUCCESS The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimGetDeviceNo2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ OUT UINTN *NumberBlockDevices\r
+ )\r
+{\r
+ SD_PEIM_HC_PRIVATE_DATA *Private;\r
+\r
+ Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);\r
+ *NumberBlockDevices = Private->TotalBlkIoDevices;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Gets a block device's media information.\r
+\r
+ This function will provide the caller with the specified block device's media\r
+ information. If the media changes, calling this function will update the media\r
+ information accordingly.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, the PPIs that\r
+ want to talk to a single device must specify the\r
+ device index that was assigned during the enumeration\r
+ process. This index is a number from one to\r
+ NumberBlockDevices.\r
+ @param[out] MediaInfo The media information of the specified block media.\r
+ The caller is responsible for the ownership of this\r
+ data structure.\r
+\r
+ @par Note:\r
+ The MediaInfo structure describes an enumeration of possible block device\r
+ types. This enumeration exists because no device paths are actually passed\r
+ across interfaces that describe the type or class of hardware that is publishing\r
+ the block I/O interface. This enumeration will allow for policy decisions\r
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+ by a given device type, they should be reported in ascending order; this\r
+ order also applies to nested partitions, such as legacy MBR, where the\r
+ outermost partitions would have precedence in the reporting order. The\r
+ same logic applies to systems such as IDE that have precedence relationships\r
+ like "Master/Slave" or "Primary/Secondary". The master device should be\r
+ reported first, the slave second.\r
+\r
+ @retval EFI_SUCCESS Media information about the specified block device\r
+ was obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware\r
+ error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimGetMediaInfo2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_PEIM_HC_PRIVATE_DATA *Private;\r
+ EFI_PEI_BLOCK_IO_MEDIA Media;\r
+\r
+ Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);\r
+\r
+ Status = SdBlockIoPeimGetMediaInfo (\r
+ PeiServices,\r
+ &Private->BlkIoPpi,\r
+ DeviceIndex,\r
+ &Media\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ CopyMem (MediaInfo, &(Private->Slot[DeviceIndex - 1].Media), sizeof (EFI_PEI_BLOCK_IO2_MEDIA));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Reads the requested number of blocks from the specified block device.\r
+\r
+ The function reads the requested number of blocks from the device. All the\r
+ blocks are read, or an error is returned. If there is no media in the device,\r
+ the function returns EFI_NO_MEDIA.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to\r
+ every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, PPIs that\r
+ want to talk to a single device must specify the device\r
+ index that was assigned during the enumeration process.\r
+ This index is a number from one to NumberBlockDevices.\r
+ @param[in] StartLBA The starting logical block address (LBA) to read from\r
+ on the device\r
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be\r
+ a multiple of the intrinsic block size of the device.\r
+ @param[out] Buffer A pointer to the destination buffer for the data.\r
+ The caller is responsible for the ownership of the\r
+ buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
+ to perform the read operation.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
+ valid, or the buffer is not properly aligned.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
+ the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimReadBlocks2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ IN EFI_PEI_LBA StartLBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_PEIM_HC_PRIVATE_DATA *Private;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);\r
+\r
+ Status = SdBlockIoPeimReadBlocks (\r
+ PeiServices,\r
+ &Private->BlkIoPpi,\r
+ DeviceIndex,\r
+ StartLBA,\r
+ BufferSize,\r
+ Buffer\r
+ );\r
+ return Status;\r
+}\r
+\r
+/**\r
+ The user code starts with this function.\r
+\r
+ @param FileHandle Handle of the file being invoked.\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+\r
+ @retval EFI_SUCCESS The driver is successfully initialized.\r
+ @retval Others Can't initialize the driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSdBlockIoPeim (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_PEIM_HC_PRIVATE_DATA *Private;\r
+ EDKII_SD_MMC_HOST_CONTROLLER_PPI *SdMmcHcPpi;\r
+ UINT32 Index;\r
+ UINTN *MmioBase;\r
+ UINT8 BarNum;\r
+ UINT8 SlotNum;\r
+ UINT8 Controller;\r
+ UINT64 Capacity;\r
+ SD_HC_SLOT_CAP Capability;\r
+ SD_PEIM_HC_SLOT *Slot;\r
+ SD_CSD *Csd;\r
+ SD_CSD2 *Csd2;\r
+ UINT32 CSize;\r
+ UINT32 CSizeMul;\r
+ UINT32 ReadBlLen;\r
+\r
+ //\r
+ // Shadow this PEIM to run from memory\r
+ //\r
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // locate Sd host controller PPI\r
+ //\r
+ Status = PeiServicesLocatePpi (\r
+ &gEdkiiPeiSdMmcHostControllerPpiGuid,\r
+ 0,\r
+ NULL,\r
+ (VOID **) &SdMmcHcPpi\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Controller = 0;\r
+ MmioBase = NULL;\r
+ while (TRUE) {\r
+ Status = SdMmcHcPpi->GetSdMmcHcMmioBar (SdMmcHcPpi, Controller, &MmioBase, &BarNum);\r
+ //\r
+ // When status is error, meant no controller is found\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ if (BarNum == 0) {\r
+ Controller++;\r
+ continue;\r
+ }\r
+\r
+ Private = AllocateCopyPool (sizeof (SD_PEIM_HC_PRIVATE_DATA), &gSdHcPrivateTemplate);\r
+ if (Private == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ break;\r
+ }\r
+ Private->BlkIoPpiList.Ppi = (VOID*)&Private->BlkIoPpi;\r
+ Private->BlkIo2PpiList.Ppi = (VOID*)&Private->BlkIo2Ppi;\r
+ //\r
+ // Initialize the memory pool which will be used in all transactions.\r
+ //\r
+ Status = SdPeimInitMemPool (Private);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ break;\r
+ }\r
+\r
+ for (Index = 0; Index < BarNum; Index++) {\r
+ Status = SdPeimHcGetCapability (MmioBase[Index], &Capability);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ if (Capability.SlotType != 0x1) {\r
+ DEBUG ((EFI_D_INFO, "The slot at 0x%x is not embedded slot type\n", MmioBase[Index]));\r
+ Status = EFI_UNSUPPORTED;\r
+ continue;\r
+ }\r
+\r
+ Status = SdPeimHcReset (MmioBase[Index]);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ Status = SdPeimHcCardDetect (MmioBase[Index]);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ Status = SdPeimHcInitHost (MmioBase[Index]);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ SlotNum = Private->SlotNum;\r
+ Slot = &Private->Slot[SlotNum];\r
+ CopyMem (Slot, &gSdHcSlotTemplate, sizeof (SD_PEIM_HC_SLOT));\r
+ Slot->Private = Private;\r
+ Slot->SdHcBase = MmioBase[Index];\r
+ CopyMem (&Slot->Capability, &Capability, sizeof (Capability));\r
+\r
+ Status = SdPeimIdentification (Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ Csd = &Slot->Csd;\r
+ if (Csd->CsdStructure == 0) {\r
+ Slot->SectorAddressing = FALSE;\r
+ CSize = (Csd->CSizeHigh << 2 | Csd->CSizeLow) + 1;\r
+ CSizeMul = (1 << (Csd->CSizeMul + 2));\r
+ ReadBlLen = (1 << (Csd->ReadBlLen));\r
+ Capacity = MultU64x32 (MultU64x32 ((UINT64)CSize, CSizeMul), ReadBlLen);\r
+ } else {\r
+ Slot->SectorAddressing = TRUE;\r
+ Csd2 = (SD_CSD2*)(VOID*)Csd;\r
+ CSize = (Csd2->CSizeHigh << 16 | Csd2->CSizeLow) + 1;\r
+ Capacity = MultU64x32 ((UINT64)CSize, SIZE_512KB);\r
+ }\r
+\r
+ Slot->Media.LastBlock = DivU64x32 (Capacity, Slot->Media.BlockSize) - 1;\r
+\r
+ Private->TotalBlkIoDevices++;\r
+ Private->SlotNum++;\r
+ }\r
+\r
+ Controller++;\r
+ if (!EFI_ERROR (Status)) {\r
+ PeiServicesInstallPpi (&Private->BlkIoPpiList);\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_BLOCK_IO_PEI_H_\r
+#define _SD_BLOCK_IO_PEI_H_\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/SdMmcHostController.h>\r
+#include <Ppi/BlockIo.h>\r
+#include <Ppi/BlockIo2.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+\r
+#include <IndustryStandard/Sd.h>\r
+\r
+typedef struct _SD_PEIM_HC_PRIVATE_DATA SD_PEIM_HC_PRIVATE_DATA;\r
+typedef struct _SD_PEIM_HC_SLOT SD_PEIM_HC_SLOT;\r
+typedef struct _SD_TRB SD_TRB;\r
+\r
+#include "SdHci.h"\r
+#include "SdHcMem.h"\r
+\r
+#define SD_PEIM_SIG SIGNATURE_32 ('S', 'D', 'C', 'P')\r
+#define SD_PEIM_SLOT_SIG SIGNATURE_32 ('S', 'D', 'C', 'S')\r
+\r
+#define SD_PEIM_MAX_SLOTS 6\r
+\r
+struct _SD_PEIM_HC_SLOT {\r
+ UINT32 Signature;\r
+ EFI_PEI_BLOCK_IO2_MEDIA Media;\r
+\r
+ UINTN SdHcBase;\r
+ SD_HC_SLOT_CAP Capability;\r
+ SD_CSD Csd;\r
+ BOOLEAN SectorAddressing;\r
+ SD_PEIM_HC_PRIVATE_DATA *Private;\r
+};\r
+\r
+struct _SD_PEIM_HC_PRIVATE_DATA {\r
+ UINT32 Signature;\r
+ SD_PEIM_MEM_POOL *Pool;\r
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi;\r
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI BlkIo2Ppi;\r
+ EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList;\r
+ EFI_PEI_PPI_DESCRIPTOR BlkIo2PpiList;\r
+ SD_PEIM_HC_SLOT Slot[SD_PEIM_MAX_SLOTS];\r
+ UINT8 SlotNum;\r
+ UINT8 TotalBlkIoDevices;\r
+};\r
+\r
+#define SD_TIMEOUT MultU64x32((UINT64)(3), 1000000)\r
+#define GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS(a) CR (a, SD_PEIM_HC_PRIVATE_DATA, BlkIoPpi, SD_PEIM_SIG)\r
+#define GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2(a) CR (a, SD_PEIM_HC_PRIVATE_DATA, BlkIo2Ppi, SD_PEIM_SIG)\r
+\r
+struct _SD_TRB {\r
+ SD_PEIM_HC_SLOT *Slot;\r
+ UINT16 BlockSize;\r
+\r
+ SD_COMMAND_PACKET *Packet;\r
+ VOID *Data;\r
+ UINT32 DataLen;\r
+ BOOLEAN Read;\r
+ SD_HC_TRANSFER_MODE Mode;\r
+\r
+ UINT64 Timeout;\r
+\r
+ SD_HC_ADMA_DESC_LINE *AdmaDesc;\r
+ UINTN AdmaDescSize;\r
+};\r
+\r
+/**\r
+ Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+ This function is used for getting the count of block I/O devices that one\r
+ specific block driver detects. To the PEI ATAPI driver, it returns the number\r
+ of all the detected ATAPI devices it detects during the enumeration process.\r
+ To the PEI legacy floppy driver, it returns the number of all the legacy\r
+ devices it finds during its enumeration process. If no device is detected,\r
+ then the function will return zero.\r
+\r
+ @param[in] PeiServices General-purpose services that are available\r
+ to every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI\r
+ instance.\r
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.\r
+\r
+ @retval EFI_SUCCESS The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimGetDeviceNo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ OUT UINTN *NumberBlockDevices\r
+ );\r
+\r
+/**\r
+ Gets a block device's media information.\r
+\r
+ This function will provide the caller with the specified block device's media\r
+ information. If the media changes, calling this function will update the media\r
+ information accordingly.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, the PPIs that\r
+ want to talk to a single device must specify the\r
+ device index that was assigned during the enumeration\r
+ process. This index is a number from one to\r
+ NumberBlockDevices.\r
+ @param[out] MediaInfo The media information of the specified block media.\r
+ The caller is responsible for the ownership of this\r
+ data structure.\r
+\r
+ @par Note:\r
+ The MediaInfo structure describes an enumeration of possible block device\r
+ types. This enumeration exists because no device paths are actually passed\r
+ across interfaces that describe the type or class of hardware that is publishing\r
+ the block I/O interface. This enumeration will allow for policy decisions\r
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+ by a given device type, they should be reported in ascending order; this\r
+ order also applies to nested partitions, such as legacy MBR, where the\r
+ outermost partitions would have precedence in the reporting order. The\r
+ same logic applies to systems such as IDE that have precedence relationships\r
+ like "Master/Slave" or "Primary/Secondary". The master device should be\r
+ reported first, the slave second.\r
+\r
+ @retval EFI_SUCCESS Media information about the specified block device\r
+ was obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware\r
+ error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimGetMediaInfo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo\r
+ );\r
+\r
+/**\r
+ Reads the requested number of blocks from the specified block device.\r
+\r
+ The function reads the requested number of blocks from the device. All the\r
+ blocks are read, or an error is returned. If there is no media in the device,\r
+ the function returns EFI_NO_MEDIA.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to\r
+ every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, PPIs that\r
+ want to talk to a single device must specify the device\r
+ index that was assigned during the enumeration process.\r
+ This index is a number from one to NumberBlockDevices.\r
+ @param[in] StartLBA The starting logical block address (LBA) to read from\r
+ on the device\r
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be\r
+ a multiple of the intrinsic block size of the device.\r
+ @param[out] Buffer A pointer to the destination buffer for the data.\r
+ The caller is responsible for the ownership of the\r
+ buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
+ to perform the read operation.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
+ valid, or the buffer is not properly aligned.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
+ the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimReadBlocks (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ IN EFI_PEI_LBA StartLBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+ This function is used for getting the count of block I/O devices that one\r
+ specific block driver detects. To the PEI ATAPI driver, it returns the number\r
+ of all the detected ATAPI devices it detects during the enumeration process.\r
+ To the PEI legacy floppy driver, it returns the number of all the legacy\r
+ devices it finds during its enumeration process. If no device is detected,\r
+ then the function will return zero.\r
+\r
+ @param[in] PeiServices General-purpose services that are available\r
+ to every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI\r
+ instance.\r
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.\r
+\r
+ @retval EFI_SUCCESS The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimGetDeviceNo2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ OUT UINTN *NumberBlockDevices\r
+ );\r
+\r
+/**\r
+ Gets a block device's media information.\r
+\r
+ This function will provide the caller with the specified block device's media\r
+ information. If the media changes, calling this function will update the media\r
+ information accordingly.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, the PPIs that\r
+ want to talk to a single device must specify the\r
+ device index that was assigned during the enumeration\r
+ process. This index is a number from one to\r
+ NumberBlockDevices.\r
+ @param[out] MediaInfo The media information of the specified block media.\r
+ The caller is responsible for the ownership of this\r
+ data structure.\r
+\r
+ @par Note:\r
+ The MediaInfo structure describes an enumeration of possible block device\r
+ types. This enumeration exists because no device paths are actually passed\r
+ across interfaces that describe the type or class of hardware that is publishing\r
+ the block I/O interface. This enumeration will allow for policy decisions\r
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+ by a given device type, they should be reported in ascending order; this\r
+ order also applies to nested partitions, such as legacy MBR, where the\r
+ outermost partitions would have precedence in the reporting order. The\r
+ same logic applies to systems such as IDE that have precedence relationships\r
+ like "Master/Slave" or "Primary/Secondary". The master device should be\r
+ reported first, the slave second.\r
+\r
+ @retval EFI_SUCCESS Media information about the specified block device\r
+ was obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware\r
+ error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimGetMediaInfo2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo\r
+ );\r
+\r
+/**\r
+ Reads the requested number of blocks from the specified block device.\r
+\r
+ The function reads the requested number of blocks from the device. All the\r
+ blocks are read, or an error is returned. If there is no media in the device,\r
+ the function returns EFI_NO_MEDIA.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to\r
+ every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, PPIs that\r
+ want to talk to a single device must specify the device\r
+ index that was assigned during the enumeration process.\r
+ This index is a number from one to NumberBlockDevices.\r
+ @param[in] StartLBA The starting logical block address (LBA) to read from\r
+ on the device\r
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be\r
+ a multiple of the intrinsic block size of the device.\r
+ @param[out] Buffer A pointer to the destination buffer for the data.\r
+ The caller is responsible for the ownership of the\r
+ buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
+ to perform the read operation.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
+ valid, or the buffer is not properly aligned.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
+ the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimReadBlocks2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ IN EFI_PEI_LBA StartLBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Initialize the memory management pool for the host controller.\r
+\r
+ @param Private The Sd Peim driver private data.\r
+\r
+ @retval EFI_SUCCESS The memory pool is initialized.\r
+ @retval Others Fail to init the memory pool.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimInitMemPool (\r
+ IN SD_PEIM_HC_PRIVATE_DATA *Private\r
+ );\r
+\r
+/**\r
+ Allocate some memory from the host controller's memory pool\r
+ which can be used to communicate with host controller.\r
+\r
+ @param Pool The host controller's memory pool.\r
+ @param Size Size of the memory to allocate.\r
+\r
+ @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+SdPeimAllocateMem (\r
+ IN SD_PEIM_MEM_POOL *Pool,\r
+ IN UINTN Size\r
+ );\r
+\r
+/**\r
+ Free the allocated memory back to the memory pool.\r
+\r
+ @param Pool The memory pool of the host controller.\r
+ @param Mem The memory to free.\r
+ @param Size The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+SdPeimFreeMem (\r
+ IN SD_PEIM_MEM_POOL *Pool,\r
+ IN VOID *Mem,\r
+ IN UINTN Size\r
+ );\r
+\r
+#endif\r
--- /dev/null
+## @file\r
+# Description file for the SD memory card Peim driver.\r
+#\r
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = SdBlockIoPei\r
+ MODULE_UNI_FILE = SdBlockIoPei.uni\r
+ FILE_GUID = 17851FBF-45C4-4ff7-A2A0-C3B12D63C27E\r
+ MODULE_TYPE = PEIM\r
+ VERSION_STRING = 1.0\r
+\r
+ ENTRY_POINT = InitializeSdBlockIoPeim\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ SdBlockIoPei.c\r
+ SdBlockIoPei.h\r
+ SdHci.c\r
+ SdHci.h\r
+ SdHcMem.c\r
+ SdHcMem.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+ IoLib\r
+ TimerLib\r
+ BaseMemoryLib\r
+ PeimEntryPoint\r
+ PeiServicesLib\r
+ DebugLib\r
+\r
+[Ppis]\r
+ gEfiPeiVirtualBlockIoPpiGuid ## PRODUCES\r
+ gEfiPeiVirtualBlockIo2PpiGuid ## PRODUCES\r
+ gEdkiiPeiSdMmcHostControllerPpiGuid ## CONSUMES\r
+\r
+[Depex]\r
+ gEfiPeiMemoryDiscoveredPpiGuid AND gEdkiiPeiSdMmcHostControllerPpiGuid\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+ SdBlockIoPeiExtra.uni\r
+\r
--- /dev/null
+// /** @file\r
+// The SdBlockIoPei driver is used to support recovery from SD memory card device.\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions\r
+// of the BSD License which accompanies this distribution. The\r
+// full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "Support recovery from SD memory card devices"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "The SdBlockIoPei driver is used to support recovery from SD memory card device."\r
+\r
--- /dev/null
+// /** @file\r
+// SdBlockIoPei Localized Strings and Content\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions\r
+// of the BSD License which accompanies this distribution. The\r
+// full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+#string STR_PROPERTIES_MODULE_NAME\r
+#language en-US\r
+"SD BlockIo Peim for Recovery"\r
+\r
+\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdBlockIoPei.h"\r
+\r
+/**\r
+ Allocate a block of memory to be used by the buffer pool.\r
+\r
+ @param Pages How many pages to allocate.\r
+\r
+ @return The allocated memory block or NULL if failed.\r
+\r
+**/\r
+SD_PEIM_MEM_BLOCK *\r
+SdPeimAllocMemBlock (\r
+ IN UINTN Pages\r
+ )\r
+{\r
+ SD_PEIM_MEM_BLOCK *Block;\r
+ EFI_STATUS Status;\r
+ VOID *TempPtr;\r
+ EFI_PHYSICAL_ADDRESS Address;\r
+\r
+ TempPtr = NULL;\r
+ Block = NULL;\r
+\r
+ Status = PeiServicesAllocatePool (sizeof(SD_PEIM_MEM_BLOCK), &TempPtr);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ ZeroMem ((VOID*)(UINTN)TempPtr, sizeof(SD_PEIM_MEM_BLOCK));\r
+\r
+ //\r
+ // each bit in the bit array represents SD_PEIM_MEM_UNIT\r
+ // bytes of memory in the memory block.\r
+ //\r
+ ASSERT (SD_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
+\r
+ Block = (SD_PEIM_MEM_BLOCK*)(UINTN)TempPtr;\r
+ Block->BufLen = EFI_PAGES_TO_SIZE (Pages);\r
+ Block->BitsLen = Block->BufLen / (SD_PEIM_MEM_UNIT * 8);\r
+\r
+ Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ ZeroMem ((VOID*)(UINTN)TempPtr, Block->BitsLen);\r
+\r
+ Block->Bits = (UINT8*)(UINTN)TempPtr;\r
+\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ Pages,\r
+ &Address\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ ZeroMem ((VOID*)(UINTN)Address, EFI_PAGES_TO_SIZE (Pages));\r
+\r
+ Block->Buf = (UINT8*)((UINTN)Address);\r
+ Block->Next = NULL;\r
+\r
+ return Block;\r
+}\r
+\r
+/**\r
+ Free the memory block from the memory pool.\r
+\r
+ @param Pool The memory pool to free the block from.\r
+ @param Block The memory block to free.\r
+\r
+**/\r
+VOID\r
+SdPeimFreeMemBlock (\r
+ IN SD_PEIM_MEM_POOL *Pool,\r
+ IN SD_PEIM_MEM_BLOCK *Block\r
+ )\r
+{\r
+ ASSERT ((Pool != NULL) && (Block != NULL));\r
+}\r
+\r
+/**\r
+ Alloc some memory from the block.\r
+\r
+ @param Block The memory block to allocate memory from.\r
+ @param Units Number of memory units to allocate.\r
+\r
+ @return The pointer to the allocated memory. If couldn't allocate the needed memory,\r
+ the return value is NULL.\r
+\r
+**/\r
+VOID *\r
+SdPeimAllocMemFromBlock (\r
+ IN SD_PEIM_MEM_BLOCK *Block,\r
+ IN UINTN Units\r
+ )\r
+{\r
+ UINTN Byte;\r
+ UINT8 Bit;\r
+ UINTN StartByte;\r
+ UINT8 StartBit;\r
+ UINTN Available;\r
+ UINTN Count;\r
+\r
+ ASSERT ((Block != 0) && (Units != 0));\r
+\r
+ StartByte = 0;\r
+ StartBit = 0;\r
+ Available = 0;\r
+\r
+ for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
+ //\r
+ // If current bit is zero, the corresponding memory unit is\r
+ // available, otherwise we need to restart our searching.\r
+ // Available counts the consective number of zero bit.\r
+ //\r
+ if (!SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
+ Available++;\r
+\r
+ if (Available >= Units) {\r
+ break;\r
+ }\r
+\r
+ SD_PEIM_NEXT_BIT (Byte, Bit);\r
+\r
+ } else {\r
+ SD_PEIM_NEXT_BIT (Byte, Bit);\r
+\r
+ Available = 0;\r
+ StartByte = Byte;\r
+ StartBit = Bit;\r
+ }\r
+ }\r
+\r
+ if (Available < Units) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Mark the memory as allocated\r
+ //\r
+ Byte = StartByte;\r
+ Bit = StartBit;\r
+\r
+ for (Count = 0; Count < Units; Count++) {\r
+ ASSERT (!SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) SD_PEIM_MEM_BIT (Bit));\r
+ SD_PEIM_NEXT_BIT (Byte, Bit);\r
+ }\r
+\r
+ return Block->Buf + (StartByte * 8 + StartBit) * SD_PEIM_MEM_UNIT;\r
+}\r
+\r
+/**\r
+ Insert the memory block to the pool's list of the blocks.\r
+\r
+ @param Head The head of the memory pool's block list.\r
+ @param Block The memory block to insert.\r
+\r
+**/\r
+VOID\r
+SdPeimInsertMemBlockToPool (\r
+ IN SD_PEIM_MEM_BLOCK *Head,\r
+ IN SD_PEIM_MEM_BLOCK *Block\r
+ )\r
+{\r
+ ASSERT ((Head != NULL) && (Block != NULL));\r
+ Block->Next = Head->Next;\r
+ Head->Next = Block;\r
+}\r
+\r
+/**\r
+ Is the memory block empty?\r
+\r
+ @param Block The memory block to check.\r
+\r
+ @retval TRUE The memory block is empty.\r
+ @retval FALSE The memory block isn't empty.\r
+\r
+**/\r
+BOOLEAN\r
+SdPeimIsMemBlockEmpty (\r
+ IN SD_PEIM_MEM_BLOCK *Block\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+\r
+ for (Index = 0; Index < Block->BitsLen; Index++) {\r
+ if (Block->Bits[Index] != 0) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Unlink the memory block from the pool's list.\r
+\r
+ @param Head The block list head of the memory's pool.\r
+ @param BlockToUnlink The memory block to unlink.\r
+\r
+**/\r
+VOID\r
+SdPeimUnlinkMemBlock (\r
+ IN SD_PEIM_MEM_BLOCK *Head,\r
+ IN SD_PEIM_MEM_BLOCK *BlockToUnlink\r
+ )\r
+{\r
+ SD_PEIM_MEM_BLOCK *Block;\r
+\r
+ ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
+\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ if (Block->Next == BlockToUnlink) {\r
+ Block->Next = BlockToUnlink->Next;\r
+ BlockToUnlink->Next = NULL;\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Initialize the memory management pool for the host controller.\r
+\r
+ @param Private The Sd Peim driver private data.\r
+\r
+ @retval EFI_SUCCESS The memory pool is initialized.\r
+ @retval Others Fail to init the memory pool.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimInitMemPool (\r
+ IN SD_PEIM_HC_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ SD_PEIM_MEM_POOL *Pool;\r
+ EFI_STATUS Status;\r
+ VOID *TempPtr;\r
+\r
+ TempPtr = NULL;\r
+ Pool = NULL;\r
+\r
+ Status = PeiServicesAllocatePool (sizeof (SD_PEIM_MEM_POOL), &TempPtr);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ ZeroMem ((VOID*)(UINTN)TempPtr, sizeof (SD_PEIM_MEM_POOL));\r
+\r
+ Pool = (SD_PEIM_MEM_POOL *)((UINTN)TempPtr);\r
+\r
+ Pool->Head = SdPeimAllocMemBlock (SD_PEIM_MEM_DEFAULT_PAGES);\r
+\r
+ if (Pool->Head == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Private->Pool = Pool;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Release the memory management pool.\r
+\r
+ @param Pool The memory pool to free.\r
+\r
+ @retval EFI_DEVICE_ERROR Fail to free the memory pool.\r
+ @retval EFI_SUCCESS The memory pool is freed.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimFreeMemPool (\r
+ IN SD_PEIM_MEM_POOL *Pool\r
+ )\r
+{\r
+ SD_PEIM_MEM_BLOCK *Block;\r
+\r
+ ASSERT (Pool->Head != NULL);\r
+\r
+ //\r
+ // Unlink all the memory blocks from the pool, then free them.\r
+ // SdPeimUnlinkMemBlock can't be used to unlink and free the\r
+ // first block.\r
+ //\r
+ for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
+ SdPeimFreeMemBlock (Pool, Block);\r
+ }\r
+\r
+ SdPeimFreeMemBlock (Pool, Pool->Head);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Allocate some memory from the host controller's memory pool\r
+ which can be used to communicate with host controller.\r
+\r
+ @param Pool The host controller's memory pool.\r
+ @param Size Size of the memory to allocate.\r
+\r
+ @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+SdPeimAllocateMem (\r
+ IN SD_PEIM_MEM_POOL *Pool,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ SD_PEIM_MEM_BLOCK *Head;\r
+ SD_PEIM_MEM_BLOCK *Block;\r
+ SD_PEIM_MEM_BLOCK *NewBlock;\r
+ VOID *Mem;\r
+ UINTN AllocSize;\r
+ UINTN Pages;\r
+\r
+ Mem = NULL;\r
+ AllocSize = SD_PEIM_MEM_ROUND (Size);\r
+ Head = Pool->Head;\r
+ ASSERT (Head != NULL);\r
+\r
+ //\r
+ // First check whether current memory blocks can satisfy the allocation.\r
+ //\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ Mem = SdPeimAllocMemFromBlock (Block, AllocSize / SD_PEIM_MEM_UNIT);\r
+\r
+ if (Mem != NULL) {\r
+ ZeroMem (Mem, Size);\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Mem != NULL) {\r
+ return Mem;\r
+ }\r
+\r
+ //\r
+ // Create a new memory block if there is not enough memory\r
+ // in the pool. If the allocation size is larger than the\r
+ // default page number, just allocate a large enough memory\r
+ // block. Otherwise allocate default pages.\r
+ //\r
+ if (AllocSize > EFI_PAGES_TO_SIZE (SD_PEIM_MEM_DEFAULT_PAGES)) {\r
+ Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
+ } else {\r
+ Pages = SD_PEIM_MEM_DEFAULT_PAGES;\r
+ }\r
+\r
+ NewBlock = SdPeimAllocMemBlock (Pages);\r
+ if (NewBlock == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Add the new memory block to the pool, then allocate memory from it\r
+ //\r
+ SdPeimInsertMemBlockToPool (Head, NewBlock);\r
+ Mem = SdPeimAllocMemFromBlock (NewBlock, AllocSize / SD_PEIM_MEM_UNIT);\r
+\r
+ if (Mem != NULL) {\r
+ ZeroMem (Mem, Size);\r
+ }\r
+\r
+ return Mem;\r
+}\r
+\r
+/**\r
+ Free the allocated memory back to the memory pool.\r
+\r
+ @param Pool The memory pool of the host controller.\r
+ @param Mem The memory to free.\r
+ @param Size The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+SdPeimFreeMem (\r
+ IN SD_PEIM_MEM_POOL *Pool,\r
+ IN VOID *Mem,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ SD_PEIM_MEM_BLOCK *Head;\r
+ SD_PEIM_MEM_BLOCK *Block;\r
+ UINT8 *ToFree;\r
+ UINTN AllocSize;\r
+ UINTN Byte;\r
+ UINTN Bit;\r
+ UINTN Count;\r
+\r
+ Head = Pool->Head;\r
+ AllocSize = SD_PEIM_MEM_ROUND (Size);\r
+ ToFree = (UINT8 *) Mem;\r
+\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ //\r
+ // scan the memory block list for the memory block that\r
+ // completely contains the memory to free.\r
+ //\r
+ if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
+ //\r
+ // compute the start byte and bit in the bit array\r
+ //\r
+ Byte = ((ToFree - Block->Buf) / SD_PEIM_MEM_UNIT) / 8;\r
+ Bit = ((ToFree - Block->Buf) / SD_PEIM_MEM_UNIT) % 8;\r
+\r
+ //\r
+ // reset associated bits in bit arry\r
+ //\r
+ for (Count = 0; Count < (AllocSize / SD_PEIM_MEM_UNIT); Count++) {\r
+ ASSERT (SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ SD_PEIM_MEM_BIT (Bit));\r
+ SD_PEIM_NEXT_BIT (Byte, Bit);\r
+ }\r
+\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If Block == NULL, it means that the current memory isn't\r
+ // in the host controller's pool. This is critical because\r
+ // the caller has passed in a wrong memory point\r
+ //\r
+ ASSERT (Block != NULL);\r
+\r
+ //\r
+ // Release the current memory block if it is empty and not the head\r
+ //\r
+ if ((Block != Head) && SdPeimIsMemBlockEmpty (Block)) {\r
+ SdPeimFreeMemBlock (Pool, Block);\r
+ }\r
+\r
+ return ;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_PEIM_MEM_H_\r
+#define _SD_PEIM_MEM_H_\r
+\r
+#define SD_PEIM_MEM_BIT(a) ((UINTN)(1 << (a)))\r
+\r
+#define SD_PEIM_MEM_BIT_IS_SET(Data, Bit) \\r
+ ((BOOLEAN)(((Data) & SD_PEIM_MEM_BIT(Bit)) == SD_PEIM_MEM_BIT(Bit)))\r
+\r
+typedef struct _SD_PEIM_MEM_BLOCK SD_PEIM_MEM_BLOCK;\r
+\r
+struct _SD_PEIM_MEM_BLOCK {\r
+ UINT8 *Bits; // Bit array to record which unit is allocated\r
+ UINTN BitsLen;\r
+ UINT8 *Buf;\r
+ UINTN BufLen; // Memory size in bytes\r
+ SD_PEIM_MEM_BLOCK *Next;\r
+};\r
+\r
+typedef struct _SD_PEIM_MEM_POOL {\r
+ SD_PEIM_MEM_BLOCK *Head;\r
+} SD_PEIM_MEM_POOL;\r
+\r
+//\r
+// Memory allocation unit, note that the value must meet SD spec alignment requirement.\r
+//\r
+#define SD_PEIM_MEM_UNIT 128\r
+\r
+#define SD_PEIM_MEM_UNIT_MASK (SD_PEIM_MEM_UNIT - 1)\r
+#define SD_PEIM_MEM_DEFAULT_PAGES 16\r
+\r
+#define SD_PEIM_MEM_ROUND(Len) (((Len) + SD_PEIM_MEM_UNIT_MASK) & (~SD_PEIM_MEM_UNIT_MASK))\r
+\r
+//\r
+// Advance the byte and bit to the next bit, adjust byte accordingly.\r
+//\r
+#define SD_PEIM_NEXT_BIT(Byte, Bit) \\r
+ do { \\r
+ (Bit)++; \\r
+ if ((Bit) > 7) { \\r
+ (Byte)++; \\r
+ (Bit) = 0; \\r
+ } \\r
+ } while (0)\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdBlockIoPei.h"\r
+\r
+/**\r
+ Read/Write specified SD host controller mmio register.\r
+\r
+ @param[in] Address The address of the mmio register to be read/written.\r
+ @param[in] Read A boolean to indicate it's read or write operation.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2 , 4 or 8 bytes.\r
+ @param[in, out] Data For read operations, the destination buffer to store\r
+ the results. For write operations, the source buffer\r
+ to write data from. The caller is responsible for\r
+ having ownership of the data buffer and ensuring its\r
+ size not less than Count bytes.\r
+\r
+ @retval EFI_INVALID_PARAMETER The Address or the Data or the Count is not valid.\r
+ @retval EFI_SUCCESS The read/write operation succeeds.\r
+ @retval Others The read/write operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdPeimHcRwMmio (\r
+ IN UINTN Address,\r
+ IN BOOLEAN Read,\r
+ IN UINT8 Count,\r
+ IN OUT VOID *Data\r
+ )\r
+{\r
+ if ((Address == 0) || (Data == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ switch (Count) {\r
+ case 1:\r
+ if (Read) {\r
+ *(UINT8*)Data = MmioRead8 (Address);\r
+ } else {\r
+ MmioWrite8 (Address, *(UINT8*)Data);\r
+ }\r
+ break;\r
+ case 2:\r
+ if (Read) {\r
+ *(UINT16*)Data = MmioRead16 (Address);\r
+ } else {\r
+ MmioWrite16 (Address, *(UINT16*)Data);\r
+ }\r
+ break;\r
+ case 4:\r
+ if (Read) {\r
+ *(UINT32*)Data = MmioRead32 (Address);\r
+ } else {\r
+ MmioWrite32 (Address, *(UINT32*)Data);\r
+ }\r
+ break;\r
+ case 8:\r
+ if (Read) {\r
+ *(UINT64*)Data = MmioRead64 (Address);\r
+ } else {\r
+ MmioWrite64 (Address, *(UINT64*)Data);\r
+ }\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Do OR operation with the value of the specified SD host controller mmio register.\r
+\r
+ @param[in] Address The address of the mmio register to be read/written.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2 , 4 or 8 bytes.\r
+ @param[in] OrData The pointer to the data used to do OR operation.\r
+ The caller is responsible for having ownership of\r
+ the data buffer and ensuring its size not less than\r
+ Count bytes.\r
+\r
+ @retval EFI_INVALID_PARAMETER The Address or the OrData or the Count is not valid.\r
+ @retval EFI_SUCCESS The OR operation succeeds.\r
+ @retval Others The OR operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdPeimHcOrMmio (\r
+ IN UINTN Address,\r
+ IN UINT8 Count,\r
+ IN VOID *OrData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 Data;\r
+ UINT64 Or;\r
+\r
+ Status = SdPeimHcRwMmio (Address, TRUE, Count, &Data);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Count == 1) {\r
+ Or = *(UINT8*) OrData;\r
+ } else if (Count == 2) {\r
+ Or = *(UINT16*) OrData;\r
+ } else if (Count == 4) {\r
+ Or = *(UINT32*) OrData;\r
+ } else if (Count == 8) {\r
+ Or = *(UINT64*) OrData;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Data |= Or;\r
+ Status = SdPeimHcRwMmio (Address, FALSE, Count, &Data);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Do AND operation with the value of the specified SD host controller mmio register.\r
+\r
+ @param[in] Address The address of the mmio register to be read/written.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2 , 4 or 8 bytes.\r
+ @param[in] AndData The pointer to the data used to do AND operation.\r
+ The caller is responsible for having ownership of\r
+ the data buffer and ensuring its size not less than\r
+ Count bytes.\r
+\r
+ @retval EFI_INVALID_PARAMETER The Address or the AndData or the Count is not valid.\r
+ @retval EFI_SUCCESS The AND operation succeeds.\r
+ @retval Others The AND operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdPeimHcAndMmio (\r
+ IN UINTN Address,\r
+ IN UINT8 Count,\r
+ IN VOID *AndData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 Data;\r
+ UINT64 And;\r
+\r
+ Status = SdPeimHcRwMmio (Address, TRUE, Count, &Data);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Count == 1) {\r
+ And = *(UINT8*) AndData;\r
+ } else if (Count == 2) {\r
+ And = *(UINT16*) AndData;\r
+ } else if (Count == 4) {\r
+ And = *(UINT32*) AndData;\r
+ } else if (Count == 8) {\r
+ And = *(UINT64*) AndData;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Data &= And;\r
+ Status = SdPeimHcRwMmio (Address, FALSE, Count, &Data);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Wait for the value of the specified MMIO register set to the test value.\r
+\r
+ @param[in] Address The address of the mmio register to be checked.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2, 4 or 8 bytes.\r
+ @param[in] MaskValue The mask value of memory.\r
+ @param[in] TestValue The test value of memory.\r
+\r
+ @retval EFI_NOT_READY The MMIO register hasn't set to the expected value.\r
+ @retval EFI_SUCCESS The MMIO register has expected value.\r
+ @retval Others The MMIO operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdPeimHcCheckMmioSet (\r
+ IN UINTN Address,\r
+ IN UINT8 Count,\r
+ IN UINT64 MaskValue,\r
+ IN UINT64 TestValue\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 Value;\r
+\r
+ //\r
+ // Access PCI MMIO space to see if the value is the tested one.\r
+ //\r
+ Value = 0;\r
+ Status = SdPeimHcRwMmio (Address, TRUE, Count, &Value);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Value &= MaskValue;\r
+\r
+ if (Value == TestValue) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return EFI_NOT_READY;\r
+}\r
+\r
+/**\r
+ Wait for the value of the specified MMIO register set to the test value.\r
+\r
+ @param[in] Address The address of the mmio register to wait.\r
+ @param[in] Count The width of the mmio register in bytes.\r
+ Must be 1, 2, 4 or 8 bytes.\r
+ @param[in] MaskValue The mask value of memory.\r
+ @param[in] TestValue The test value of memory.\r
+ @param[in] Timeout The time out value for wait memory set, uses 1\r
+ microsecond as a unit.\r
+\r
+ @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout\r
+ range.\r
+ @retval EFI_SUCCESS The MMIO register has expected value.\r
+ @retval Others The MMIO operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdPeimHcWaitMmioSet (\r
+ IN UINTN Address,\r
+ IN UINT8 Count,\r
+ IN UINT64 MaskValue,\r
+ IN UINT64 TestValue,\r
+ IN UINT64 Timeout\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN InfiniteWait;\r
+\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
+\r
+ while (InfiniteWait || (Timeout > 0)) {\r
+ Status = SdPeimHcCheckMmioSet (\r
+ Address,\r
+ Count,\r
+ MaskValue,\r
+ TestValue\r
+ );\r
+ if (Status != EFI_NOT_READY) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Stall for 1 microsecond.\r
+ //\r
+ MicroSecondDelay (1);\r
+\r
+ Timeout--;\r
+ }\r
+\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+ Software reset the specified SD host controller and enable all interrupts.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The software reset executes successfully.\r
+ @retval Others The software reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcReset (\r
+ IN UINTN Bar\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 SwReset;\r
+\r
+ SwReset = 0xFF;\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimHcReset: write full 1 fails: %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ Status = SdPeimHcWaitMmioSet (\r
+ Bar + SD_HC_SW_RST,\r
+ sizeof (SwReset),\r
+ 0xFF,\r
+ 0x00,\r
+ SD_TIMEOUT\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "SdPeimHcReset: reset done with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Enable all interrupt after reset all.\r
+ //\r
+ Status = SdPeimHcEnableInterrupt (Bar);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set all interrupt status bits in Normal and Error Interrupt Status Enable\r
+ register.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The operation executes successfully.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcEnableInterrupt (\r
+ IN UINTN Bar\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 IntStatus;\r
+\r
+ //\r
+ // Enable all bits in Error Interrupt Status Enable Register\r
+ //\r
+ IntStatus = 0xFFFF;\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_ERR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Enable all bits in Normal Interrupt Status Enable Register\r
+ //\r
+ IntStatus = 0xFFFF;\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get the capability data from the specified slot.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[out] Capability The buffer to store the capability data.\r
+\r
+ @retval EFI_SUCCESS The operation executes successfully.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcGetCapability (\r
+ IN UINTN Bar,\r
+ OUT SD_HC_SLOT_CAP *Capability\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 Cap;\r
+\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_CAP, TRUE, sizeof (Cap), &Cap);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ CopyMem (Capability, &Cap, sizeof (Cap));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Detect whether there is a SD card attached at the specified SD host controller\r
+ slot.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS There is a SD card attached.\r
+ @retval EFI_NO_MEDIA There is not a SD card attached.\r
+ @retval Others The detection fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcCardDetect (\r
+ IN UINTN Bar\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 Data;\r
+ UINT32 PresentState;\r
+\r
+ //\r
+ // Check Normal Interrupt Status Register\r
+ //\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, TRUE, sizeof (Data), &Data);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((Data & (BIT6 | BIT7)) != 0) {\r
+ //\r
+ // Clear BIT6 and BIT7 by writing 1 to these two bits if set.\r
+ //\r
+ Data &= BIT6 | BIT7;\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, FALSE, sizeof (Data), &Data);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Check Present State Register to see if there is a card presented.\r
+ //\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((PresentState & BIT16) != 0) {\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ return EFI_NO_MEDIA;\r
+ }\r
+}\r
+\r
+/**\r
+ Stop SD card clock.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS Succeed to stop SD clock.\r
+ @retval Others Fail to stop SD clock.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcStopClock (\r
+ IN UINTN Bar\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 PresentState;\r
+ UINT16 ClockCtrl;\r
+\r
+ //\r
+ // Ensure no SD transactions are occurring on the SD Bus by\r
+ // waiting for Command Inhibit (DAT) and Command Inhibit (CMD)\r
+ // in the Present State register to be 0.\r
+ //\r
+ Status = SdPeimHcWaitMmioSet (\r
+ Bar + SD_HC_PRESENT_STATE,\r
+ sizeof (PresentState),\r
+ BIT0 | BIT1,\r
+ 0,\r
+ SD_TIMEOUT\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Set SD Clock Enable in the Clock Control register to 0\r
+ //\r
+ ClockCtrl = (UINT16)~BIT2;\r
+ Status = SdPeimHcAndMmio (Bar + SD_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ SD card clock supply.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.\r
+\r
+ @retval EFI_SUCCESS The clock is supplied successfully.\r
+ @retval Others The clock isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcClockSupply (\r
+ IN UINTN Bar,\r
+ IN UINT64 ClockFreq\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_HC_SLOT_CAP Capability;\r
+ UINT32 BaseClkFreq;\r
+ UINT32 SettingFreq;\r
+ UINT32 Divisor;\r
+ UINT32 Remainder;\r
+ UINT16 ControllerVer;\r
+ UINT16 ClockCtrl;\r
+\r
+ //\r
+ // Calculate a divisor for SD clock frequency\r
+ //\r
+ Status = SdPeimHcGetCapability (Bar, &Capability);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ ASSERT (Capability.BaseClkFreq != 0);\r
+\r
+ BaseClkFreq = Capability.BaseClkFreq;\r
+ if ((ClockFreq > (BaseClkFreq * 1000)) || (ClockFreq == 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Calculate the divisor of base frequency.\r
+ //\r
+ Divisor = 0;\r
+ SettingFreq = BaseClkFreq * 1000;\r
+ while (ClockFreq < SettingFreq) {\r
+ Divisor++;\r
+\r
+ SettingFreq = (BaseClkFreq * 1000) / (2 * Divisor);\r
+ Remainder = (BaseClkFreq * 1000) % (2 * Divisor);\r
+ if ((ClockFreq == SettingFreq) && (Remainder == 0)) {\r
+ break;\r
+ }\r
+ if ((ClockFreq == SettingFreq) && (Remainder != 0)) {\r
+ SettingFreq ++;\r
+ }\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq));\r
+\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register.\r
+ //\r
+ if ((ControllerVer & 0xFF) == 2) {\r
+ ASSERT (Divisor <= 0x3FF);\r
+ ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2);\r
+ } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {\r
+ //\r
+ // Only the most significant bit can be used as divisor.\r
+ //\r
+ if (((Divisor - 1) & Divisor) != 0) {\r
+ Divisor = 1 << (HighBitSet32 (Divisor) + 1);\r
+ }\r
+ ASSERT (Divisor <= 0x80);\r
+ ClockCtrl = (Divisor & 0xFF) << 8;\r
+ } else {\r
+ DEBUG ((EFI_D_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Stop bus clock at first\r
+ //\r
+ Status = SdPeimHcStopClock (Bar);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Supply clock frequency with specified divisor\r
+ //\r
+ ClockCtrl |= BIT0;\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n"));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Wait Internal Clock Stable in the Clock Control register to be 1\r
+ //\r
+ Status = SdPeimHcWaitMmioSet (\r
+ Bar + SD_HC_CLOCK_CTRL,\r
+ sizeof (ClockCtrl),\r
+ BIT1,\r
+ BIT1,\r
+ SD_TIMEOUT\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Set SD Clock Enable in the Clock Control register to 1\r
+ //\r
+ ClockCtrl = BIT2;\r
+ Status = SdPeimHcOrMmio (Bar + SD_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ SD bus power control.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] PowerCtrl The value setting to the power control register.\r
+\r
+ @retval TRUE There is a SD card attached.\r
+ @retval FALSE There is no a SD card attached.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcPowerControl (\r
+ IN UINTN Bar,\r
+ IN UINT8 PowerCtrl\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Clr SD Bus Power\r
+ //\r
+ PowerCtrl &= (UINT8)~BIT0;\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register\r
+ //\r
+ PowerCtrl |= BIT0;\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set the SD bus width.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] BusWidth The bus width used by the SD device, it must be 1, 4 or 8.\r
+\r
+ @retval EFI_SUCCESS The bus width is set successfully.\r
+ @retval Others The bus width isn't set successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcSetBusWidth (\r
+ IN UINTN Bar,\r
+ IN UINT16 BusWidth\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 HostCtrl1;\r
+\r
+ if (BusWidth == 1) {\r
+ HostCtrl1 = (UINT8)~(BIT5 | BIT1);\r
+ Status = SdPeimHcAndMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ } else if (BusWidth == 4) {\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ HostCtrl1 |= BIT1;\r
+ HostCtrl1 &= (UINT8)~BIT5;\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);\r
+ } else if (BusWidth == 8) {\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ HostCtrl1 &= (UINT8)~BIT1;\r
+ HostCtrl1 |= BIT5;\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);\r
+ } else {\r
+ ASSERT (FALSE);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Supply SD card with lowest clock frequency at initialization.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The clock is supplied successfully.\r
+ @retval Others The clock isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcInitClockFreq (\r
+ IN UINTN Bar\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_HC_SLOT_CAP Capability;\r
+ UINT32 InitFreq;\r
+\r
+ //\r
+ // Calculate a divisor for SD clock frequency\r
+ //\r
+ Status = SdPeimHcGetCapability (Bar, &Capability);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Capability.BaseClkFreq == 0) {\r
+ //\r
+ // Don't support get Base Clock Frequency information via another method\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Supply 400KHz clock frequency at initialization phase.\r
+ //\r
+ InitFreq = 400;\r
+ Status = SdPeimHcClockSupply (Bar, InitFreq);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Supply SD card with maximum voltage at initialization.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The voltage is supplied successfully.\r
+ @retval Others The voltage isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcInitPowerVoltage (\r
+ IN UINTN Bar\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_HC_SLOT_CAP Capability;\r
+ UINT8 MaxVoltage;\r
+ UINT8 HostCtrl2;\r
+\r
+ //\r
+ // Get the support voltage of the Host Controller\r
+ //\r
+ Status = SdPeimHcGetCapability (Bar, &Capability);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Calculate supported maximum voltage according to SD Bus Voltage Select\r
+ //\r
+ if (Capability.Voltage33 != 0) {\r
+ //\r
+ // Support 3.3V\r
+ //\r
+ MaxVoltage = 0x0E;\r
+ } else if (Capability.Voltage30 != 0) {\r
+ //\r
+ // Support 3.0V\r
+ //\r
+ MaxVoltage = 0x0C;\r
+ } else if (Capability.Voltage18 != 0) {\r
+ //\r
+ // Support 1.8V\r
+ //\r
+ MaxVoltage = 0x0A;\r
+ HostCtrl2 = BIT3;\r
+ Status = SdPeimHcOrMmio (Bar + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ MicroSecondDelay (5000);\r
+ } else {\r
+ ASSERT (FALSE);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register\r
+ //\r
+ Status = SdPeimHcPowerControl (Bar, MaxVoltage);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Initialize the Timeout Control register with most conservative value at initialization.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The timeout control register is configured successfully.\r
+ @retval Others The timeout control register isn't configured successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcInitTimeoutCtrl (\r
+ IN UINTN Bar\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Timeout;\r
+\r
+ Timeout = 0x0E;\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_TIMEOUT_CTRL, FALSE, sizeof (Timeout), &Timeout);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Initial SD host controller with lowest clock frequency, max power and max timeout value\r
+ at initialization.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The host controller is initialized successfully.\r
+ @retval Others The host controller isn't initialized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcInitHost (\r
+ IN UINTN Bar\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = SdPeimHcInitClockFreq (Bar);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = SdPeimHcInitPowerVoltage (Bar);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = SdPeimHcInitTimeoutCtrl (Bar);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Turn on/off LED.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] On The boolean to turn on/off LED.\r
+\r
+ @retval EFI_SUCCESS The LED is turned on/off successfully.\r
+ @retval Others The LED isn't turned on/off successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcLedOnOff (\r
+ IN UINTN Bar,\r
+ IN BOOLEAN On\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 HostCtrl1;\r
+\r
+ if (On) {\r
+ HostCtrl1 = BIT0;\r
+ Status = SdPeimHcOrMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ } else {\r
+ HostCtrl1 = (UINT8)~BIT0;\r
+ Status = SdPeimHcAndMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Build ADMA descriptor table for transfer.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details.\r
+\r
+ @param[in] Trb The pointer to the SD_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The ADMA descriptor table is created successfully.\r
+ @retval Others The ADMA descriptor table isn't created successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+BuildAdmaDescTable (\r
+ IN SD_TRB *Trb\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS Data;\r
+ UINT64 DataLen;\r
+ UINT64 Entries;\r
+ UINT32 Index;\r
+ UINT64 Remaining;\r
+ UINT32 Address;\r
+\r
+ Data = (EFI_PHYSICAL_ADDRESS)(UINTN)Trb->Data;\r
+ DataLen = Trb->DataLen;\r
+ //\r
+ // Only support 32bit ADMA Descriptor Table\r
+ //\r
+ if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)\r
+ // for 32-bit address descriptor table.\r
+ //\r
+ if ((Data & (BIT0 | BIT1)) != 0) {\r
+ DEBUG ((EFI_D_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));\r
+ }\r
+\r
+ Entries = DivU64x32 ((DataLen + ADMA_MAX_DATA_PER_LINE - 1), ADMA_MAX_DATA_PER_LINE);\r
+\r
+ Trb->AdmaDescSize = (UINTN)MultU64x32 (Entries, sizeof (SD_HC_ADMA_DESC_LINE));\r
+ Trb->AdmaDesc = SdPeimAllocateMem (Trb->Slot->Private->Pool, Trb->AdmaDescSize);\r
+ if (Trb->AdmaDesc == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Remaining = DataLen;\r
+ Address = (UINT32)Data;\r
+ for (Index = 0; Index < Entries; Index++) {\r
+ if (Remaining <= ADMA_MAX_DATA_PER_LINE) {\r
+ Trb->AdmaDesc[Index].Valid = 1;\r
+ Trb->AdmaDesc[Index].Act = 2;\r
+ Trb->AdmaDesc[Index].Length = (UINT16)Remaining;\r
+ Trb->AdmaDesc[Index].Address = Address;\r
+ break;\r
+ } else {\r
+ Trb->AdmaDesc[Index].Valid = 1;\r
+ Trb->AdmaDesc[Index].Act = 2;\r
+ Trb->AdmaDesc[Index].Length = 0;\r
+ Trb->AdmaDesc[Index].Address = Address;\r
+ }\r
+\r
+ Remaining -= ADMA_MAX_DATA_PER_LINE;\r
+ Address += ADMA_MAX_DATA_PER_LINE;\r
+ }\r
+\r
+ //\r
+ // Set the last descriptor line as end of descriptor table\r
+ //\r
+ Trb->AdmaDesc[Index].End = 1;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Create a new TRB for the SD cmd request.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Packet A pointer to the SD command data structure.\r
+\r
+ @return Created Trb or NULL.\r
+\r
+**/\r
+SD_TRB *\r
+SdPeimCreateTrb (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN SD_COMMAND_PACKET *Packet\r
+ )\r
+{\r
+ SD_TRB *Trb;\r
+ EFI_STATUS Status;\r
+ SD_HC_SLOT_CAP Capability;\r
+\r
+ //\r
+ // Calculate a divisor for SD clock frequency\r
+ //\r
+ Status = SdPeimHcGetCapability (Slot->SdHcBase, &Capability);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ Trb = SdPeimAllocateMem (Slot->Private->Pool, sizeof (SD_TRB));\r
+ if (Trb == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Trb->Slot = Slot;\r
+ Trb->BlockSize = 0x200;\r
+ Trb->Packet = Packet;\r
+ Trb->Timeout = Packet->Timeout;\r
+\r
+ if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {\r
+ Trb->Data = Packet->InDataBuffer;\r
+ Trb->DataLen = Packet->InTransferLength;\r
+ Trb->Read = TRUE;\r
+ } else if ((Packet->OutTransferLength != 0) && (Packet->OutDataBuffer != NULL)) {\r
+ Trb->Data = Packet->OutDataBuffer;\r
+ Trb->DataLen = Packet->OutTransferLength;\r
+ Trb->Read = FALSE;\r
+ } else if ((Packet->InTransferLength == 0) && (Packet->OutTransferLength == 0)) {\r
+ Trb->Data = NULL;\r
+ Trb->DataLen = 0;\r
+ } else {\r
+ goto Error;\r
+ }\r
+\r
+ if ((Trb->DataLen % Trb->BlockSize) != 0) {\r
+ if (Trb->DataLen < Trb->BlockSize) {\r
+ Trb->BlockSize = (UINT16)Trb->DataLen;\r
+ }\r
+ }\r
+\r
+ if (Trb->DataLen == 0) {\r
+ Trb->Mode = SdNoData;\r
+ } else if (Capability.Adma2 != 0) {\r
+ Trb->Mode = SdAdmaMode;\r
+ Status = BuildAdmaDescTable (Trb);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ } else if (Capability.Sdma != 0) {\r
+ Trb->Mode = SdSdmaMode;\r
+ } else {\r
+ Trb->Mode = SdPioMode;\r
+ }\r
+\r
+ return Trb;\r
+\r
+Error:\r
+ SdPeimFreeTrb (Trb);\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Free the resource used by the TRB.\r
+\r
+ @param[in] Trb The pointer to the SD_TRB instance.\r
+\r
+**/\r
+VOID\r
+SdPeimFreeTrb (\r
+ IN SD_TRB *Trb\r
+ )\r
+{\r
+ if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) {\r
+ SdPeimFreeMem (Trb->Slot->Private->Pool, Trb->AdmaDesc, Trb->AdmaDescSize);\r
+ }\r
+\r
+ if (Trb != NULL) {\r
+ SdPeimFreeMem (Trb->Slot->Private->Pool, Trb, sizeof (SD_TRB));\r
+ }\r
+ return;\r
+}\r
+\r
+/**\r
+ Check if the env is ready for execute specified TRB.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] Trb The pointer to the SD_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The env is ready for TRB execution.\r
+ @retval EFI_NOT_READY The env is not ready for TRB execution.\r
+ @retval Others Some erros happen.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimCheckTrbEnv (\r
+ IN UINTN Bar,\r
+ IN SD_TRB *Trb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_COMMAND_PACKET *Packet;\r
+ UINT32 PresentState;\r
+\r
+ Packet = Trb->Packet;\r
+\r
+ if ((Packet->SdCmdBlk->CommandType == SdCommandTypeAdtc) ||\r
+ (Packet->SdCmdBlk->ResponseType == SdResponseTypeR1b) ||\r
+ (Packet->SdCmdBlk->ResponseType == SdResponseTypeR5b)) {\r
+ //\r
+ // Wait Command Inhibit (CMD) and Command Inhibit (DAT) in\r
+ // the Present State register to be 0\r
+ //\r
+ PresentState = BIT0 | BIT1;\r
+ if (Packet->SdCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK) {\r
+ PresentState = BIT0;\r
+ }\r
+ } else {\r
+ //\r
+ // Wait Command Inhibit (CMD) in the Present State register\r
+ // to be 0\r
+ //\r
+ PresentState = BIT0;\r
+ }\r
+\r
+ Status = SdPeimHcCheckMmioSet (\r
+ Bar + SD_HC_PRESENT_STATE,\r
+ sizeof (PresentState),\r
+ PresentState,\r
+ 0\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Wait for the env to be ready for execute specified TRB.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] Trb The pointer to the SD_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The env is ready for TRB execution.\r
+ @retval EFI_TIMEOUT The env is not ready for TRB execution in time.\r
+ @retval Others Some erros happen.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimWaitTrbEnv (\r
+ IN UINTN Bar,\r
+ IN SD_TRB *Trb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_COMMAND_PACKET *Packet;\r
+ UINT64 Timeout;\r
+ BOOLEAN InfiniteWait;\r
+\r
+ //\r
+ // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register\r
+ //\r
+ Packet = Trb->Packet;\r
+ Timeout = Packet->Timeout;\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
+\r
+ while (InfiniteWait || (Timeout > 0)) {\r
+ //\r
+ // Check Trb execution result by reading Normal Interrupt Status register.\r
+ //\r
+ Status = SdPeimCheckTrbEnv (Bar, Trb);\r
+ if (Status != EFI_NOT_READY) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Stall for 1 microsecond.\r
+ //\r
+ MicroSecondDelay (1);\r
+\r
+ Timeout--;\r
+ }\r
+\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+ Execute the specified TRB.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] Trb The pointer to the SD_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The TRB is sent to host controller successfully.\r
+ @retval Others Some erros happen when sending this request to the host controller.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimExecTrb (\r
+ IN UINTN Bar,\r
+ IN SD_TRB *Trb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_COMMAND_PACKET *Packet;\r
+ UINT16 Cmd;\r
+ UINT16 IntStatus;\r
+ UINT32 Argument;\r
+ UINT16 BlkCount;\r
+ UINT16 BlkSize;\r
+ UINT16 TransMode;\r
+ UINT8 HostCtrl1;\r
+ UINT32 SdmaAddr;\r
+ UINT64 AdmaAddr;\r
+\r
+ Packet = Trb->Packet;\r
+ //\r
+ // Clear all bits in Error Interrupt Status Register\r
+ //\r
+ IntStatus = 0xFFFF;\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_ERR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Clear all bits in Normal Interrupt Status Register\r
+ //\r
+ IntStatus = 0xFFFF;\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Set Host Control 1 register DMA Select field\r
+ //\r
+ if (Trb->Mode == SdAdmaMode) {\r
+ HostCtrl1 = BIT4;\r
+ Status = SdPeimHcOrMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ SdPeimHcLedOnOff (Bar, TRUE);\r
+\r
+ if (Trb->Mode == SdSdmaMode) {\r
+ if ((UINT64)(UINTN)Trb->Data >= 0x100000000ul) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ SdmaAddr = (UINT32)(UINTN)Trb->Data;\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ } else if (Trb->Mode == SdAdmaMode) {\r
+ AdmaAddr = (UINT64)(UINTN)Trb->AdmaDesc;\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ BlkSize = Trb->BlockSize;\r
+ if (Trb->Mode == SdSdmaMode) {\r
+ //\r
+ // Set SDMA boundary to be 512K bytes.\r
+ //\r
+ BlkSize |= 0x7000;\r
+ }\r
+\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_BLK_SIZE, FALSE, sizeof (BlkSize), &BlkSize);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Argument = Packet->SdCmdBlk->CommandArgument;\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_ARG1, FALSE, sizeof (Argument), &Argument);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ TransMode = 0;\r
+ if (Trb->Mode != SdNoData) {\r
+ if (Trb->Mode != SdPioMode) {\r
+ TransMode |= BIT0;\r
+ }\r
+ if (Trb->Read) {\r
+ TransMode |= BIT4;\r
+ }\r
+ if (BlkCount != 0) {\r
+ TransMode |= BIT5 | BIT1;\r
+ }\r
+ if (BlkCount > 1) {\r
+ TransMode |= BIT2;\r
+ }\r
+ }\r
+\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_TRANS_MOD, FALSE, sizeof (TransMode), &TransMode);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Cmd = (UINT16)LShiftU64(Packet->SdCmdBlk->CommandIndex, 8);\r
+ if (Packet->SdCmdBlk->CommandType == SdCommandTypeAdtc) {\r
+ Cmd |= BIT5;\r
+ }\r
+ //\r
+ // Convert ResponseType to value\r
+ //\r
+ if (Packet->SdCmdBlk->CommandType != SdCommandTypeBc) {\r
+ switch (Packet->SdCmdBlk->ResponseType) {\r
+ case SdResponseTypeR1:\r
+ case SdResponseTypeR5:\r
+ case SdResponseTypeR6:\r
+ case SdResponseTypeR7:\r
+ Cmd |= (BIT1 | BIT3 | BIT4);\r
+ break;\r
+ case SdResponseTypeR2:\r
+ Cmd |= (BIT0 | BIT3);\r
+ break;\r
+ case SdResponseTypeR3:\r
+ case SdResponseTypeR4:\r
+ Cmd |= BIT1;\r
+ break;\r
+ case SdResponseTypeR1b:\r
+ case SdResponseTypeR5b:\r
+ Cmd |= (BIT0 | BIT1 | BIT3 | BIT4);\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // Execute cmd\r
+ //\r
+ Status = SdPeimHcRwMmio (Bar + SD_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Check the TRB execution result.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] Trb The pointer to the SD_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The TRB is executed successfully.\r
+ @retval EFI_NOT_READY The TRB is not completed for execution.\r
+ @retval Others Some erros happen when executing this request.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimCheckTrbResult (\r
+ IN UINTN Bar,\r
+ IN SD_TRB *Trb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_COMMAND_PACKET *Packet;\r
+ UINT16 IntStatus;\r
+ UINT32 Response[4];\r
+ UINT32 SdmaAddr;\r
+ UINT8 Index;\r
+ UINT8 SwReset;\r
+\r
+ SwReset = 0;\r
+ Packet = Trb->Packet;\r
+ //\r
+ // Check Trb execution result by reading Normal Interrupt Status register.\r
+ //\r
+ Status = SdPeimHcRwMmio (\r
+ Bar + SD_HC_NOR_INT_STS,\r
+ TRUE,\r
+ sizeof (IntStatus),\r
+ &IntStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Check Transfer Complete bit is set or not.\r
+ //\r
+ if ((IntStatus & BIT1) == BIT1) {\r
+ if ((IntStatus & BIT15) == BIT15) {\r
+ //\r
+ // Read Error Interrupt Status register to check if the error is\r
+ // Data Timeout Error.\r
+ // If yes, treat it as success as Transfer Complete has higher\r
+ // priority than Data Timeout Error.\r
+ //\r
+ Status = SdPeimHcRwMmio (\r
+ Bar + SD_HC_ERR_INT_STS,\r
+ TRUE,\r
+ sizeof (IntStatus),\r
+ &IntStatus\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ if ((IntStatus & BIT4) == BIT4) {\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+ }\r
+\r
+ goto Done;\r
+ }\r
+ //\r
+ // Check if there is a error happened during cmd execution.\r
+ // If yes, then do error recovery procedure to follow SD Host Controller\r
+ // Simplified Spec 3.0 section 3.10.1.\r
+ //\r
+ if ((IntStatus & BIT15) == BIT15) {\r
+ Status = SdPeimHcRwMmio (\r
+ Bar + SD_HC_ERR_INT_STS,\r
+ TRUE,\r
+ sizeof (IntStatus),\r
+ &IntStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ if ((IntStatus & 0x0F) != 0) {\r
+ SwReset |= BIT1;\r
+ }\r
+ if ((IntStatus & 0xF0) != 0) {\r
+ SwReset |= BIT2;\r
+ }\r
+\r
+ Status = SdPeimHcRwMmio (\r
+ Bar + SD_HC_SW_RST,\r
+ FALSE,\r
+ sizeof (SwReset),\r
+ &SwReset\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ Status = SdPeimHcWaitMmioSet (\r
+ Bar + SD_HC_SW_RST,\r
+ sizeof (SwReset),\r
+ 0xFF,\r
+ 0,\r
+ SD_TIMEOUT\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+ //\r
+ // Check if DMA interrupt is signalled for the SDMA transfer.\r
+ //\r
+ if ((Trb->Mode == SdSdmaMode) && ((IntStatus & BIT3) == BIT3)) {\r
+ //\r
+ // Clear DMA interrupt bit.\r
+ //\r
+ IntStatus = BIT3;\r
+ Status = SdPeimHcRwMmio (\r
+ Bar + SD_HC_NOR_INT_STS,\r
+ FALSE,\r
+ sizeof (IntStatus),\r
+ &IntStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Update SDMA Address register.\r
+ //\r
+ SdmaAddr = SD_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->Data, SD_SDMA_BOUNDARY);\r
+ Status = SdPeimHcRwMmio (\r
+ Bar + SD_HC_SDMA_ADDR,\r
+ FALSE,\r
+ sizeof (UINT32),\r
+ &SdmaAddr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ Trb->Data = (VOID*)(UINTN)SdmaAddr;\r
+ }\r
+\r
+ if ((Packet->SdCmdBlk->CommandType != SdCommandTypeAdtc) &&\r
+ (Packet->SdCmdBlk->ResponseType != SdResponseTypeR1b) &&\r
+ (Packet->SdCmdBlk->ResponseType != SdResponseTypeR5b)) {\r
+ if ((IntStatus & BIT0) == BIT0) {\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ if (Packet->SdCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK) {\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+ Status = EFI_NOT_READY;\r
+Done:\r
+ //\r
+ // Get response data when the cmd is executed successfully.\r
+ //\r
+ if (!EFI_ERROR (Status)) {\r
+ if (Packet->SdCmdBlk->CommandType != SdCommandTypeBc) {\r
+ for (Index = 0; Index < 4; Index++) {\r
+ Status = SdPeimHcRwMmio (\r
+ Bar + SD_HC_RESPONSE + Index * 4,\r
+ TRUE,\r
+ sizeof (UINT32),\r
+ &Response[Index]\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ SdPeimHcLedOnOff (Bar, FALSE);\r
+ return Status;\r
+ }\r
+ }\r
+ CopyMem (Packet->SdStatusBlk, Response, sizeof (Response));\r
+ }\r
+ }\r
+\r
+ if (Status != EFI_NOT_READY) {\r
+ SdPeimHcLedOnOff (Bar, FALSE);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Wait for the TRB execution result.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[in] Trb The pointer to the SD_TRB instance.\r
+\r
+ @retval EFI_SUCCESS The TRB is executed successfully.\r
+ @retval Others Some erros happen when executing this request.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimWaitTrbResult (\r
+ IN UINTN Bar,\r
+ IN SD_TRB *Trb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_COMMAND_PACKET *Packet;\r
+ UINT64 Timeout;\r
+ BOOLEAN InfiniteWait;\r
+\r
+ Packet = Trb->Packet;\r
+ //\r
+ // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register\r
+ //\r
+ Timeout = Packet->Timeout;\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
+\r
+ while (InfiniteWait || (Timeout > 0)) {\r
+ //\r
+ // Check Trb execution result by reading Normal Interrupt Status register.\r
+ //\r
+ Status = SdPeimCheckTrbResult (Bar, Trb);\r
+ if (Status != EFI_NOT_READY) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Stall for 1 microsecond.\r
+ //\r
+ MicroSecondDelay (1);\r
+\r
+ Timeout--;\r
+ }\r
+\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+ Sends SD command to an SD card that is attached to the SD controller.\r
+\r
+ If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.\r
+\r
+ If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.\r
+\r
+ If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER\r
+ is returned.\r
+\r
+ If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,\r
+ EFI_INVALID_PARAMETER is returned.\r
+\r
+ @param[in] Slot The slot number of the Sd card to send the command to.\r
+ @param[in,out] Packet A pointer to the SD command data structure.\r
+\r
+ @retval EFI_SUCCESS The SD Command Packet was sent by the host.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD\r
+ command Packet.\r
+ @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.\r
+ @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and\r
+ OutDataBuffer are NULL.\r
+ @retval EFI_NO_MEDIA SD Device not present in the Slot.\r
+ @retval EFI_UNSUPPORTED The command described by the SD Command Packet is not\r
+ supported by the host controller.\r
+ @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the\r
+ limit supported by SD card ( i.e. if the number of bytes\r
+ exceed the Last LBA).\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdPeimExecCmd (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN OUT SD_COMMAND_PACKET *Packet\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_TRB *Trb;\r
+\r
+ if (Packet == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Packet->SdCmdBlk == NULL) || (Packet->SdStatusBlk == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Trb = SdPeimCreateTrb (Slot, Packet);\r
+ if (Trb == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = SdPeimWaitTrbEnv (Slot->SdHcBase, Trb);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = SdPeimExecTrb (Slot->SdHcBase, Trb);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = SdPeimWaitTrbResult (Slot->SdHcBase, Trb);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+Done:\r
+ SdPeimFreeTrb (Trb);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command GO_IDLE_STATE to the device to make it go to Idle State.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The SD device is reset correctly.\r
+ @retval Others The device reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimReset (\r
+ IN SD_PEIM_HC_SLOT *Slot\r
+ )\r
+{\r
+ SD_COMMAND_BLOCK SdCmdBlk;\r
+ SD_STATUS_BLOCK SdStatusBlk;\r
+ SD_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdCmdBlk = &SdCmdBlk;\r
+ Packet.SdStatusBlk = &SdStatusBlk;\r
+ Packet.Timeout = SD_TIMEOUT;\r
+\r
+ SdCmdBlk.CommandIndex = SD_GO_IDLE_STATE;\r
+ SdCmdBlk.CommandType = SdCommandTypeBc;\r
+ SdCmdBlk.ResponseType = 0;\r
+ SdCmdBlk.CommandArgument = 0;\r
+\r
+ Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_IF_COND to the device to inquiry the SD Memory Card interface\r
+ condition.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] SupplyVoltage The supplied voltage by the host.\r
+ @param[in] CheckPattern The check pattern to be sent to the device.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimVoltageCheck (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN UINT8 SupplyVoltage,\r
+ IN UINT8 CheckPattern\r
+ )\r
+{\r
+ SD_COMMAND_BLOCK SdCmdBlk;\r
+ SD_STATUS_BLOCK SdStatusBlk;\r
+ SD_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdCmdBlk = &SdCmdBlk;\r
+ Packet.SdStatusBlk = &SdStatusBlk;\r
+ Packet.Timeout = SD_TIMEOUT;\r
+\r
+ SdCmdBlk.CommandIndex = SD_SEND_IF_COND;\r
+ SdCmdBlk.CommandType = SdCommandTypeBcr;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR7;\r
+ SdCmdBlk.CommandArgument = (SupplyVoltage << 8) | CheckPattern;\r
+\r
+ Status = SdPeimExecCmd (Slot, &Packet);\r
+ if (!EFI_ERROR (Status)) {\r
+ if (SdStatusBlk.Resp0 != SdCmdBlk.CommandArgument) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SDIO_SEND_OP_COND to the device to see whether it is SDIO device.\r
+\r
+ Refer to SDIO Simplified Spec 3 Section 3.2 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] VoltageWindow The supply voltage window.\r
+ @param[in] S18r The boolean to show if it should switch to 1.8v.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdioSendOpCond (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN UINT32 VoltageWindow,\r
+ IN BOOLEAN S18r\r
+ )\r
+{\r
+ SD_COMMAND_BLOCK SdCmdBlk;\r
+ SD_STATUS_BLOCK SdStatusBlk;\r
+ SD_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+ UINT32 Switch;\r
+\r
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdCmdBlk = &SdCmdBlk;\r
+ Packet.SdStatusBlk = &SdStatusBlk;\r
+ Packet.Timeout = SD_TIMEOUT;\r
+\r
+ SdCmdBlk.CommandIndex = SDIO_SEND_OP_COND;\r
+ SdCmdBlk.CommandType = SdCommandTypeBcr;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR4;\r
+\r
+ Switch = S18r ? BIT24 : 0;\r
+\r
+ SdCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch;\r
+\r
+ Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SD_SEND_OP_COND to the device to see whether it is SDIO device.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address of addressed device.\r
+ @param[in] VoltageWindow The supply voltage window.\r
+ @param[in] S18r The boolean to show if it should switch to 1.8v.\r
+ @param[in] Xpc The boolean to show if it should provide 0.36w power control.\r
+ @param[in] Hcs The boolean to show if it support host capacity info.\r
+ @param[out] Ocr The buffer to store returned OCR register value.\r
+\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSendOpCond (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN UINT16 Rca,\r
+ IN UINT32 VoltageWindow,\r
+ IN BOOLEAN S18r,\r
+ IN BOOLEAN Xpc,\r
+ IN BOOLEAN Hcs,\r
+ OUT UINT32 *Ocr\r
+ )\r
+{\r
+ SD_COMMAND_BLOCK SdCmdBlk;\r
+ SD_STATUS_BLOCK SdStatusBlk;\r
+ SD_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+ UINT32 Switch;\r
+ UINT32 MaxPower;\r
+ UINT32 HostCapacity;\r
+\r
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdCmdBlk = &SdCmdBlk;\r
+ Packet.SdStatusBlk = &SdStatusBlk;\r
+ Packet.Timeout = SD_TIMEOUT;\r
+\r
+ SdCmdBlk.CommandIndex = SD_APP_CMD;\r
+ SdCmdBlk.CommandType = SdCommandTypeAc;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+ SdCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = SdPeimExecCmd (Slot, &Packet);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ SdCmdBlk.CommandIndex = SD_SEND_OP_COND;\r
+ SdCmdBlk.CommandType = SdCommandTypeBcr;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR3;\r
+\r
+ Switch = S18r ? BIT24 : 0;\r
+ MaxPower = Xpc ? BIT28 : 0;\r
+ HostCapacity = Hcs ? BIT30 : 0;\r
+ SdCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch | MaxPower | HostCapacity;\r
+\r
+ Status = SdPeimExecCmd (Slot, &Packet);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+ //\r
+ *Ocr = SdStatusBlk.Resp0;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Broadcast command ALL_SEND_CID to the bus to ask all the SD devices to send the\r
+ data of their CID registers.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimAllSendCid (\r
+ IN SD_PEIM_HC_SLOT *Slot\r
+ )\r
+{\r
+ SD_COMMAND_BLOCK SdCmdBlk;\r
+ SD_STATUS_BLOCK SdStatusBlk;\r
+ SD_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdCmdBlk = &SdCmdBlk;\r
+ Packet.SdStatusBlk = &SdStatusBlk;\r
+ Packet.Timeout = SD_TIMEOUT;\r
+\r
+ SdCmdBlk.CommandIndex = SD_ALL_SEND_CID;\r
+ SdCmdBlk.CommandType = SdCommandTypeBcr;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR2;\r
+ SdCmdBlk.CommandArgument = 0;\r
+\r
+ Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SET_RELATIVE_ADDR to the SD device to assign a Relative device\r
+ Address (RCA).\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[out] Rca The relative device address to be assigned.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSetRca (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ OUT UINT16 *Rca\r
+ )\r
+{\r
+ SD_COMMAND_BLOCK SdCmdBlk;\r
+ SD_STATUS_BLOCK SdStatusBlk;\r
+ SD_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdCmdBlk = &SdCmdBlk;\r
+ Packet.SdStatusBlk = &SdStatusBlk;\r
+ Packet.Timeout = SD_TIMEOUT;\r
+\r
+ SdCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;\r
+ SdCmdBlk.CommandType = SdCommandTypeBcr;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR6;\r
+\r
+ Status = SdPeimExecCmd (Slot, &Packet);\r
+ if (!EFI_ERROR (Status)) {\r
+ *Rca = (UINT16)(SdStatusBlk.Resp0 >> 16);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_CSD to the SD device to get the data of the CSD register.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address of selected device.\r
+ @param[out] Csd The buffer to store the content of the CSD register.\r
+ Note the caller should ignore the lowest byte of this\r
+ buffer as the content of this byte is meaningless even\r
+ if the operation succeeds.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimGetCsd (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN UINT16 Rca,\r
+ OUT SD_CSD *Csd\r
+ )\r
+{\r
+ SD_COMMAND_BLOCK SdCmdBlk;\r
+ SD_STATUS_BLOCK SdStatusBlk;\r
+ SD_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdCmdBlk = &SdCmdBlk;\r
+ Packet.SdStatusBlk = &SdStatusBlk;\r
+ Packet.Timeout = SD_TIMEOUT;\r
+\r
+ SdCmdBlk.CommandIndex = SD_SEND_CSD;\r
+ SdCmdBlk.CommandType = SdCommandTypeAc;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR2;\r
+ SdCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = SdPeimExecCmd (Slot, &Packet);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+ //\r
+ CopyMem (((UINT8*)Csd) + 1, &SdStatusBlk.Resp0, sizeof (SD_CSD) - 1);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SELECT_DESELECT_CARD to the SD device to select/deselect it.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address of selected device.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSelect (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN UINT16 Rca\r
+ )\r
+{\r
+ SD_COMMAND_BLOCK SdCmdBlk;\r
+ SD_STATUS_BLOCK SdStatusBlk;\r
+ SD_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdCmdBlk = &SdCmdBlk;\r
+ Packet.SdStatusBlk = &SdStatusBlk;\r
+ Packet.Timeout = SD_TIMEOUT;\r
+\r
+ SdCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;\r
+ SdCmdBlk.CommandType = SdCommandTypeAc;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR1b;\r
+ SdCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command VOLTAGE_SWITCH to the SD device to switch the voltage of the device.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimVoltageSwitch (\r
+ IN SD_PEIM_HC_SLOT *Slot\r
+ )\r
+{\r
+ SD_COMMAND_BLOCK SdCmdBlk;\r
+ SD_STATUS_BLOCK SdStatusBlk;\r
+ SD_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdCmdBlk = &SdCmdBlk;\r
+ Packet.SdStatusBlk = &SdStatusBlk;\r
+ Packet.Timeout = SD_TIMEOUT;\r
+\r
+ SdCmdBlk.CommandIndex = SD_VOLTAGE_SWITCH;\r
+ SdCmdBlk.CommandType = SdCommandTypeAc;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+ SdCmdBlk.CommandArgument = 0;\r
+\r
+ Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SET_BUS_WIDTH to the SD device to set the bus width.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address of addressed device.\r
+ @param[in] BusWidth The bus width to be set, it could be 1 or 4.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSetBusWidth (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN UINT16 Rca,\r
+ IN UINT8 BusWidth\r
+ )\r
+{\r
+ SD_COMMAND_BLOCK SdCmdBlk;\r
+ SD_STATUS_BLOCK SdStatusBlk;\r
+ SD_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+ UINT8 Value;\r
+\r
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdCmdBlk = &SdCmdBlk;\r
+ Packet.SdStatusBlk = &SdStatusBlk;\r
+ Packet.Timeout = SD_TIMEOUT;\r
+\r
+ SdCmdBlk.CommandIndex = SD_APP_CMD;\r
+ SdCmdBlk.CommandType = SdCommandTypeAc;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+ SdCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = SdPeimExecCmd (Slot, &Packet);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ SdCmdBlk.CommandIndex = SD_SET_BUS_WIDTH;\r
+ SdCmdBlk.CommandType = SdCommandTypeAc;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+\r
+ if (BusWidth == 1) {\r
+ Value = 0;\r
+ } else if (BusWidth == 4) {\r
+ Value = 2;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ SdCmdBlk.CommandArgument = Value & 0x3;\r
+\r
+ Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SWITCH_FUNC to the SD device to check switchable function or switch card function.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] AccessMode The value for access mode group.\r
+ @param[in] CommandSystem The value for command set group.\r
+ @param[in] DriveStrength The value for drive length group.\r
+ @param[in] PowerLimit The value for power limit group.\r
+ @param[in] Mode Switch or check function.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSwitch (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN UINT8 AccessMode,\r
+ IN UINT8 CommandSystem,\r
+ IN UINT8 DriveStrength,\r
+ IN UINT8 PowerLimit,\r
+ IN BOOLEAN Mode\r
+ )\r
+{\r
+ SD_COMMAND_BLOCK SdCmdBlk;\r
+ SD_STATUS_BLOCK SdStatusBlk;\r
+ SD_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+ UINT32 ModeValue;\r
+ UINT8 Data[64];\r
+\r
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdCmdBlk = &SdCmdBlk;\r
+ Packet.SdStatusBlk = &SdStatusBlk;\r
+ Packet.Timeout = SD_TIMEOUT;\r
+\r
+ SdCmdBlk.CommandIndex = SD_SWITCH_FUNC;\r
+ SdCmdBlk.CommandType = SdCommandTypeAdtc;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+\r
+ ModeValue = Mode ? BIT31 : 0;\r
+ SdCmdBlk.CommandArgument = (AccessMode & 0xF) | ((PowerLimit & 0xF) << 4) | \\r
+ ((DriveStrength & 0xF) << 8) | ((DriveStrength & 0xF) << 12) | \\r
+ ModeValue;\r
+ Packet.InDataBuffer = Data;\r
+ Packet.InTransferLength = sizeof (Data);\r
+\r
+ Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_STATUS to the addressed SD device to get its status register.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address of addressed device.\r
+ @param[out] DevStatus The returned device status.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSendStatus (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN UINT16 Rca,\r
+ OUT UINT32 *DevStatus\r
+ )\r
+{\r
+ SD_COMMAND_BLOCK SdCmdBlk;\r
+ SD_STATUS_BLOCK SdStatusBlk;\r
+ SD_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdCmdBlk = &SdCmdBlk;\r
+ Packet.SdStatusBlk = &SdStatusBlk;\r
+ Packet.Timeout = SD_TIMEOUT;\r
+\r
+ SdCmdBlk.CommandIndex = SD_SEND_STATUS;\r
+ SdCmdBlk.CommandType = SdCommandTypeAc;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+ SdCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = SdPeimExecCmd (Slot, &Packet);\r
+ if (!EFI_ERROR (Status)) {\r
+ *DevStatus = SdStatusBlk.Resp0;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command READ_SINGLE_BLOCK/WRITE_SINGLE_BLOCK to the addressed SD device\r
+ to read/write the specified number of blocks.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Lba The logical block address of starting access.\r
+ @param[in] BlockSize The block size of specified SD device partition.\r
+ @param[in] Buffer The pointer to the transfer buffer.\r
+ @param[in] BufferSize The size of transfer buffer.\r
+ @param[in] IsRead Boolean to show the operation direction.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimRwSingleBlock (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN EFI_LBA Lba,\r
+ IN UINT32 BlockSize,\r
+ IN VOID *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN BOOLEAN IsRead\r
+ )\r
+{\r
+ SD_COMMAND_BLOCK SdCmdBlk;\r
+ SD_STATUS_BLOCK SdStatusBlk;\r
+ SD_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdCmdBlk = &SdCmdBlk;\r
+ Packet.SdStatusBlk = &SdStatusBlk;\r
+ //\r
+ // Calculate timeout value through the below formula.\r
+ // Timeout = (transfer size) / (2MB/s).\r
+ // Taking 2MB/s as divisor is because it's the lowest\r
+ // transfer speed of class 2.\r
+ //\r
+ Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;;\r
+\r
+ if (IsRead) {\r
+ Packet.InDataBuffer = Buffer;\r
+ Packet.InTransferLength = (UINT32)BufferSize;\r
+\r
+ SdCmdBlk.CommandIndex = SD_READ_SINGLE_BLOCK;\r
+ SdCmdBlk.CommandType = SdCommandTypeAdtc;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+ } else {\r
+ Packet.OutDataBuffer = Buffer;\r
+ Packet.OutTransferLength = (UINT32)BufferSize;\r
+\r
+ SdCmdBlk.CommandIndex = SD_WRITE_SINGLE_BLOCK;\r
+ SdCmdBlk.CommandType = SdCommandTypeAdtc;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+ }\r
+\r
+ if (Slot->SectorAddressing) {\r
+ SdCmdBlk.CommandArgument = (UINT32)Lba;\r
+ } else {\r
+ SdCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, BlockSize);\r
+ }\r
+\r
+ Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed SD device\r
+ to read/write the specified number of blocks.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Lba The logical block address of starting access.\r
+ @param[in] BlockSize The block size of specified SD device partition.\r
+ @param[in] Buffer The pointer to the transfer buffer.\r
+ @param[in] BufferSize The size of transfer buffer.\r
+ @param[in] IsRead Boolean to show the operation direction.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimRwMultiBlocks (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN EFI_LBA Lba,\r
+ IN UINT32 BlockSize,\r
+ IN VOID *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN BOOLEAN IsRead\r
+ )\r
+{\r
+ SD_COMMAND_BLOCK SdCmdBlk;\r
+ SD_STATUS_BLOCK SdStatusBlk;\r
+ SD_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdCmdBlk = &SdCmdBlk;\r
+ Packet.SdStatusBlk = &SdStatusBlk;\r
+ //\r
+ // Calculate timeout value through the below formula.\r
+ // Timeout = (transfer size) / (2MB/s).\r
+ // Taking 2MB/s as divisor is because it's the lowest\r
+ // transfer speed of class 2.\r
+ //\r
+ Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;;\r
+\r
+ if (IsRead) {\r
+ Packet.InDataBuffer = Buffer;\r
+ Packet.InTransferLength = (UINT32)BufferSize;\r
+\r
+ SdCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK;\r
+ SdCmdBlk.CommandType = SdCommandTypeAdtc;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+ } else {\r
+ Packet.OutDataBuffer = Buffer;\r
+ Packet.OutTransferLength = (UINT32)BufferSize;\r
+\r
+ SdCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK;\r
+ SdCmdBlk.CommandType = SdCommandTypeAdtc;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+ }\r
+\r
+ if (Slot->SectorAddressing) {\r
+ SdCmdBlk.CommandArgument = (UINT32)Lba;\r
+ } else {\r
+ SdCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, BlockSize);\r
+ }\r
+\r
+ Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_TUNING_BLOCK to the SD device for SDR104/SDR50 optimal sampling point\r
+ detection.\r
+\r
+ It may be sent up to 40 times until the host finishes the tuning procedure.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSendTuningBlk (\r
+ IN SD_PEIM_HC_SLOT *Slot\r
+ )\r
+{\r
+ SD_COMMAND_BLOCK SdCmdBlk;\r
+ SD_STATUS_BLOCK SdStatusBlk;\r
+ SD_COMMAND_PACKET Packet;\r
+ EFI_STATUS Status;\r
+ UINT8 TuningBlock[64];\r
+\r
+ ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+ ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+\r
+ Packet.SdCmdBlk = &SdCmdBlk;\r
+ Packet.SdStatusBlk = &SdStatusBlk;\r
+ Packet.Timeout = SD_TIMEOUT;\r
+\r
+ SdCmdBlk.CommandIndex = SD_SEND_TUNING_BLOCK;\r
+ SdCmdBlk.CommandType = SdCommandTypeAdtc;\r
+ SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+ SdCmdBlk.CommandArgument = 0;\r
+\r
+ Packet.InDataBuffer = TuningBlock;\r
+ Packet.InTransferLength = sizeof (TuningBlock);\r
+\r
+ Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Tunning the sampling point of SDR104 or SDR50 bus speed mode.\r
+\r
+ Command SD_SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the\r
+ tuning procedure.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and SD Host Controller\r
+ Simplified Spec 3.0 Figure 2-29 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimTuningClock (\r
+ IN SD_PEIM_HC_SLOT *Slot\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 HostCtrl2;\r
+ UINT8 Retry;\r
+\r
+ //\r
+ // Notify the host that the sampling clock tuning procedure starts.\r
+ //\r
+ HostCtrl2 = BIT6;\r
+ Status = SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.\r
+ //\r
+ Retry = 0;\r
+ do {\r
+ Status = SdPeimSendTuningBlk (Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
+ break;\r
+ }\r
+ } while (++Retry < 40);\r
+\r
+ if (Retry == 40) {\r
+ Status = EFI_TIMEOUT;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Switch the bus width to specified width.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and\r
+ SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+ @param[in] BusWidth The bus width to be set, it could be 4 or 8.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSwitchBusWidth (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN UINT16 Rca,\r
+ IN UINT8 BusWidth\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 DevStatus;\r
+\r
+ Status = SdPeimSetBusWidth (Slot, Rca, BusWidth);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = SdPeimSendStatus (Slot, Rca, &DevStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Check the switch operation is really successful or not.\r
+ //\r
+ if ((DevStatus >> 16) != 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Status = SdPeimHcSetBusWidth (Slot->SdHcBase, BusWidth);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Switch the high speed timing according to request.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and\r
+ SD Host Controller Simplified Spec 3.0 section Figure 2-29 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Rca The relative device address to be assigned.\r
+ @param[in] S18a The boolean to show if it's a UHS-I SD card.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSetBusMode (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN UINT16 Rca,\r
+ IN BOOLEAN S18a\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_HC_SLOT_CAP Capability;\r
+ UINT32 ClockFreq;\r
+ UINT8 BusWidth;\r
+ UINT8 AccessMode;\r
+ UINT8 HostCtrl1;\r
+ UINT8 HostCtrl2;\r
+\r
+ Status = SdPeimGetCsd (Slot, Rca, &Slot->Csd);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimGetCsd fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ Status = SdPeimHcGetCapability (Slot->SdHcBase, &Capability);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = SdPeimSelect (Slot, Rca);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimSelect fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ BusWidth = 4;\r
+ Status = SdPeimSwitchBusWidth (Slot, Rca, BusWidth);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimSwitchBusWidth fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Calculate supported bus speed/bus width/clock frequency.\r
+ //\r
+ ClockFreq = 0;\r
+ if (S18a && (Capability.Sdr104 != 0)) {\r
+ ClockFreq = 208;\r
+ AccessMode = 3;\r
+ } else if (S18a && (Capability.Sdr50 != 0)) {\r
+ ClockFreq = 100;\r
+ AccessMode = 2;\r
+ } else if (S18a && (Capability.Ddr50 != 0)) {\r
+ ClockFreq = 50;\r
+ AccessMode = 4;\r
+ } else {\r
+ ClockFreq = 50;\r
+ AccessMode = 1;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "AccessMode %d ClockFreq %d BusWidth %d\n", AccessMode, ClockFreq, BusWidth));\r
+\r
+ Status = SdPeimSwitch (Slot, AccessMode, 0, 0, 0, TRUE);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimSwitch fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Set to Hight Speed timing\r
+ //\r
+ if (AccessMode == 1) {\r
+ HostCtrl1 = BIT2;\r
+ Status = SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ HostCtrl2 = (UINT8)~0x7;\r
+ Status = SdPeimHcAndMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ HostCtrl2 = AccessMode;\r
+ Status = SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = SdPeimHcClockSupply (Slot->SdHcBase, ClockFreq * 1000);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimHcClockSupply %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ if ((AccessMode == 3) || ((AccessMode == 2) && (Capability.TuningSDR50 != 0))) {\r
+ Status = SdPeimTuningClock (Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimTuningClock fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "SdPeimSetBusMode: SdPeimSetBusMode %r\n", Status));\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Execute SD device identification procedure.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 3.6 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+\r
+ @retval EFI_SUCCESS There is a SD card.\r
+ @retval Others There is not a SD card.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimIdentification (\r
+ IN SD_PEIM_HC_SLOT *Slot\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Ocr;\r
+ UINT16 Rca;\r
+ BOOLEAN Xpc;\r
+ BOOLEAN S18r;\r
+ UINT64 MaxCurrent;\r
+ UINT64 Current;\r
+ UINT16 ControllerVer;\r
+ UINT8 PowerCtrl;\r
+ UINT32 PresentState;\r
+ UINT8 HostCtrl2;\r
+ SD_HC_SLOT_CAP Capability;\r
+\r
+ //\r
+ // 1. Send Cmd0 to the device\r
+ //\r
+ Status = SdPeimReset (Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing Cmd0 fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // 2. Send Cmd8 to the device\r
+ //\r
+ Status = SdPeimVoltageCheck (Slot, 0x1, 0xFF);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing Cmd8 fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // 3. Send SDIO Cmd5 to the device to the SDIO device OCR register.\r
+ //\r
+ Status = SdioSendOpCond (Slot, 0, FALSE);\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Found SDIO device, ignore it as we don't support\n"));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // 4. Send Acmd41 with voltage window 0 to the device\r
+ //\r
+ Status = SdPeimSendOpCond (Slot, 0, 0, FALSE, FALSE, FALSE, &Ocr);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing SdPeimSendOpCond fails with %r\n", Status));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Status = SdPeimHcGetCapability (Slot->SdHcBase, &Capability);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_MAX_CURRENT_CAP, TRUE, sizeof (Current), &Current);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Capability.Voltage33 != 0) {\r
+ //\r
+ // Support 3.3V\r
+ //\r
+ MaxCurrent = ((UINT32)Current & 0xFF) * 4;\r
+ } else if (Capability.Voltage30 != 0) {\r
+ //\r
+ // Support 3.0V\r
+ //\r
+ MaxCurrent = (((UINT32)Current >> 8) & 0xFF) * 4;\r
+ } else if (Capability.Voltage18 != 0) {\r
+ //\r
+ // Support 1.8V\r
+ //\r
+ MaxCurrent = (((UINT32)Current >> 16) & 0xFF) * 4;\r
+ } else {\r
+ ASSERT (FALSE);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (MaxCurrent >= 150) {\r
+ Xpc = TRUE;\r
+ } else {\r
+ Xpc = FALSE;\r
+ }\r
+\r
+ Status = SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((ControllerVer & 0xFF) == 2) {\r
+ S18r = TRUE;\r
+ } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {\r
+ S18r = FALSE;\r
+ } else {\r
+ ASSERT (FALSE);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // 5. Repeatly send Acmd41 with supply voltage window to the device.\r
+ // Note here we only support the cards complied with SD physical\r
+ // layer simplified spec version 2.0 and version 3.0 and above.\r
+ //\r
+ do {\r
+ Status = SdPeimSendOpCond (Slot, 0, Ocr, S18r, Xpc, TRUE, &Ocr);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: SdPeimSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n", Status, Ocr, S18r, Xpc));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ } while ((Ocr & BIT31) == 0);\r
+\r
+ //\r
+ // 6. If the S18a bit is set and the Host Controller supports 1.8V signaling\r
+ // (One of support bits is set to 1: SDR50, SDR104 or DDR50 in the\r
+ // Capabilities register), switch its voltage to 1.8V.\r
+ //\r
+ if ((Capability.Sdr50 != 0 ||\r
+ Capability.Sdr104 != 0 ||\r
+ Capability.Ddr50 != 0) &&\r
+ ((Ocr & BIT24) != 0)) {\r
+ Status = SdPeimVoltageSwitch (Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing SdPeimVoltageSwitch fails with %r\n", Status));\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Error;\r
+ } else {\r
+ Status = SdPeimHcStopClock (Slot->SdHcBase);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Error;\r
+ }\r
+\r
+ SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
+ if (((PresentState >> 20) & 0xF) != 0) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: SwitchVoltage fails with PresentState = 0x%x\n", PresentState));\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Error;\r
+ }\r
+ HostCtrl2 = BIT3;\r
+ SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+\r
+ MicroSecondDelay (5000);\r
+\r
+ SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);\r
+ if ((HostCtrl2 & BIT3) == 0) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: SwitchVoltage fails with HostCtrl2 = 0x%x\n", HostCtrl2));\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Error;\r
+ }\r
+\r
+ SdPeimHcInitClockFreq (Slot->SdHcBase);\r
+\r
+ MicroSecondDelay (1);\r
+\r
+ SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
+ if (((PresentState >> 20) & 0xF) != 0xF) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: SwitchVoltage fails with PresentState = 0x%x, It should be 0xF\n", PresentState));\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Error;\r
+ }\r
+ }\r
+ DEBUG ((EFI_D_INFO, "SdPeimIdentification: Switch to 1.8v signal voltage success\n"));\r
+ }\r
+\r
+ Status = SdPeimAllSendCid (Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing SdPeimAllSendCid fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ Status = SdPeimSetRca (Slot, &Rca);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing SdPeimSetRca fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Enter Data Tranfer Mode.\r
+ //\r
+ DEBUG ((EFI_D_INFO, "Found a SD device at slot [%d]\n", Slot));\r
+\r
+ Status = SdPeimSetBusMode (Slot, Rca, ((Ocr & BIT24) != 0));\r
+\r
+ return Status;\r
+\r
+Error:\r
+ //\r
+ // Set SD Bus Power = 0\r
+ //\r
+ PowerCtrl = (UINT8)~BIT0;\r
+ Status = SdPeimHcAndMmio (Slot->SdHcBase + SD_HC_POWER_CTRL, sizeof (PowerCtrl), &PowerCtrl);\r
+ return EFI_DEVICE_ERROR;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_HCI_H_\r
+#define _SD_HCI_H_\r
+\r
+//\r
+// SD Host Controller MMIO Register Offset\r
+//\r
+#define SD_HC_SDMA_ADDR 0x00\r
+#define SD_HC_ARG2 0x00\r
+#define SD_HC_BLK_SIZE 0x04\r
+#define SD_HC_BLK_COUNT 0x06\r
+#define SD_HC_ARG1 0x08\r
+#define SD_HC_TRANS_MOD 0x0C\r
+#define SD_HC_COMMAND 0x0E\r
+#define SD_HC_RESPONSE 0x10\r
+#define SD_HC_BUF_DAT_PORT 0x20\r
+#define SD_HC_PRESENT_STATE 0x24\r
+#define SD_HC_HOST_CTRL1 0x28\r
+#define SD_HC_POWER_CTRL 0x29\r
+#define SD_HC_BLK_GAP_CTRL 0x2A\r
+#define SD_HC_WAKEUP_CTRL 0x2B\r
+#define SD_HC_CLOCK_CTRL 0x2C\r
+#define SD_HC_TIMEOUT_CTRL 0x2E\r
+#define SD_HC_SW_RST 0x2F\r
+#define SD_HC_NOR_INT_STS 0x30\r
+#define SD_HC_ERR_INT_STS 0x32\r
+#define SD_HC_NOR_INT_STS_EN 0x34\r
+#define SD_HC_ERR_INT_STS_EN 0x36\r
+#define SD_HC_NOR_INT_SIG_EN 0x38\r
+#define SD_HC_ERR_INT_SIG_EN 0x3A\r
+#define SD_HC_AUTO_CMD_ERR_STS 0x3C\r
+#define SD_HC_HOST_CTRL2 0x3E\r
+#define SD_HC_CAP 0x40\r
+#define SD_HC_MAX_CURRENT_CAP 0x48\r
+#define SD_HC_FORCE_EVT_AUTO_CMD 0x50\r
+#define SD_HC_FORCE_EVT_ERR_INT 0x52\r
+#define SD_HC_ADMA_ERR_STS 0x54\r
+#define SD_HC_ADMA_SYS_ADDR 0x58\r
+#define SD_HC_PRESET_VAL 0x60\r
+#define SD_HC_SHARED_BUS_CTRL 0xE0\r
+#define SD_HC_SLOT_INT_STS 0xFC\r
+#define SD_HC_CTRL_VER 0xFE\r
+\r
+//\r
+// The transfer modes supported by SD Host Controller\r
+// Simplified Spec 3.0 Table 1-2\r
+//\r
+typedef enum {\r
+ SdNoData,\r
+ SdPioMode,\r
+ SdSdmaMode,\r
+ SdAdmaMode\r
+} SD_HC_TRANSFER_MODE;\r
+\r
+//\r
+// The maximum data length of each descriptor line\r
+//\r
+#define ADMA_MAX_DATA_PER_LINE 0x10000\r
+#define SD_SDMA_BOUNDARY 512 * 1024\r
+#define SD_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1))\r
+\r
+typedef enum {\r
+ SdCommandTypeBc, // Broadcast commands, no response\r
+ SdCommandTypeBcr, // Broadcast commands with response\r
+ SdCommandTypeAc, // Addressed(point-to-point) commands\r
+ SdCommandTypeAdtc // Addressed(point-to-point) data transfer commands\r
+} SD_COMMAND_TYPE;\r
+\r
+typedef enum {\r
+ SdResponseTypeR1,\r
+ SdResponseTypeR1b,\r
+ SdResponseTypeR2,\r
+ SdResponseTypeR3,\r
+ SdResponseTypeR4,\r
+ SdResponseTypeR5,\r
+ SdResponseTypeR5b,\r
+ SdResponseTypeR6,\r
+ SdResponseTypeR7\r
+} SD_RESPONSE_TYPE;\r
+\r
+typedef struct _SD_COMMAND_BLOCK {\r
+ UINT16 CommandIndex;\r
+ UINT32 CommandArgument;\r
+ UINT32 CommandType; // One of the SD_COMMAND_TYPE values\r
+ UINT32 ResponseType; // One of the SD_RESPONSE_TYPE values\r
+} SD_COMMAND_BLOCK;\r
+\r
+typedef struct _SD_STATUS_BLOCK {\r
+ UINT32 Resp0;\r
+ UINT32 Resp1;\r
+ UINT32 Resp2;\r
+ UINT32 Resp3;\r
+} SD_STATUS_BLOCK;\r
+\r
+typedef struct _SD_COMMAND_PACKET {\r
+ UINT64 Timeout;\r
+ SD_COMMAND_BLOCK *SdCmdBlk;\r
+ SD_STATUS_BLOCK *SdStatusBlk;\r
+ VOID *InDataBuffer;\r
+ VOID *OutDataBuffer;\r
+ UINT32 InTransferLength;\r
+ UINT32 OutTransferLength;\r
+} SD_COMMAND_PACKET;\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+ UINT32 Valid:1;\r
+ UINT32 End:1;\r
+ UINT32 Int:1;\r
+ UINT32 Reserved:1;\r
+ UINT32 Act:2;\r
+ UINT32 Reserved1:10;\r
+ UINT32 Length:16;\r
+ UINT32 Address;\r
+} SD_HC_ADMA_DESC_LINE;\r
+\r
+typedef struct {\r
+ UINT32 TimeoutFreq:6; // bit 0:5\r
+ UINT32 Reserved:1; // bit 6\r
+ UINT32 TimeoutUnit:1; // bit 7\r
+ UINT32 BaseClkFreq:8; // bit 8:15\r
+ UINT32 MaxBlkLen:2; // bit 16:17\r
+ UINT32 BusWidth8:1; // bit 18\r
+ UINT32 Adma2:1; // bit 19\r
+ UINT32 Reserved2:1; // bit 20\r
+ UINT32 HighSpeed:1; // bit 21\r
+ UINT32 Sdma:1; // bit 22\r
+ UINT32 SuspRes:1; // bit 23\r
+ UINT32 Voltage33:1; // bit 24\r
+ UINT32 Voltage30:1; // bit 25\r
+ UINT32 Voltage18:1; // bit 26\r
+ UINT32 Reserved3:1; // bit 27\r
+ UINT32 SysBus64:1; // bit 28\r
+ UINT32 AsyncInt:1; // bit 29\r
+ UINT32 SlotType:2; // bit 30:31\r
+ UINT32 Sdr50:1; // bit 32\r
+ UINT32 Sdr104:1; // bit 33\r
+ UINT32 Ddr50:1; // bit 34\r
+ UINT32 Reserved4:1; // bit 35\r
+ UINT32 DriverTypeA:1; // bit 36\r
+ UINT32 DriverTypeC:1; // bit 37\r
+ UINT32 DriverTypeD:1; // bit 38\r
+ UINT32 DriverType4:1; // bit 39\r
+ UINT32 TimerCount:4; // bit 40:43\r
+ UINT32 Reserved5:1; // bit 44\r
+ UINT32 TuningSDR50:1; // bit 45\r
+ UINT32 RetuningMod:2; // bit 46:47\r
+ UINT32 ClkMultiplier:8; // bit 48:55\r
+ UINT32 Reserved6:7; // bit 56:62\r
+ UINT32 Hs400:1; // bit 63\r
+} SD_HC_SLOT_CAP;\r
+\r
+#pragma pack()\r
+\r
+/**\r
+ Software reset the specified SD host controller and enable all interrupts.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The software reset executes successfully.\r
+ @retval Others The software reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcReset (\r
+ IN UINTN Bar\r
+ );\r
+\r
+/**\r
+ Set all interrupt status bits in Normal and Error Interrupt Status Enable\r
+ register.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The operation executes successfully.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcEnableInterrupt (\r
+ IN UINTN Bar\r
+ );\r
+\r
+/**\r
+ Get the capability data from the specified slot.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+ @param[out] Capability The buffer to store the capability data.\r
+\r
+ @retval EFI_SUCCESS The operation executes successfully.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcGetCapability (\r
+ IN UINTN Bar,\r
+ OUT SD_HC_SLOT_CAP *Capability\r
+ );\r
+\r
+/**\r
+ Detect whether there is a SD card attached at the specified SD host controller\r
+ slot.\r
+\r
+ Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS There is a SD card attached.\r
+ @retval EFI_NO_MEDIA There is not a SD card attached.\r
+ @retval Others The detection fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcCardDetect (\r
+ IN UINTN Bar\r
+ );\r
+\r
+/**\r
+ Initial SD host controller with lowest clock frequency, max power and max timeout value\r
+ at initialization.\r
+\r
+ @param[in] Bar The mmio base address of the slot to be accessed.\r
+\r
+ @retval EFI_SUCCESS The host controller is initialized successfully.\r
+ @retval Others The host controller isn't initialized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcInitHost (\r
+ IN UINTN Bar\r
+ );\r
+\r
+/**\r
+ Send command SWITCH_FUNC to the SD device to check switchable function or switch card function.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] AccessMode The value for access mode group.\r
+ @param[in] CommandSystem The value for command set group.\r
+ @param[in] DriveStrength The value for drive length group.\r
+ @param[in] PowerLimit The value for power limit group.\r
+ @param[in] Mode Switch or check function.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSwitch (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN UINT8 AccessMode,\r
+ IN UINT8 CommandSystem,\r
+ IN UINT8 DriveStrength,\r
+ IN UINT8 PowerLimit,\r
+ IN BOOLEAN Mode\r
+ );\r
+\r
+/**\r
+ Send command READ_SINGLE_BLOCK/WRITE_SINGLE_BLOCK to the addressed SD device\r
+ to read/write the specified number of blocks.\r
+\r
+ Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] Lba The logical block address of starting access.\r
+ @param[in] BlockSize The block size of specified SD device partition.\r
+ @param[in] Buffer The pointer to the transfer buffer.\r
+ @param[in] BufferSize The size of transfer buffer.\r
+ @param[in] IsRead Boolean to show the operation direction.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimRwSingleBlock (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN EFI_LBA Lba,\r
+ IN UINT32 BlockSize,\r
+ IN VOID *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN BOOLEAN IsRead\r
+ );\r
+\r
+/**\r
+ Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed SD device\r
+ to read/write the specified number of blocks.\r
+\r
+ Refer to SD Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Sd card to send the command to.\r
+ @param[in] Lba The logical block address of starting access.\r
+ @param[in] BlockSize The block size of specified SD device partition.\r
+ @param[in] Buffer The pointer to the transfer buffer.\r
+ @param[in] BufferSize The size of transfer buffer.\r
+ @param[in] IsRead Boolean to show the operation direction.\r
+\r
+ @retval EFI_SUCCESS The operation is done correctly.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimRwMultiBlocks (\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN EFI_LBA Lba,\r
+ IN UINT32 BlockSize,\r
+ IN VOID *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN BOOLEAN IsRead\r
+ );\r
+\r
+/**\r
+ Execute SD device identification procedure.\r
+\r
+ Refer to SD Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+ @param[in] Slot The slot number of the Sd card to send the command to.\r
+\r
+ @retval EFI_SUCCESS There is a SD card.\r
+ @retval Others There is not a SD card.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimIdentification (\r
+ IN SD_PEIM_HC_SLOT *Slot\r
+ );\r
+\r
+/**\r
+ Free the resource used by the TRB.\r
+\r
+ @param[in] Trb The pointer to the SD_TRB instance.\r
+\r
+**/\r
+VOID\r
+SdPeimFreeTrb (\r
+ IN SD_TRB *Trb\r
+ );\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+ UEFI Component Name(2) protocol implementation for SdDxe driver.\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdDxe.h"\r
+\r
+//\r
+// Driver name table\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdDxeDriverNameTable[] = {\r
+ { "eng;en", L"Edkii Sd Memory Card Device Driver" },\r
+ { NULL , NULL }\r
+};\r
+\r
+//\r
+// Controller name table\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdDxeControllerNameTable[] = {\r
+ { "eng;en", L"Edkii Sd Host Controller" },\r
+ { NULL , NULL }\r
+};\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSdDxeComponentName = {\r
+ SdDxeComponentNameGetDriverName,\r
+ SdDxeComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSdDxeComponentName2 = {\r
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SdDxeComponentNameGetDriverName,\r
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SdDxeComponentNameGetControllerName,\r
+ "en"\r
+};\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+{\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ mSdDxeDriverNameTable,\r
+ DriverName,\r
+ (BOOLEAN)(This == &gSdDxeComponentName)\r
+ );\r
+\r
+}\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ SD_DEVICE *Device;\r
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;\r
+\r
+ //\r
+ // Make sure this driver is currently managing ControllHandle\r
+ //\r
+ Status = EfiTestManagedDevice (\r
+ ControllerHandle,\r
+ gSdDxeDriverBinding.DriverBindingHandle,\r
+ &gEfiSdMmcPassThruProtocolGuid\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ ControllerNameTable = mSdDxeControllerNameTable;\r
+ if (ChildHandle != NULL) {\r
+ Status = EfiTestChildHandle (\r
+ ControllerHandle,\r
+ ChildHandle,\r
+ &gEfiSdMmcPassThruProtocolGuid\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Get the child context\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlockIo,\r
+ gSdDxeDriverBinding.DriverBindingHandle,\r
+ ChildHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Device = SD_DEVICE_DATA_FROM_BLKIO (BlockIo);\r
+ ControllerNameTable = Device->ControllerNameTable;\r
+ }\r
+\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ ControllerNameTable,\r
+ ControllerName,\r
+ (BOOLEAN)(This == &gSdDxeComponentName)\r
+ );\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ The helper functions for BlockIo and BlockIo2 protocol.\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdDxe.h"\r
+\r
+/**\r
+ Nonblocking I/O callback funtion when the event is signaled.\r
+\r
+ @param[in] Event The Event this notify function registered to.\r
+ @param[in] Context Pointer to the context data registered to the\r
+ Event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AsyncIoCallback (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ SD_REQUEST *Request;\r
+\r
+ gBS->CloseEvent (Event);\r
+\r
+ Request = (SD_REQUEST *) Context;\r
+\r
+ DEBUG_CODE_BEGIN ();\r
+ DEBUG ((EFI_D_INFO, "Sd Async Request: CmdIndex[%d] Arg[%08x] %r\n",\r
+ Request->SdMmcCmdBlk.CommandIndex, Request->SdMmcCmdBlk.CommandArgument,\r
+ Request->Packet.TransactionStatus));\r
+ DEBUG_CODE_END ();\r
+\r
+ if (EFI_ERROR (Request->Packet.TransactionStatus)) {\r
+ Request->Token->TransactionStatus = Request->Packet.TransactionStatus;\r
+ }\r
+\r
+ RemoveEntryList (&Request->Link);\r
+\r
+ if (Request->IsEnd) {\r
+ gBS->SignalEvent (Request->Token->Event);\r
+ }\r
+\r
+ FreePool (Request);\r
+}\r
+\r
+/**\r
+ Send command SET_RELATIVE_ADDRESS to the device to set the device address.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[out] Rca The relative device address to assign.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdSetRca (\r
+ IN SD_DEVICE *Device,\r
+ OUT UINT16 *Rca\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "Set RCA succeeds with Resp0 = 0x%x\n", SdMmcStatusBlk.Resp0));\r
+ *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SELECT to the device to select/deselect the device.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdSelect (\r
+ IN SD_DEVICE *Device,\r
+ IN UINT16 Rca\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_STATUS to the device to get device status.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+ @param[out] DevStatus The buffer to store the device status.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdSendStatus (\r
+ IN SD_DEVICE *Device,\r
+ IN UINT16 Rca,\r
+ OUT UINT32 *DevStatus\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ CopyMem (DevStatus, &SdMmcStatusBlk.Resp0, sizeof (UINT32));\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_CSD to the device to get the CSD register data.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+ @param[out] Csd The buffer to store the SD_CSD register data.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdGetCsd (\r
+ IN SD_DEVICE *Device,\r
+ IN UINT16 Rca,\r
+ OUT SD_CSD *Csd\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ ZeroMem (Csd, sizeof (SD_CSD));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SEND_CSD;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+ //\r
+ CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send command SEND_CID to the device to get the CID register data.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+ @param[out] Cid The buffer to store the SD_CID register data.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdGetCid (\r
+ IN SD_DEVICE *Device,\r
+ IN UINT16 Rca,\r
+ OUT SD_CID *Cid\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ ZeroMem (Cid, sizeof (SD_CID));\r
+\r
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+ Packet.Timeout = SD_GENERIC_TIMEOUT;\r
+\r
+ SdMmcCmdBlk.CommandIndex = SD_SEND_CID;\r
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+ //\r
+ CopyMem (((UINT8*)Cid) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CID) - 1);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read/write single block through sync or async I/O request.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] Lba The starting logical block address to be read/written.\r
+ The caller is responsible for reading/writing to only\r
+ legitimate locations.\r
+ @param[in] Buffer A pointer to the destination/source buffer for the data.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[in] IsRead Indicates it is a read or write operation.\r
+ @param[in] Token A pointer to the token associated with the transaction.\r
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
+ This parameter is only meaningful in async I/O request.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdRwSingleBlock (\r
+ IN SD_DEVICE *Device,\r
+ IN EFI_LBA Lba,\r
+ IN VOID *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN BOOLEAN IsRead,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN BOOLEAN IsEnd\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ SD_REQUEST *RwSingleBlkReq;\r
+ EFI_TPL OldTpl;\r
+\r
+ RwSingleBlkReq = NULL;\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ RwSingleBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));\r
+ if (RwSingleBlkReq == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ RwSingleBlkReq->Signature = SD_REQUEST_SIGNATURE;\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ InsertTailList (&Device->Queue, &RwSingleBlkReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ RwSingleBlkReq->Packet.SdMmcCmdBlk = &RwSingleBlkReq->SdMmcCmdBlk;\r
+ RwSingleBlkReq->Packet.SdMmcStatusBlk = &RwSingleBlkReq->SdMmcStatusBlk;\r
+ //\r
+ // Calculate timeout value through the below formula.\r
+ // Timeout = (transfer size) / (2MB/s).\r
+ // Taking 2MB/s as divisor as it's the lowest transfer speed\r
+ // above class 2.\r
+ // Refer to SD Physical Layer Simplified spec section 3.4 for details.\r
+ //\r
+ RwSingleBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;\r
+\r
+ if (IsRead) {\r
+ RwSingleBlkReq->Packet.InDataBuffer = Buffer;\r
+ RwSingleBlkReq->Packet.InTransferLength = (UINT32)BufferSize;\r
+\r
+ RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_SINGLE_BLOCK;\r
+ RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ } else {\r
+ RwSingleBlkReq->Packet.OutDataBuffer = Buffer;\r
+ RwSingleBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;\r
+\r
+ RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_SINGLE_BLOCK;\r
+ RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ }\r
+\r
+ if (Device->SectorAddressing) {\r
+ RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;\r
+ } else {\r
+ RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);\r
+ }\r
+\r
+ RwSingleBlkReq->IsEnd = IsEnd;\r
+ RwSingleBlkReq->Token = Token;\r
+\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ AsyncIoCallback,\r
+ RwSingleBlkReq,\r
+ &RwSingleBlkReq->Event\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ } else {\r
+ RwSingleBlkReq->Event = NULL;\r
+ }\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &RwSingleBlkReq->Packet, RwSingleBlkReq->Event);\r
+\r
+Error:\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ //\r
+ // For asynchronous operation, only free request and event in error case.\r
+ // The request and event will be freed in asynchronous callback for success case.\r
+ //\r
+ if (EFI_ERROR (Status) && (RwSingleBlkReq != NULL)) {\r
+ RemoveEntryList (&RwSingleBlkReq->Link);\r
+ if (RwSingleBlkReq->Event != NULL) {\r
+ gBS->CloseEvent (RwSingleBlkReq->Event);\r
+ }\r
+ FreePool (RwSingleBlkReq);\r
+ }\r
+ } else {\r
+ //\r
+ // For synchronous operation, free request whatever the execution result is.\r
+ //\r
+ if (RwSingleBlkReq != NULL) {\r
+ RemoveEntryList (&RwSingleBlkReq->Link);\r
+ FreePool (RwSingleBlkReq);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read/write multiple blocks through sync or async I/O request.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] Lba The starting logical block address to be read/written.\r
+ The caller is responsible for reading/writing to only\r
+ legitimate locations.\r
+ @param[in] Buffer A pointer to the destination/source buffer for the data.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[in] IsRead Indicates it is a read or write operation.\r
+ @param[in] Token A pointer to the token associated with the transaction.\r
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
+ This parameter is only meaningful in async I/O request.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdRwMultiBlocks (\r
+ IN SD_DEVICE *Device,\r
+ IN EFI_LBA Lba,\r
+ IN VOID *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN BOOLEAN IsRead,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN BOOLEAN IsEnd\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_REQUEST *RwMultiBlkReq;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_TPL OldTpl;\r
+\r
+ RwMultiBlkReq = NULL;\r
+\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ RwMultiBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));\r
+ if (RwMultiBlkReq == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ RwMultiBlkReq->Signature = SD_REQUEST_SIGNATURE;\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ InsertTailList (&Device->Queue, &RwMultiBlkReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ RwMultiBlkReq->Packet.SdMmcCmdBlk = &RwMultiBlkReq->SdMmcCmdBlk;\r
+ RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk;\r
+ //\r
+ // Calculate timeout value through the below formula.\r
+ // Timeout = (transfer size) / (2MB/s).\r
+ // Taking 2MB/s as divisor as it's the lowest transfer speed\r
+ // above class 2.\r
+ // Refer to SD Physical Layer Simplified spec section 3.4 for details.\r
+ //\r
+ RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;\r
+\r
+ if (IsRead) {\r
+ RwMultiBlkReq->Packet.InDataBuffer = Buffer;\r
+ RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;\r
+\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK;\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ } else {\r
+ RwMultiBlkReq->Packet.OutDataBuffer = Buffer;\r
+ RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;\r
+\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK;\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
+ RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+ }\r
+\r
+ if (Device->SectorAddressing) {\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;\r
+ } else {\r
+ RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);\r
+ }\r
+\r
+ RwMultiBlkReq->IsEnd = IsEnd;\r
+ RwMultiBlkReq->Token = Token;\r
+\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ AsyncIoCallback,\r
+ RwMultiBlkReq,\r
+ &RwMultiBlkReq->Event\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ } else {\r
+ RwMultiBlkReq->Event = NULL;\r
+ }\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);\r
+\r
+Error:\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ //\r
+ // For asynchronous operation, only free request and event in error case.\r
+ // The request and event will be freed in asynchronous callback for success case.\r
+ //\r
+ if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {\r
+ RemoveEntryList (&RwMultiBlkReq->Link);\r
+ if (RwMultiBlkReq->Event != NULL) {\r
+ gBS->CloseEvent (RwMultiBlkReq->Event);\r
+ }\r
+ FreePool (RwMultiBlkReq);\r
+ }\r
+ } else {\r
+ //\r
+ // For synchronous operation, free request whatever the execution result is.\r
+ //\r
+ if (RwMultiBlkReq != NULL) {\r
+ RemoveEntryList (&RwMultiBlkReq->Link);\r
+ FreePool (RwMultiBlkReq);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function transfers data from/to the sd memory card device.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] MediaId The media ID that the read/write request is for.\r
+ @param[in] Lba The starting logical block address to be read/written.\r
+ The caller is responsible for reading/writing to only\r
+ legitimate locations.\r
+ @param[in, out] Buffer A pointer to the destination/source buffer for the data.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[in] IsRead Indicates it is a read or write operation.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+\r
+ @retval EFI_SUCCESS The data was read/written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device can not be read/written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+SdReadWrite (\r
+ IN SD_DEVICE *Device,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT VOID *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN BOOLEAN IsRead,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ UINTN BlockSize;\r
+ UINTN BlockNum;\r
+ UINTN IoAlign;\r
+ UINTN Remaining;\r
+ UINT32 MaxBlock;\r
+ BOOLEAN LastRw;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Media = &Device->BlockMedia;\r
+ LastRw = FALSE;\r
+\r
+ if (MediaId != Media->MediaId) {\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ if (!IsRead && Media->ReadOnly) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
+ //\r
+ // Check parameters.\r
+ //\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ gBS->SignalEvent (Token->Event);\r
+ }\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ BlockSize = Media->BlockSize;\r
+ if ((BufferSize % BlockSize) != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ BlockNum = BufferSize / BlockSize;\r
+ if ((Lba + BlockNum - 1) > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ IoAlign = Media->IoAlign;\r
+ if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Start to execute data transfer. The max block number in single cmd is 65535 blocks.\r
+ //\r
+ Remaining = BlockNum;\r
+ MaxBlock = 0xFFFF;\r
+\r
+ while (Remaining > 0) {\r
+ if (Remaining <= MaxBlock) {\r
+ BlockNum = Remaining;\r
+ LastRw = TRUE;\r
+ } else {\r
+ BlockNum = MaxBlock;\r
+ }\r
+\r
+ BufferSize = BlockNum * BlockSize;\r
+ if (BlockNum == 1) {\r
+ Status = SdRwSingleBlock (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);\r
+ } else {\r
+ Status = SdRwMultiBlocks (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ DEBUG ((EFI_D_INFO, "Sd%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", IsRead ? "Read" : "Write", Lba, BlockNum, Token->Event, Status));\r
+\r
+ Lba += BlockNum;\r
+ Buffer = (UINT8*)Buffer + BufferSize;\r
+ Remaining -= BlockNum;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Reset the Block Device.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
+ not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdReset (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_DEVICE *Device;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+\r
+ Device = SD_DEVICE_DATA_FROM_BLKIO (This);\r
+\r
+ PassThru = Device->Private->PassThru;\r
+ Status = PassThru->ResetDevice (PassThru, Device->Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId Id of the media, changes every time the media is replaced.\r
+ @param Lba The starting Logical Block Address to read from\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller is\r
+ responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdReadBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_DEVICE *Device;\r
+\r
+ Device = SD_DEVICE_DATA_FROM_BLKIO (This);\r
+\r
+ Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Write BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId The media ID that the write request is for.\r
+ @param Lba The starting logical block address to be written. The caller is\r
+ responsible for writing to only legitimate locations.\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the source buffer for the data.\r
+\r
+ @retval EFI_SUCCESS The data was written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device can not be written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdWriteBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_DEVICE *Device;\r
+\r
+ Device = SD_DEVICE_DATA_FROM_BLKIO (This);\r
+\r
+ Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Flush the Block Device.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+\r
+ @retval EFI_SUCCESS All outstanding data was written to the device\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdFlushBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This\r
+ )\r
+{\r
+ //\r
+ // return directly\r
+ //\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Reset the Block Device.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
+ not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdResetEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ SD_DEVICE *Device;\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *NextLink;\r
+ SD_REQUEST *Request;\r
+ EFI_TPL OldTpl;\r
+\r
+ Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ for (Link = GetFirstNode (&Device->Queue);\r
+ !IsNull (&Device->Queue, Link);\r
+ Link = NextLink) {\r
+ NextLink = GetNextNode (&Device->Queue, Link);\r
+ RemoveEntryList (Link);\r
+\r
+ Request = SD_REQUEST_FROM_LINK (Link);\r
+\r
+ gBS->CloseEvent (Request->Event);\r
+ Request->Token->TransactionStatus = EFI_ABORTED;\r
+\r
+ if (Request->IsEnd) {\r
+ gBS->SignalEvent (Request->Token->Event);\r
+ }\r
+\r
+ FreePool (Request);\r
+ }\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read BufferSize bytes from Lba into Buffer.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] MediaId Id of the media, changes every time the media is replaced.\r
+ @param[in] Lba The starting Logical Block Address to read from.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[out] Buffer A pointer to the destination buffer for the data. The caller is\r
+ responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+ @retval EFI_SUCCESS The read request was queued if Event is not NULL.\r
+ The data was read correctly from the device if\r
+ the Event is NULL.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing\r
+ the read.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r
+ intrinsic block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
+ of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdReadBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_DEVICE *Device;\r
+\r
+ Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);\r
+\r
+ Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, Token);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Write BufferSize bytes from Lba into Buffer.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] MediaId The media ID that the write request is for.\r
+ @param[in] Lba The starting logical block address to be written. The\r
+ caller is responsible for writing to only legitimate\r
+ locations.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[in] Buffer A pointer to the source buffer for the data.\r
+\r
+ @retval EFI_SUCCESS The data was written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device can not be written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdWriteBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_DEVICE *Device;\r
+\r
+ Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);\r
+\r
+ Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, Token);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Flush the Block Device.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+\r
+ @retval EFI_SUCCESS All outstanding data was written to the device\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdFlushBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
+ )\r
+{\r
+ //\r
+ // Signal event and return directly.\r
+ //\r
+ if (Token != NULL && Token->Event != NULL) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ gBS->SignalEvent (Token->Event);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
--- /dev/null
+/** @file\r
+ Header file for SdDxe Driver.\r
+\r
+ This file defines common data structures, macro definitions and some module\r
+ internal function header files.\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_BLOCK_IO_H_\r
+#define _SD_BLOCK_IO_H_\r
+\r
+/**\r
+ Reset the Block Device.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
+ not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdReset (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ );\r
+\r
+/**\r
+ Read BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId Id of the media, changes every time the media is replaced.\r
+ @param Lba The starting Logical Block Address to read from\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller is\r
+ responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdReadBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Write BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId The media ID that the write request is for.\r
+ @param Lba The starting logical block address to be written. The caller is\r
+ responsible for writing to only legitimate locations.\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the source buffer for the data.\r
+\r
+ @retval EFI_SUCCESS The data was written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device can not be written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdWriteBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Flush the Block Device.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+\r
+ @retval EFI_SUCCESS All outstanding data was written to the device\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdFlushBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This\r
+ );\r
+\r
+/**\r
+ Reset the Block Device.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
+ not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdResetEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ );\r
+\r
+/**\r
+ Read BufferSize bytes from Lba into Buffer.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] MediaId Id of the media, changes every time the media is replaced.\r
+ @param[in] Lba The starting Logical Block Address to read from.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[out] Buffer A pointer to the destination buffer for the data. The caller is\r
+ responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+ @retval EFI_SUCCESS The read request was queued if Event is not NULL.\r
+ The data was read correctly from the device if\r
+ the Event is NULL.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing\r
+ the read.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r
+ intrinsic block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
+ of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdReadBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Write BufferSize bytes from Lba into Buffer.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] MediaId The media ID that the write request is for.\r
+ @param[in] Lba The starting logical block address to be written. The\r
+ caller is responsible for writing to only legitimate\r
+ locations.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[in] Buffer A pointer to the source buffer for the data.\r
+\r
+ @retval EFI_SUCCESS The data was written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device can not be written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdWriteBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Flush the Block Device.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+\r
+ @retval EFI_SUCCESS All outstanding data was written to the device\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdFlushBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
+ );\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+ The SdDxe driver is used to manage the SD memory card device.\r
+\r
+ It produces BlockIo and BlockIo2 protocols to allow upper layer\r
+ access the SD memory card device.\r
+\r
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdDxe.h"\r
+\r
+//\r
+// SdDxe Driver Binding Protocol Instance\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gSdDxeDriverBinding = {\r
+ SdDxeDriverBindingSupported,\r
+ SdDxeDriverBindingStart,\r
+ SdDxeDriverBindingStop,\r
+ 0x10,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+//\r
+// Template for SD_DEVICE data structure.\r
+//\r
+SD_DEVICE mSdDeviceTemplate = {\r
+ SD_DEVICE_SIGNATURE, // Signature\r
+ NULL, // Handle\r
+ NULL, // DevicePath\r
+ 0xFF, // Slot\r
+ FALSE, // SectorAddressing\r
+ { // BlockIo\r
+ EFI_BLOCK_IO_PROTOCOL_REVISION,\r
+ NULL,\r
+ SdReset,\r
+ SdReadBlocks,\r
+ SdWriteBlocks,\r
+ SdFlushBlocks\r
+ },\r
+ { // BlockIo2\r
+ NULL,\r
+ SdResetEx,\r
+ SdReadBlocksEx,\r
+ SdWriteBlocksEx,\r
+ SdFlushBlocksEx\r
+ },\r
+ { // BlockMedia\r
+ 0, // MediaId\r
+ FALSE, // RemovableMedia\r
+ TRUE, // MediaPresent\r
+ FALSE, // LogicPartition\r
+ FALSE, // ReadOnly\r
+ FALSE, // WritingCache\r
+ 0x200, // BlockSize\r
+ 0, // IoAlign\r
+ 0 // LastBlock\r
+ },\r
+ { // Queue\r
+ NULL,\r
+ NULL\r
+ },\r
+ { // Csd\r
+ 0,\r
+ },\r
+ { // Cid\r
+ 0,\r
+ },\r
+ NULL, // ControllerNameTable\r
+ { // ModelName\r
+ 0,\r
+ },\r
+ NULL // Private\r
+};\r
+\r
+/**\r
+ Decode and print SD CSD Register content.\r
+\r
+ @param[in] Csd Pointer to SD_CSD data structure.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully\r
+**/\r
+EFI_STATUS\r
+DumpCsd (\r
+ IN SD_CSD *Csd\r
+ )\r
+{\r
+ SD_CSD2 *Csd2;\r
+\r
+ DEBUG((DEBUG_INFO, "== Dump Sd Csd Register==\n"));\r
+ DEBUG((DEBUG_INFO, " CSD structure 0x%x\n", Csd->CsdStructure));\r
+ DEBUG((DEBUG_INFO, " Data read access-time 1 0x%x\n", Csd->Taac));\r
+ DEBUG((DEBUG_INFO, " Data read access-time 2 0x%x\n", Csd->Nsac));\r
+ DEBUG((DEBUG_INFO, " Max. bus clock frequency 0x%x\n", Csd->TranSpeed));\r
+ DEBUG((DEBUG_INFO, " Device command classes 0x%x\n", Csd->Ccc));\r
+ DEBUG((DEBUG_INFO, " Max. read data block length 0x%x\n", Csd->ReadBlLen));\r
+ DEBUG((DEBUG_INFO, " Partial blocks for read allowed 0x%x\n", Csd->ReadBlPartial));\r
+ DEBUG((DEBUG_INFO, " Write block misalignment 0x%x\n", Csd->WriteBlkMisalign));\r
+ DEBUG((DEBUG_INFO, " Read block misalignment 0x%x\n", Csd->ReadBlkMisalign));\r
+ DEBUG((DEBUG_INFO, " DSR implemented 0x%x\n", Csd->DsrImp));\r
+ if (Csd->CsdStructure == 0) {\r
+ DEBUG((DEBUG_INFO, " Device size 0x%x\n", Csd->CSizeLow | (Csd->CSizeHigh << 2)));\r
+ DEBUG((DEBUG_INFO, " Max. read current @ VDD min 0x%x\n", Csd->VddRCurrMin));\r
+ DEBUG((DEBUG_INFO, " Max. read current @ VDD max 0x%x\n", Csd->VddRCurrMax));\r
+ DEBUG((DEBUG_INFO, " Max. write current @ VDD min 0x%x\n", Csd->VddWCurrMin));\r
+ DEBUG((DEBUG_INFO, " Max. write current @ VDD max 0x%x\n", Csd->VddWCurrMax));\r
+ } else {\r
+ Csd2 = (SD_CSD2*)(VOID*)Csd;\r
+ DEBUG((DEBUG_INFO, " Device size 0x%x\n", Csd2->CSizeLow | (Csd->CSizeHigh << 16)));\r
+ }\r
+ DEBUG((DEBUG_INFO, " Erase sector size 0x%x\n", Csd->SectorSize));\r
+ DEBUG((DEBUG_INFO, " Erase single block enable 0x%x\n", Csd->EraseBlkEn));\r
+ DEBUG((DEBUG_INFO, " Write protect group size 0x%x\n", Csd->WpGrpSize));\r
+ DEBUG((DEBUG_INFO, " Write protect group enable 0x%x\n", Csd->WpGrpEnable));\r
+ DEBUG((DEBUG_INFO, " Write speed factor 0x%x\n", Csd->R2WFactor));\r
+ DEBUG((DEBUG_INFO, " Max. write data block length 0x%x\n", Csd->WriteBlLen));\r
+ DEBUG((DEBUG_INFO, " Partial blocks for write allowed 0x%x\n", Csd->WriteBlPartial));\r
+ DEBUG((DEBUG_INFO, " File format group 0x%x\n", Csd->FileFormatGrp));\r
+ DEBUG((DEBUG_INFO, " Copy flag (OTP) 0x%x\n", Csd->Copy));\r
+ DEBUG((DEBUG_INFO, " Permanent write protection 0x%x\n", Csd->PermWriteProtect));\r
+ DEBUG((DEBUG_INFO, " Temporary write protection 0x%x\n", Csd->TmpWriteProtect));\r
+ DEBUG((DEBUG_INFO, " File format 0x%x\n", Csd->FileFormat));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get SD device model name.\r
+\r
+ @param[in, out] Device The pointer to the SD_DEVICE data structure.\r
+ @param[in] Cid Pointer to SD_CID data structure.\r
+\r
+ @retval EFI_SUCCESS The function completed successfully\r
+\r
+**/\r
+EFI_STATUS\r
+GetSdModelName (\r
+ IN OUT SD_DEVICE *Device,\r
+ IN SD_CID *Cid\r
+ )\r
+{\r
+ CHAR8 String[SD_MODEL_NAME_MAX_LEN];\r
+\r
+ ZeroMem (String, sizeof (String));\r
+ CopyMem (String, Cid->OemId, sizeof (Cid->OemId));\r
+ String[sizeof (Cid->OemId)] = ' ';\r
+ CopyMem (String + sizeof (Cid->OemId) + 1, Cid->ProductName, sizeof (Cid->ProductName));\r
+ String[sizeof (Cid->OemId) + sizeof (Cid->ProductName)] = ' ';\r
+ CopyMem (String + sizeof (Cid->OemId) + sizeof (Cid->ProductName) + 1, Cid->ProductSerialNumber, sizeof (Cid->ProductSerialNumber));\r
+\r
+ AsciiStrToUnicodeStr (String, Device->ModelName);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Discover user area partition in the SD device.\r
+\r
+ @param[in] Device The pointer to the SD_DEVICE data structure.\r
+\r
+ @retval EFI_SUCCESS The user area partition in the SD device is successfully identified.\r
+ @return Others Some error occurs when identifying the user area.\r
+\r
+**/\r
+EFI_STATUS\r
+DiscoverUserArea (\r
+ IN SD_DEVICE *Device\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_CSD *Csd;\r
+ SD_CSD2 *Csd2;\r
+ SD_CID *Cid;\r
+ UINT64 Capacity;\r
+ UINT32 DevStatus;\r
+ UINT16 Rca;\r
+ UINT32 CSize;\r
+ UINT32 CSizeMul;\r
+ UINT32 ReadBlLen;\r
+\r
+ //\r
+ // Deselect the device to force it enter stby mode.\r
+ // Note here we don't judge return status as some SD devices return\r
+ // error but the state has been stby.\r
+ //\r
+ SdSelect (Device, 0);\r
+\r
+ Status = SdSetRca (Device, &Rca);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "DiscoverUserArea(): Assign new Rca = 0x%x fails with %r\n", Rca, Status));\r
+ return Status;\r
+ }\r
+\r
+ Csd = &Device->Csd;\r
+ Status = SdGetCsd (Device, Rca, Csd);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ DumpCsd (Csd);\r
+\r
+ Cid = &Device->Cid;\r
+ Status = SdGetCid (Device, Rca, Cid);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ GetSdModelName (Device, Cid);\r
+\r
+ Status = SdSelect (Device, Rca);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "DiscoverUserArea(): Reselect the device 0x%x fails with %r\n", Rca, Status));\r
+ return Status;\r
+ }\r
+\r
+ Status = SdSendStatus (Device, Rca, &DevStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Csd->CsdStructure == 0) {\r
+ Device->SectorAddressing = FALSE;\r
+ CSize = (Csd->CSizeHigh << 2 | Csd->CSizeLow) + 1;\r
+ CSizeMul = (1 << (Csd->CSizeMul + 2));\r
+ ReadBlLen = (1 << (Csd->ReadBlLen));\r
+ Capacity = MultU64x32 (MultU64x32 ((UINT64)CSize, CSizeMul), ReadBlLen);\r
+ } else {\r
+ Device->SectorAddressing = TRUE;\r
+ Csd2 = (SD_CSD2*)(VOID*)Csd;\r
+ CSize = (Csd2->CSizeHigh << 16 | Csd2->CSizeLow) + 1;\r
+ Capacity = MultU64x32 ((UINT64)CSize, SIZE_512KB);\r
+ }\r
+\r
+ Device->BlockIo.Media = &Device->BlockMedia;\r
+ Device->BlockIo2.Media = &Device->BlockMedia;\r
+ Device->BlockMedia.IoAlign = Device->Private->PassThru->IoAlign;\r
+ Device->BlockMedia.BlockSize = 0x200;\r
+ Device->BlockMedia.LastBlock = 0x00;\r
+ Device->BlockMedia.RemovableMedia = TRUE;\r
+ Device->BlockMedia.MediaPresent = TRUE;\r
+ Device->BlockMedia.LogicalPartition = FALSE;\r
+ Device->BlockMedia.LastBlock = DivU64x32 (Capacity, Device->BlockMedia.BlockSize) - 1;\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Scan SD Bus to discover the device.\r
+\r
+ @param[in] Private The SD driver private data structure.\r
+ @param[in] Slot The slot number to check device present.\r
+\r
+ @retval EFI_SUCCESS Successfully to discover the device and attach\r
+ SdMmcIoProtocol to it.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
+ of resources.\r
+ @retval EFI_ALREADY_STARTED The device was discovered before.\r
+ @retval Others Fail to discover the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DiscoverSdDevice (\r
+ IN SD_DRIVER_PRIVATE_DATA *Private,\r
+ IN UINT8 Slot\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SD_DEVICE *Device;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;\r
+ EFI_HANDLE DeviceHandle;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+\r
+ Device = NULL;\r
+ DevicePath = NULL;\r
+ NewDevicePath = NULL;\r
+ RemainingDevicePath = NULL;\r
+ PassThru = Private->PassThru;\r
+\r
+ //\r
+ // Build Device Path\r
+ //\r
+ Status = PassThru->BuildDevicePath (\r
+ PassThru,\r
+ Slot,\r
+ &DevicePath\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (DevicePath->SubType != MSG_SD_DP) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Error;\r
+ }\r
+\r
+ NewDevicePath = AppendDevicePathNode (\r
+ Private->ParentDevicePath,\r
+ DevicePath\r
+ );\r
+\r
+ if (NewDevicePath == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ DeviceHandle = NULL;\r
+ RemainingDevicePath = NewDevicePath;\r
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);\r
+ if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {\r
+ //\r
+ // The device has been started, directly return to fast boot.\r
+ //\r
+ Status = EFI_ALREADY_STARTED;\r
+ goto Error;\r
+ }\r
+\r
+ //\r
+ // Allocate buffer to store SD_DEVICE private data.\r
+ //\r
+ Device = AllocateCopyPool (sizeof (SD_DEVICE), &mSdDeviceTemplate);\r
+ if (Device == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ Device->DevicePath = NewDevicePath;\r
+ Device->Slot = Slot;\r
+ Device->Private = Private;\r
+ InitializeListHead (&Device->Queue);\r
+\r
+ //\r
+ // Expose user area in the Sd memory card to upper layer.\r
+ //\r
+ Status = DiscoverUserArea (Device);\r
+ if (EFI_ERROR(Status)) {\r
+ goto Error;\r
+ }\r
+\r
+ Device->ControllerNameTable = NULL;\r
+ AddUnicodeString2 (\r
+ "eng",\r
+ gSdDxeComponentName.SupportedLanguages,\r
+ &Device->ControllerNameTable,\r
+ Device->ModelName,\r
+ TRUE\r
+ );\r
+ AddUnicodeString2 (\r
+ "en",\r
+ gSdDxeComponentName.SupportedLanguages,\r
+ &Device->ControllerNameTable,\r
+ Device->ModelName,\r
+ FALSE\r
+ );\r
+\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Device->Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ Device->DevicePath,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &Device->BlockIo,\r
+ &gEfiBlockIo2ProtocolGuid,\r
+ &Device->BlockIo2,\r
+ NULL\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ gBS->OpenProtocol (\r
+ Private->Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ (VOID **) &(Private->PassThru),\r
+ Private->DriverBindingHandle,\r
+ Device->Handle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ }\r
+\r
+Error:\r
+ FreePool (DevicePath);\r
+\r
+ if (EFI_ERROR (Status) && (NewDevicePath != NULL)) {\r
+ FreePool (NewDevicePath);\r
+ }\r
+\r
+ if (EFI_ERROR (Status) && (Device != NULL)) {\r
+ FreePool (Device);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Tests to see if this driver supports a given controller. If a child device is provided,\r
+ it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+ This function checks to see if the driver specified by This supports the device specified by\r
+ ControllerHandle. Drivers will typically use the device path attached to\r
+ ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+ ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+ may be called many times during platform initialization. In order to reduce boot times, the tests\r
+ performed by this function must be very small, and take as little time as possible to execute. This\r
+ function must not change the state of any hardware devices, and this function must be aware that the\r
+ device specified by ControllerHandle may already be managed by the same driver or a\r
+ different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+ to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to test. This handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For bus drivers, if this parameter is not NULL, then\r
+ the bus driver must determine if the bus controller specified\r
+ by ControllerHandle and the child controller specified\r
+ by RemainingDevicePath are both supported by this\r
+ bus driver.\r
+\r
+ @retval EFI_SUCCESS The device specified by ControllerHandle and\r
+ RemainingDevicePath is supported by the driver specified by This.\r
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by the driver\r
+ specified by This.\r
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by a different\r
+ driver or an application that requires exclusive access.\r
+ Currently not implemented.\r
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ UINT8 Slot;\r
+\r
+ //\r
+ // Test EFI_SD_MMC_PASS_THRU_PROTOCOL on the controller handle.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ (VOID**) &PassThru,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Test RemainingDevicePath is valid or not.\r
+ //\r
+ if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {\r
+ Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Close the I/O Abstraction(s) used to perform the supported test\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Close the I/O Abstraction(s) used to perform the supported test\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ //\r
+ // Open the EFI Device Path protocol needed to perform the supported test\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &ParentDevicePath,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Starts a device controller or a bus controller.\r
+\r
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+ As a result, much of the error checking on the parameters to Start() has been moved into this\r
+ common boot service. It is legal to call Start() from other locations,\r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE.\r
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+ EFI_DEVICE_PATH_PROTOCOL.\r
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to start. This handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For a bus driver, if this parameter is NULL, then handles\r
+ for all the children of Controller are created by this driver.\r
+ If this parameter is not NULL and the first Device Path Node is\r
+ not the End of Device Path Node, then only the handle for the\r
+ child device specified by the first Device Path Node of\r
+ RemainingDevicePath is created by this driver.\r
+ If the first Device Path Node of RemainingDevicePath is\r
+ the End of Device Path Node, no child handle is created by this\r
+ driver.\r
+\r
+ @retval EFI_SUCCESS The device was started.\r
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval Others The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ SD_DRIVER_PRIVATE_DATA *Private;\r
+ UINT8 Slot;\r
+\r
+ Private = NULL;\r
+ PassThru = NULL;\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ (VOID **) &PassThru,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Check EFI_ALREADY_STARTED to reuse the original SD_DRIVER_PRIVATE_DATA.\r
+ //\r
+ if (Status != EFI_ALREADY_STARTED) {\r
+ Private = AllocateZeroPool (sizeof (SD_DRIVER_PRIVATE_DATA));\r
+ if (Private == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &ParentDevicePath,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ Private->PassThru = PassThru;\r
+ Private->Controller = Controller;\r
+ Private->ParentDevicePath = ParentDevicePath;\r
+ Private->DriverBindingHandle = This->DriverBindingHandle;\r
+\r
+ Status = gBS->InstallProtocolInterface (\r
+ &Controller,\r
+ &gEfiCallerIdGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ Private\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ } else {\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiCallerIdGuid,\r
+ (VOID **) &Private,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ }\r
+\r
+ if (RemainingDevicePath == NULL) {\r
+ Slot = 0xFF;\r
+ while (TRUE) {\r
+ Status = PassThru->GetNextSlot (PassThru, &Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Cannot find more legal slots.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+ }\r
+\r
+ Status = DiscoverSdDevice (Private, Slot);\r
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+ break;\r
+ }\r
+ }\r
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
+ Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = DiscoverSdDevice (Private, Slot);\r
+ }\r
+ }\r
+\r
+Error:\r
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ if (Private != NULL) {\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ Controller,\r
+ &gEfiCallerIdGuid,\r
+ Private,\r
+ NULL\r
+ );\r
+ FreePool (Private);\r
+ }\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Stops a device controller or a bus controller.\r
+\r
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+ As a result, much of the error checking on the parameters to Stop() has been moved\r
+ into this common boot service. It is legal to call Stop() from other locations,\r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+ same driver's Start() function.\r
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+ Start() function, and the Start() function must have called OpenProtocol() on\r
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must\r
+ support a bus specific I/O protocol for the driver\r
+ to use to stop the device.\r
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+ if NumberOfChildren is 0.\r
+\r
+ @retval EFI_SUCCESS The device was stopped.\r
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN AllChildrenStopped;\r
+ UINTN Index;\r
+ SD_DRIVER_PRIVATE_DATA *Private;\r
+ SD_DEVICE *Device;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *NextLink;\r
+ SD_REQUEST *Request;\r
+ EFI_TPL OldTpl;\r
+\r
+ if (NumberOfChildren == 0) {\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiCallerIdGuid,\r
+ (VOID **) &Private,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ gBS->UninstallProtocolInterface (\r
+ Controller,\r
+ &gEfiCallerIdGuid,\r
+ Private\r
+ );\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ FreePool (Private);\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ AllChildrenStopped = TRUE;\r
+\r
+ for (Index = 0; Index < NumberOfChildren; Index++) {\r
+ BlockIo = NULL;\r
+ BlockIo2 = NULL;\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandleBuffer[Index],\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlockIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandleBuffer[Index],\r
+ &gEfiBlockIo2ProtocolGuid,\r
+ (VOID **) &BlockIo2,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ AllChildrenStopped = FALSE;\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if (BlockIo != NULL) {\r
+ Device = SD_DEVICE_DATA_FROM_BLKIO (BlockIo);\r
+ } else {\r
+ ASSERT (BlockIo2 != NULL);\r
+ Device = SD_DEVICE_DATA_FROM_BLKIO2 (BlockIo2);\r
+ }\r
+\r
+ //\r
+ // Free all on-going async tasks.\r
+ //\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ for (Link = GetFirstNode (&Device->Queue);\r
+ !IsNull (&Device->Queue, Link);\r
+ Link = NextLink) {\r
+ NextLink = GetNextNode (&Device->Queue, Link);\r
+ RemoveEntryList (Link);\r
+\r
+ Request = SD_REQUEST_FROM_LINK (Link);\r
+\r
+ gBS->CloseEvent (Request->Event);\r
+ Request->Token->TransactionStatus = EFI_ABORTED;\r
+\r
+ if (Request->IsEnd) {\r
+ gBS->SignalEvent (Request->Token->Event);\r
+ }\r
+\r
+ FreePool (Request);\r
+ }\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ //\r
+ // Close the child handle\r
+ //\r
+ Status = gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index]\r
+ );\r
+\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ ChildHandleBuffer[Index],\r
+ &gEfiDevicePathProtocolGuid,\r
+ Device->DevicePath,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &Device->BlockIo,\r
+ &gEfiBlockIo2ProtocolGuid,\r
+ &Device->BlockIo2,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ AllChildrenStopped = FALSE;\r
+ gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSdMmcPassThruProtocolGuid,\r
+ (VOID **)&PassThru,\r
+ This->DriverBindingHandle,\r
+ ChildHandleBuffer[Index],\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ } else {\r
+ FreePool (Device->DevicePath);\r
+ FreeUnicodeStringTable (Device->ControllerNameTable);\r
+ FreePool (Device);\r
+ }\r
+ }\r
+\r
+ if (!AllChildrenStopped) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ The user Entry Point for module SdDxe. The user code starts with this function.\r
+\r
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
+ @param[in] SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The entry point is executed successfully.\r
+ @retval other Some errors occur when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSdDxe (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Install driver model protocol(s).\r
+ //\r
+ Status = EfiLibInstallDriverBindingComponentName2 (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gSdDxeDriverBinding,\r
+ ImageHandle,\r
+ &gSdDxeComponentName,\r
+ &gSdDxeComponentName2\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ Header file for SdDxe Driver.\r
+\r
+ This file defines common data structures, macro definitions and some module\r
+ internal function header files.\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_DXE_H_\r
+#define _SD_DXE_H_\r
+\r
+#include <Uefi.h>\r
+#include <IndustryStandard/Sd.h>\r
+\r
+#include <Protocol/SdMmcPassThru.h>\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/BlockIo2.h>\r
+\r
+#include <Protocol/DevicePath.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+\r
+#include "SdBlockIo.h"\r
+//\r
+// Global Variables\r
+//\r
+extern EFI_DRIVER_BINDING_PROTOCOL gSdDxeDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL gSdDxeComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL gSdDxeComponentName2;\r
+\r
+#define SD_DEVICE_SIGNATURE SIGNATURE_32 ('S', 'D', 't', 'f')\r
+\r
+#define SD_DEVICE_DATA_FROM_BLKIO(a) \\r
+ CR(a, SD_DEVICE, BlockIo, SD_DEVICE_SIGNATURE)\r
+\r
+#define SD_DEVICE_DATA_FROM_BLKIO2(a) \\r
+ CR(a, SD_DEVICE, BlockIo2, SD_DEVICE_SIGNATURE)\r
+\r
+//\r
+// Take 2.5 seconds as generic time out value, 1 microsecond as unit.\r
+//\r
+#define SD_GENERIC_TIMEOUT 2500 * 1000\r
+\r
+#define SD_REQUEST_SIGNATURE SIGNATURE_32 ('S', 'D', 'R', 'E')\r
+\r
+#define SD_MODEL_NAME_MAX_LEN 32\r
+\r
+typedef struct _SD_DEVICE SD_DEVICE;\r
+typedef struct _SD_DRIVER_PRIVATE_DATA SD_DRIVER_PRIVATE_DATA;\r
+\r
+//\r
+// Asynchronous I/O request.\r
+//\r
+typedef struct {\r
+ UINT32 Signature;\r
+ LIST_ENTRY Link;\r
+\r
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ BOOLEAN IsEnd;\r
+\r
+ EFI_BLOCK_IO2_TOKEN *Token;\r
+\r
+ EFI_EVENT Event;\r
+} SD_REQUEST;\r
+\r
+#define SD_REQUEST_FROM_LINK(a) \\r
+ CR(a, SD_REQUEST, Link, SD_REQUEST_SIGNATURE)\r
+\r
+struct _SD_DEVICE {\r
+ UINT32 Signature;\r
+ EFI_HANDLE Handle;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ UINT8 Slot;\r
+ BOOLEAN SectorAddressing;\r
+ EFI_BLOCK_IO_PROTOCOL BlockIo;\r
+ EFI_BLOCK_IO2_PROTOCOL BlockIo2;\r
+ EFI_BLOCK_IO_MEDIA BlockMedia;\r
+\r
+ LIST_ENTRY Queue;\r
+\r
+ SD_CSD Csd;\r
+ SD_CID Cid;\r
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;\r
+ //\r
+ // The model name consists of three fields in CID register\r
+ // 1) OEM/Application ID (2 bytes)\r
+ // 2) Product Name (5 bytes)\r
+ // 3) Product Serial Number (4 bytes)\r
+ // The delimiters of these fields are whitespace.\r
+ //\r
+ CHAR16 ModelName[SD_MODEL_NAME_MAX_LEN];\r
+ SD_DRIVER_PRIVATE_DATA *Private;\r
+} ;\r
+\r
+//\r
+// SD DXE driver private data structure\r
+//\r
+struct _SD_DRIVER_PRIVATE_DATA {\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ EFI_HANDLE Controller;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ EFI_HANDLE DriverBindingHandle;\r
+} ;\r
+\r
+/**\r
+ Tests to see if this driver supports a given controller. If a child device is provided,\r
+ it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+ This function checks to see if the driver specified by This supports the device specified by\r
+ ControllerHandle. Drivers will typically use the device path attached to\r
+ ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+ ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+ may be called many times during platform initialization. In order to reduce boot times, the tests\r
+ performed by this function must be very small, and take as little time as possible to execute. This\r
+ function must not change the state of any hardware devices, and this function must be aware that the\r
+ device specified by ControllerHandle may already be managed by the same driver or a\r
+ different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+ to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to test. This handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For bus drivers, if this parameter is not NULL, then\r
+ the bus driver must determine if the bus controller specified\r
+ by ControllerHandle and the child controller specified\r
+ by RemainingDevicePath are both supported by this\r
+ bus driver.\r
+\r
+ @retval EFI_SUCCESS The device specified by ControllerHandle and\r
+ RemainingDevicePath is supported by the driver specified by This.\r
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by the driver\r
+ specified by This.\r
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by a different\r
+ driver or an application that requires exclusive access.\r
+ Currently not implemented.\r
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Starts a device controller or a bus controller.\r
+\r
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+ As a result, much of the error checking on the parameters to Start() has been moved into this\r
+ common boot service. It is legal to call Start() from other locations,\r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE.\r
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+ EFI_DEVICE_PATH_PROTOCOL.\r
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to start. This handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For a bus driver, if this parameter is NULL, then handles\r
+ for all the children of Controller are created by this driver.\r
+ If this parameter is not NULL and the first Device Path Node is\r
+ not the End of Device Path Node, then only the handle for the\r
+ child device specified by the first Device Path Node of\r
+ RemainingDevicePath is created by this driver.\r
+ If the first Device Path Node of RemainingDevicePath is\r
+ the End of Device Path Node, no child handle is created by this\r
+ driver.\r
+\r
+ @retval EFI_SUCCESS The device was started.\r
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval Others The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Stops a device controller or a bus controller.\r
+\r
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+ As a result, much of the error checking on the parameters to Stop() has been moved\r
+ into this common boot service. It is legal to call Stop() from other locations,\r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+ same driver's Start() function.\r
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+ Start() function, and the Start() function must have called OpenProtocol() on\r
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must\r
+ support a bus specific I/O protocol for the driver\r
+ to use to stop the device.\r
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+ if NumberOfChildren is 0.\r
+\r
+ @retval EFI_SUCCESS The device was stopped.\r
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ );\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ );\r
+\r
+/**\r
+ Send command SET_RELATIVE_ADDRESS to the device to set the device address.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[out] Rca The relative device address to assign.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdSetRca (\r
+ IN SD_DEVICE *Device,\r
+ OUT UINT16 *Rca\r
+ );\r
+\r
+/**\r
+ Send command SELECT to the device to select/deselect the device.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdSelect (\r
+ IN SD_DEVICE *Device,\r
+ IN UINT16 Rca\r
+ );\r
+\r
+/**\r
+ Send command SEND_STATUS to the device to get device status.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+ @param[out] DevStatus The buffer to store the device status.\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdSendStatus (\r
+ IN SD_DEVICE *Device,\r
+ IN UINT16 Rca,\r
+ OUT UINT32 *DevStatus\r
+ );\r
+\r
+/**\r
+ Send command SEND_CSD to the device to get the CSD register data.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+ @param[out] Csd The buffer to store the SD_CSD register data.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdGetCsd (\r
+ IN SD_DEVICE *Device,\r
+ IN UINT16 Rca,\r
+ OUT SD_CSD *Csd\r
+ );\r
+\r
+/**\r
+ Send command SEND_CID to the device to get the CID register data.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] Rca The relative device address to use.\r
+ @param[out] Cid The buffer to store the SD_CID register data.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdGetCid (\r
+ IN SD_DEVICE *Device,\r
+ IN UINT16 Rca,\r
+ OUT SD_CID *Cid\r
+ );\r
+\r
+#endif\r
+\r
--- /dev/null
+## @file\r
+# SdDxe driver is used to manage the SD memory card device.\r
+#\r
+# It produces BlockIo and BlockIo2 protocols to allow upper layer\r
+# access the SD memory card device.\r
+#\r
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = SdDxe\r
+ MODULE_UNI_FILE = SdDxe.uni\r
+ FILE_GUID = 430AC2F7-EEC6-4093-94F7-9F825A7C1C40\r
+ MODULE_TYPE = UEFI_DRIVER\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = InitializeSdDxe\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+# DRIVER_BINDING = gSdDxeDriverBinding\r
+# COMPONENT_NAME = gSdDxeComponentName\r
+# COMPONENT_NAME2 = gSdDxeComponentName2\r
+#\r
+\r
+[Sources.common]\r
+ ComponentName.c\r
+ SdDxe.c\r
+ SdDxe.h\r
+ SdBlockIo.c\r
+ SdBlockIo.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+ DevicePathLib\r
+ UefiBootServicesTableLib\r
+ MemoryAllocationLib\r
+ BaseMemoryLib\r
+ UefiLib\r
+ BaseLib\r
+ UefiDriverEntryPoint\r
+ DebugLib\r
+\r
+[Protocols]\r
+ gEfiSdMmcPassThruProtocolGuid ## TO_START\r
+ gEfiBlockIoProtocolGuid ## BY_START\r
+ gEfiBlockIo2ProtocolGuid ## BY_START\r
+ ## TO_START\r
+ ## BY_START\r
+ gEfiDevicePathProtocolGuid\r
+\r
--- /dev/null
+// /** @file\r
+// SD memory card device driver to manage the SD memory card device and provide interface for upper layer\r
+// access.\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "SD device driver to manage the SD memory card device and provide interface for upper layer access"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "This driver follows the UEFI driver model and layers on the SdMmcPassThru protocol. It installs BlockIo and BlockIo2 protocols on the SD device."\r
+\r
--- /dev/null
+// /** @file\r
+// SD memory card device driver to manage the SD memory card device and provide interface for upper layer\r
+// access.\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "SD device driver to manage the SD memory card device and provide interface for upper layer access"\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "This driver follows the UEFI driver model and layers on the SdMmcPassThru protocol. It installs BlockIo and BlockIo2 protocols on the SD device."\r
+\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EDKII_PEI_SD_MMC_HOST_CONTROLLER_PPI_H_\r
+#define _EDKII_PEI_SD_MMC_HOST_CONTROLLER_PPI_H_\r
+\r
+///\r
+/// Global ID for the EDKII_SD_MMC_HOST_CONTROLLER_PPI.\r
+///\r
+#define EDKII_SD_MMC_HOST_CONTROLLER_PPI_GUID \\r
+ { \\r
+ 0xb30dfeed, 0x947f, 0x4396, { 0xb1, 0x5a, 0xdf, 0xbd, 0xb9, 0x16, 0xdc, 0x24 } \\r
+ }\r
+\r
+///\r
+/// Forward declaration for the SD_MMC_HOST_CONTROLLER_PPI.\r
+///\r
+typedef struct _EDKII_SD_MMC_HOST_CONTROLLER_PPI EDKII_SD_MMC_HOST_CONTROLLER_PPI;\r
+\r
+/**\r
+ Get the MMIO base address of SD/MMC host controller.\r
+\r
+ @param[in] This The protocol instance pointer.\r
+ @param[in] ControllerId The ID of the SD/MMC host controller.\r
+ @param[in,out] MmioBar The pointer to store the array of available\r
+ SD/MMC host controller slot MMIO base addresses.\r
+ The entry number of the array is specified by BarNum.\r
+ @param[out] BarNum The pointer to store the supported bar number.\r
+\r
+ @retval EFI_SUCCESS The operation succeeds.\r
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EDKII_SD_MMC_HC_GET_MMIO_BAR)(\r
+ IN EDKII_SD_MMC_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 ControllerId,\r
+ IN OUT UINTN **MmioBar,\r
+ OUT UINT8 *BarNum\r
+ );\r
+\r
+///\r
+/// This PPI contains a set of services to interact with the SD_MMC host controller.\r
+///\r
+struct _EDKII_SD_MMC_HOST_CONTROLLER_PPI {\r
+ EDKII_SD_MMC_HC_GET_MMIO_BAR GetSdMmcHcMmioBar;\r
+};\r
+\r
+extern EFI_GUID gEdkiiPeiSdMmcHostControllerPpiGuid;\r
+\r
+#endif\r
## Include/Ppi/IpmiPpi.h\r
gPeiIpmiPpiGuid = { 0xa9731431, 0xd968, 0x4277, { 0xb7, 0x52, 0xa3, 0xa9, 0xa6, 0xae, 0x18, 0x98 }}\r
\r
+ ## Include/Ppi/SdMmcHostController.h\r
+ gEdkiiPeiSdMmcHostControllerPpiGuid = { 0xb30dfeed, 0x947f, 0x4396, { 0xb1, 0x5a, 0xdf, 0xbd, 0xb9, 0x16, 0xdc, 0x24 }}\r
+\r
[Protocols]\r
## Load File protocol provides capability to load and unload EFI image into memory and execute it.\r
# Include/Protocol/LoadPe32Image.h\r
# @Prompt Set NX for stack.\r
gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack|FALSE|BOOLEAN|0x0001006f\r
\r
+ ## This PCD specifies the PCI-based SD/MMC host controller mmio base address.\r
+ # Define the mmio base address of the pci-based SD/MMC host controller. If there are multiple SD/MMC\r
+ # host controllers, their mmio base addresses are calculated one by one from this base address.\r
+ # @Prompt Mmio base address of pci-based SD/MMC host controller.\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSdMmcPciHostControllerMmioBase|0xd0000000|UINT32|0x30001043\r
+\r
[PcdsPatchableInModule]\r
## Specify memory size with page number for PEI code when\r
# Loading Module at Fixed Address feature is enabled.\r
MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf\r
MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf\r
MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf\r
+ MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf\r
+ MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.inf\r
+ MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.inf\r
+ MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.inf\r
+ MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf\r
+ MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf\r
MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.inf\r
MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf\r
MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.inf\r