diff options
author | 2023-10-10 14:33:42 +0000 | |
---|---|---|
committer | 2023-10-10 14:33:42 +0000 | |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe')
-rw-r--r-- | roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/ComponentName.c | 236 | ||||
-rw-r--r-- | roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c | 2161 | ||||
-rw-r--r-- | roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h | 497 | ||||
-rw-r--r-- | roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.c | 134 | ||||
-rw-r--r-- | roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.h | 109 | ||||
-rw-r--r-- | roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c | 1205 | ||||
-rw-r--r-- | roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h | 501 | ||||
-rw-r--r-- | roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf | 65 | ||||
-rw-r--r-- | roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.uni | 15 | ||||
-rw-r--r-- | roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxeExtra.uni | 14 |
10 files changed, 4937 insertions, 0 deletions
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/ComponentName.c new file mode 100644 index 000000000..6a4d18d4d --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/ComponentName.c @@ -0,0 +1,236 @@ +/** @file
+ UEFI Component Name(2) protocol implementation for EmmcDxe driver.
+
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EmmcDxe.h"
+
+//
+// Driver name table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mEmmcDxeDriverNameTable[] = {
+ { "eng;en", L"Edkii Emmc Device Driver" },
+ { NULL , NULL }
+};
+
+//
+// Controller name table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mEmmcDxeControllerNameTable[] = {
+ { "eng;en", L"Edkii Emmc Host Controller" },
+ { NULL , NULL }
+};
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gEmmcDxeComponentName = {
+ EmmcDxeComponentNameGetDriverName,
+ EmmcDxeComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gEmmcDxeComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) EmmcDxeComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) EmmcDxeComponentNameGetControllerName,
+ "en"
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDxeComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mEmmcDxeDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gEmmcDxeComponentName)
+ );
+
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDxeComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EMMC_DEVICE *Device;
+ EMMC_PARTITION *Partition;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+ //
+ // Make sure this driver is currently managing ControllHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gEmmcDxeDriverBinding.DriverBindingHandle,
+ &gEfiSdMmcPassThruProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ControllerNameTable = mEmmcDxeControllerNameTable;
+ if (ChildHandle != NULL) {
+ Status = EfiTestChildHandle (
+ ControllerHandle,
+ ChildHandle,
+ &gEfiSdMmcPassThruProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the child context
+ //
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ gEmmcDxeDriverBinding.DriverBindingHandle,
+ ChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO (BlockIo);
+ Device = Partition->Device;
+ ControllerNameTable = Device->ControllerNameTable;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gEmmcDxeComponentName)
+ );
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c new file mode 100644 index 000000000..afdc0a57e --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c @@ -0,0 +1,2161 @@ +/** @file
+ The helper functions for BlockIo and BlockIo2 protocol.
+
+ Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EmmcDxe.h"
+
+/**
+ Nonblocking I/O callback function when the event is signaled.
+
+ @param[in] Event The Event this notify function registered to.
+ @param[in] Context Pointer to the context data registered to the
+ Event.
+
+**/
+VOID
+EFIAPI
+AsyncIoCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EMMC_REQUEST *Request;
+ EFI_STATUS Status;
+
+ Status = gBS->CloseEvent (Event);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ Request = (EMMC_REQUEST *) Context;
+
+ DEBUG_CODE_BEGIN ();
+ DEBUG ((EFI_D_INFO, "Emmc Async Request: CmdIndex[%d] Arg[%08x] %r\n",
+ Request->SdMmcCmdBlk.CommandIndex, Request->SdMmcCmdBlk.CommandArgument,
+ Request->Packet.TransactionStatus));
+ DEBUG_CODE_END ();
+
+ if (EFI_ERROR (Request->Packet.TransactionStatus)) {
+ Request->Token->TransactionStatus = Request->Packet.TransactionStatus;
+ }
+
+ RemoveEntryList (&Request->Link);
+
+ if (Request->IsEnd) {
+ gBS->SignalEvent (Request->Token->Event);
+ }
+
+ FreePool (Request);
+}
+
+/**
+ Send command SELECT to the device to select/deselect the device.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcSelect (
+ IN EMMC_DEVICE *Device,
+ IN UINT16 Rca
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ PassThru = Device->Private->PassThru;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Send command SEND_STATUS to the device to get device status.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] DevStatus The buffer to store the device status.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcSendStatus (
+ IN EMMC_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT UINT32 *DevStatus
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ PassThru = Device->Private->PassThru;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ CopyMem (DevStatus, &SdMmcStatusBlk.Resp0, sizeof (UINT32));
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_CSD to the device to get the CSD register data.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] Csd The buffer to store the EMMC_CSD register data.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcGetCsd (
+ IN EMMC_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT EMMC_CSD *Csd
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ PassThru = Device->Private->PassThru;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+ ZeroMem (Csd, sizeof (EMMC_CSD));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_CID to the device to get the CID register data.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] Cid The buffer to store the EMMC_CID register data.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcGetCid (
+ IN EMMC_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT EMMC_CID *Cid
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ PassThru = Device->Private->PassThru;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+ ZeroMem (Cid, sizeof (EMMC_CID));
+
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_CID;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+ SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
+ if (!EFI_ERROR (Status)) {
+ //
+ // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+ //
+ CopyMem (((UINT8*)Cid) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CID) - 1);
+ }
+
+ return Status;
+}
+
+/**
+ Send command SEND_EXT_CSD to the device to get the EXT_CSD register data.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[out] ExtCsd The buffer to store the EXT_CSD register data.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcGetExtCsd (
+ IN EMMC_DEVICE *Device,
+ OUT EMMC_EXT_CSD *ExtCsd
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ PassThru = Device->Private->PassThru;
+
+ ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+ ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+ ZeroMem (&Packet, sizeof (Packet));
+ ZeroMem (ExtCsd, sizeof (EMMC_EXT_CSD));
+ Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
+ Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+ Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;
+ SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SdMmcCmdBlk.CommandArgument = 0x00000000;
+ Packet.InDataBuffer = ExtCsd;
+ Packet.InTransferLength = sizeof (EMMC_EXT_CSD);
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
+
+ return Status;
+}
+
+/**
+ Set the specified EXT_CSD register field through sync or async I/O request.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] Offset The offset of the specified field in EXT_CSD register.
+ @param[in] Value The byte value written to the field specified by Offset.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcSetExtCsd (
+ IN EMMC_PARTITION *Partition,
+ IN UINT8 Offset,
+ IN UINT8 Value,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EMMC_DEVICE *Device;
+ EMMC_REQUEST *SetExtCsdReq;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ UINT32 CommandArgument;
+ EFI_TPL OldTpl;
+
+ SetExtCsdReq = NULL;
+
+ Device = Partition->Device;
+ PassThru = Device->Private->PassThru;
+
+ SetExtCsdReq = AllocateZeroPool (sizeof (EMMC_REQUEST));
+ if (SetExtCsdReq == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ SetExtCsdReq->Signature = EMMC_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Partition->Queue, &SetExtCsdReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ SetExtCsdReq->Packet.SdMmcCmdBlk = &SetExtCsdReq->SdMmcCmdBlk;
+ SetExtCsdReq->Packet.SdMmcStatusBlk = &SetExtCsdReq->SdMmcStatusBlk;
+ SetExtCsdReq->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ SetExtCsdReq->SdMmcCmdBlk.CommandIndex = EMMC_SWITCH;
+ SetExtCsdReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SetExtCsdReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
+ //
+ // Write the Value to the field specified by Offset.
+ //
+ CommandArgument = (Value << 8) | (Offset << 16) | BIT24 | BIT25;
+ SetExtCsdReq->SdMmcCmdBlk.CommandArgument = CommandArgument;
+
+ SetExtCsdReq->IsEnd = IsEnd;
+ SetExtCsdReq->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ SetExtCsdReq,
+ &SetExtCsdReq->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ SetExtCsdReq->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &SetExtCsdReq->Packet, SetExtCsdReq->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (SetExtCsdReq != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&SetExtCsdReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (SetExtCsdReq->Event != NULL) {
+ gBS->CloseEvent (SetExtCsdReq->Event);
+ }
+ FreePool (SetExtCsdReq);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (SetExtCsdReq != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&SetExtCsdReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (SetExtCsdReq);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Set the number of blocks for a block read/write cmd through sync or async I/O request.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] BlockNum The number of blocks for transfer.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcSetBlkCount (
+ IN EMMC_PARTITION *Partition,
+ IN UINT16 BlockNum,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EMMC_DEVICE *Device;
+ EMMC_REQUEST *SetBlkCntReq;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_TPL OldTpl;
+
+ SetBlkCntReq = NULL;
+
+ Device = Partition->Device;
+ PassThru = Device->Private->PassThru;
+
+ SetBlkCntReq = AllocateZeroPool (sizeof (EMMC_REQUEST));
+ if (SetBlkCntReq == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ SetBlkCntReq->Signature = EMMC_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Partition->Queue, &SetBlkCntReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ SetBlkCntReq->Packet.SdMmcCmdBlk = &SetBlkCntReq->SdMmcCmdBlk;
+ SetBlkCntReq->Packet.SdMmcStatusBlk = &SetBlkCntReq->SdMmcStatusBlk;
+ SetBlkCntReq->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ SetBlkCntReq->SdMmcCmdBlk.CommandIndex = EMMC_SET_BLOCK_COUNT;
+ SetBlkCntReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ SetBlkCntReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ SetBlkCntReq->SdMmcCmdBlk.CommandArgument = BlockNum;
+
+ SetBlkCntReq->IsEnd = IsEnd;
+ SetBlkCntReq->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ SetBlkCntReq,
+ &SetBlkCntReq->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ SetBlkCntReq->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &SetBlkCntReq->Packet, SetBlkCntReq->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (SetBlkCntReq != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&SetBlkCntReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (SetBlkCntReq->Event != NULL) {
+ gBS->CloseEvent (SetBlkCntReq->Event);
+ }
+ FreePool (SetBlkCntReq);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (SetBlkCntReq != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&SetBlkCntReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (SetBlkCntReq);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Read blocks through security protocol cmds with the way of sync or async I/O request.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
+ @param[out] PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param[in] IsRead Indicates it is a read or write operation.
+ @param[in] Timeout The timeout value, in 100ns units.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcProtocolInOut (
+ IN EMMC_PARTITION *Partition,
+ IN UINT8 SecurityProtocol,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ IN BOOLEAN IsRead,
+ IN UINT64 Timeout,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EMMC_DEVICE *Device;
+ EMMC_REQUEST *ProtocolReq;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_TPL OldTpl;
+
+ ProtocolReq = NULL;
+
+ Device = Partition->Device;
+ PassThru = Device->Private->PassThru;
+
+ ProtocolReq = AllocateZeroPool (sizeof (EMMC_REQUEST));
+ if (ProtocolReq == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ ProtocolReq->Signature = EMMC_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Partition->Queue, &ProtocolReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ ProtocolReq->Packet.SdMmcCmdBlk = &ProtocolReq->SdMmcCmdBlk;
+ ProtocolReq->Packet.SdMmcStatusBlk = &ProtocolReq->SdMmcStatusBlk;
+
+ if (IsRead) {
+ ProtocolReq->Packet.InDataBuffer = PayloadBuffer;
+ ProtocolReq->Packet.InTransferLength = (UINT32)PayloadBufferSize;
+
+ ProtocolReq->SdMmcCmdBlk.CommandIndex = EMMC_PROTOCOL_RD;
+ ProtocolReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ ProtocolReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ } else {
+ ProtocolReq->Packet.OutDataBuffer = PayloadBuffer;
+ ProtocolReq->Packet.OutTransferLength = (UINT32)PayloadBufferSize;
+
+ ProtocolReq->SdMmcCmdBlk.CommandIndex = EMMC_PROTOCOL_WR;
+ ProtocolReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ ProtocolReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ }
+
+ ProtocolReq->SdMmcCmdBlk.CommandArgument = (SecurityProtocol << 8) | (SecurityProtocolSpecificData << 16);
+ //
+ // Convert to 1 microsecond unit.
+ //
+ ProtocolReq->Packet.Timeout = DivU64x32 (Timeout, 10) + 1;
+
+ ProtocolReq->IsEnd = IsEnd;
+ ProtocolReq->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ ProtocolReq,
+ &ProtocolReq->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ ProtocolReq->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &ProtocolReq->Packet, ProtocolReq->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (ProtocolReq != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&ProtocolReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (ProtocolReq->Event != NULL) {
+ gBS->CloseEvent (ProtocolReq->Event);
+ }
+ FreePool (ProtocolReq);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (ProtocolReq != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&ProtocolReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (ProtocolReq);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Read/write multiple blocks through sync or async I/O request.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] Lba The starting logical block address to be read/written.
+ The caller is responsible for reading/writing to only
+ legitimate locations.
+ @param[in] Buffer A pointer to the destination/source buffer for the data.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] IsRead Indicates it is a read or write operation.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcRwMultiBlocks (
+ IN EMMC_PARTITION *Partition,
+ IN EFI_LBA Lba,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ IN BOOLEAN IsRead,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EMMC_DEVICE *Device;
+ EMMC_REQUEST *RwMultiBlkReq;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_TPL OldTpl;
+
+ RwMultiBlkReq = NULL;
+
+ Device = Partition->Device;
+ PassThru = Device->Private->PassThru;
+
+ RwMultiBlkReq = AllocateZeroPool (sizeof (EMMC_REQUEST));
+ if (RwMultiBlkReq == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ RwMultiBlkReq->Signature = EMMC_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Partition->Queue, &RwMultiBlkReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ RwMultiBlkReq->Packet.SdMmcCmdBlk = &RwMultiBlkReq->SdMmcCmdBlk;
+ RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk;
+ //
+ // Calculate timeout value through the below formula.
+ // Timeout = (transfer size) / (2MB/s).
+ // Taking 2MB/s as divisor is because it's nearest to the eMMC lowest
+ // transfer speed (2.4MB/s).
+ // Refer to eMMC 5.0 spec section 6.9.1 for details.
+ //
+ RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
+
+ if (IsRead) {
+ RwMultiBlkReq->Packet.InDataBuffer = Buffer;
+ RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;
+
+ RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = EMMC_READ_MULTIPLE_BLOCK;
+ RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ } else {
+ RwMultiBlkReq->Packet.OutDataBuffer = Buffer;
+ RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
+
+ RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = EMMC_WRITE_MULTIPLE_BLOCK;
+ RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
+ RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+ }
+
+ if (Partition->Device->SectorAddressing) {
+ RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
+ } else {
+ RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Partition->BlockMedia.BlockSize);
+ }
+
+ RwMultiBlkReq->IsEnd = IsEnd;
+ RwMultiBlkReq->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ RwMultiBlkReq,
+ &RwMultiBlkReq->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ RwMultiBlkReq->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&RwMultiBlkReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (RwMultiBlkReq->Event != NULL) {
+ gBS->CloseEvent (RwMultiBlkReq->Event);
+ }
+ FreePool (RwMultiBlkReq);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (RwMultiBlkReq != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&RwMultiBlkReq->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (RwMultiBlkReq);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ This function transfers data from/to EMMC device.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] MediaId The media ID that the read/write request is for.
+ @param[in] Lba The starting logical block address to be read/written.
+ The caller is responsible for reading/writing to only
+ legitimate locations.
+ @param[in, out] Buffer A pointer to the destination/source buffer for the data.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] IsRead Indicates it is a read or write operation.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+
+ @retval EFI_SUCCESS The data was read/written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be read/written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EmmcReadWrite (
+ IN EMMC_PARTITION *Partition,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT VOID *Buffer,
+ IN UINTN BufferSize,
+ IN BOOLEAN IsRead,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ EMMC_DEVICE *Device;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN BlockNum;
+ UINTN IoAlign;
+ UINT8 PartitionConfig;
+ UINTN Remaining;
+ UINT32 MaxBlock;
+ BOOLEAN LastRw;
+
+ Status = EFI_SUCCESS;
+ Device = Partition->Device;
+ Media = &Partition->BlockMedia;
+ LastRw = FALSE;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (!IsRead && Media->ReadOnly) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ //
+ // Check parameters.
+ //
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+ return EFI_SUCCESS;
+ }
+
+ BlockSize = Media->BlockSize;
+ if ((BufferSize % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ BlockNum = BufferSize / BlockSize;
+ if ((Lba + BlockNum - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IoAlign = Media->IoAlign;
+ if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ }
+ //
+ // Check if needs to switch partition access.
+ //
+ PartitionConfig = Device->ExtCsd.PartitionConfig;
+ if ((PartitionConfig & 0x7) != Partition->PartitionType) {
+ PartitionConfig &= (UINT8)~0x7;
+ PartitionConfig |= Partition->PartitionType;
+ Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, Token, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Device->ExtCsd.PartitionConfig = PartitionConfig;
+ }
+ //
+ // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
+ //
+ Remaining = BlockNum;
+ MaxBlock = 0xFFFF;
+
+ while (Remaining > 0) {
+ if (Remaining <= MaxBlock) {
+ BlockNum = Remaining;
+ LastRw = TRUE;
+ } else {
+ BlockNum = MaxBlock;
+ }
+ Status = EmmcSetBlkCount (Partition, (UINT16)BlockNum, Token, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BufferSize = BlockNum * BlockSize;
+ Status = EmmcRwMultiBlocks (Partition, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DEBUG ((DEBUG_BLKIO,
+ "Emmc%a(): Part %d Lba 0x%x BlkNo 0x%x Event %p with %r\n",
+ IsRead ? "Read " : "Write", Partition->PartitionType, Lba, BlockNum,
+ (Token != NULL) ? Token->Event : NULL, Status));
+
+ Lba += BlockNum;
+ Buffer = (UINT8*)Buffer + BufferSize;
+ Remaining -= BlockNum;
+ }
+
+ return Status;
+}
+
+/**
+ Reset the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);
+
+ PassThru = Partition->Device->Private->PassThru;
+ Status = PassThru->ResetDevice (PassThru, Partition->Device->Slot);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);
+
+ Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);
+ return Status;
+}
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written. The caller is
+ responsible for writing to only legitimate locations.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);
+
+ Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);
+ return Status;
+}
+
+/**
+ Flush the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ //
+ // return directly
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Reset the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcResetEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EMMC_PARTITION *Partition;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ EMMC_REQUEST *Request;
+ EFI_TPL OldTpl;
+
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ for (Link = GetFirstNode (&Partition->Queue);
+ !IsNull (&Partition->Queue, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Partition->Queue, Link);
+ RemoveEntryList (Link);
+
+ Request = EMMC_REQUEST_FROM_LINK (Link);
+
+ gBS->CloseEvent (Request->Event);
+ Request->Token->TransactionStatus = EFI_ABORTED;
+
+ if (Request->IsEnd) {
+ gBS->SignalEvent (Request->Token->Event);
+ }
+
+ FreePool (Request);
+ }
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[out] Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The read request was queued if Event is not NULL.
+ The data was read correctly from the device if
+ the Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing
+ the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);
+
+ Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, TRUE, Token);
+ return Status;
+}
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written. The
+ caller is responsible for writing to only legitimate
+ locations.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcWriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);
+
+ Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, FALSE, Token);
+ return Status;
+}
+
+/**
+ Flush the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcFlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ //
+ // Signal event and return directly.
+ //
+ if (Token != NULL && Token->Event != NULL) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given MediaId.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function shall
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
+ the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId ID of the medium to receive data from.
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param[in] SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
+ @param[out] PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param[out] PayloadTransferSize A pointer to a buffer to store the size in bytes of the
+ data written to the payload data buffer.
+ @param[in] IsRead Indicates it is a read or write operation.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
+ data from the device. The PayloadBuffer contains the truncated data.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
+ PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcSecurityProtocolInOut (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize,
+ IN BOOLEAN IsRead
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+ EMMC_DEVICE *Device;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN BlockNum;
+ UINTN IoAlign;
+ UINTN Remaining;
+ UINT32 MaxBlock;
+ UINT8 PartitionConfig;
+
+ Status = EFI_SUCCESS;
+ Partition = EMMC_PARTITION_DATA_FROM_SSP (This);
+ Device = Partition->Device;
+ Media = &Partition->BlockMedia;
+
+ if (PayloadTransferSize != NULL) {
+ *PayloadTransferSize = 0;
+ }
+
+ if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (PayloadBufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BlockSize = Media->BlockSize;
+ if ((PayloadBufferSize % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ BlockNum = PayloadBufferSize / BlockSize;
+
+ IoAlign = Media->IoAlign;
+ if (IoAlign > 0 && (((UINTN) PayloadBuffer & (IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Security protocol interface is synchronous transfer.
+ // Waiting for async I/O list to be empty before any operation.
+ //
+ while (!IsListEmpty (&Partition->Queue));
+
+ //
+ // Check if needs to switch partition access.
+ //
+ PartitionConfig = Device->ExtCsd.PartitionConfig;
+ if ((PartitionConfig & 0x7) != Partition->PartitionType) {
+ PartitionConfig &= (UINT8)~0x7;
+ PartitionConfig |= Partition->PartitionType;
+ Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, NULL, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Device->ExtCsd.PartitionConfig = PartitionConfig;
+ }
+ //
+ // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
+ //
+ Remaining = BlockNum;
+ MaxBlock = 0xFFFF;
+
+ while (Remaining > 0) {
+ if (Remaining <= MaxBlock) {
+ BlockNum = Remaining;
+ } else {
+ BlockNum = MaxBlock;
+ }
+
+ Status = EmmcSetBlkCount (Partition, (UINT16)BlockNum, NULL, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PayloadBufferSize = BlockNum * BlockSize;
+ Status = EmmcProtocolInOut (Partition, SecurityProtocolId, SecurityProtocolSpecificData, PayloadBufferSize, PayloadBuffer, IsRead, Timeout, NULL, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PayloadBuffer = (UINT8*)PayloadBuffer + PayloadBufferSize;
+ Remaining -= BlockNum;
+ if (PayloadTransferSize != NULL) {
+ *PayloadTransferSize += PayloadBufferSize;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given MediaId.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function shall
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
+ the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
+ data written to the payload data buffer.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
+ data from the device. The PayloadBuffer contains the truncated data.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
+ PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcSecurityProtocolIn (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize
+ )
+{
+ EFI_STATUS Status;
+
+ if ((PayloadTransferSize == NULL) && PayloadBufferSize != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EmmcSecurityProtocolInOut (
+ This,
+ MediaId,
+ Timeout,
+ SecurityProtocolId,
+ SecurityProtocolSpecificData,
+ PayloadBufferSize,
+ PayloadBuffer,
+ PayloadTransferSize,
+ TRUE
+ );
+
+ return Status;
+}
+
+/**
+ Send a security protocol command to a device.
+
+ The SendData function sends a security protocol command containing the payload
+ PayloadBuffer to the given MediaId. The security protocol command sent is
+ defined by SecurityProtocolId and contains the security protocol specific data
+ SecurityProtocolSpecificData. If the underlying protocol command requires a
+ specific padding for the command payload, the SendData function shall add padding
+ bytes to the command payload to satisfy the padding requirements.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command is
+ sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+ return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED. If there is no media in the device, the function
+ returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
+ device, the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall return
+ EFI_SUCCESS. If the security protocol command completes with an error, the function
+ shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcSecurityProtocolOut (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ IN VOID *PayloadBuffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EmmcSecurityProtocolInOut (
+ This,
+ MediaId,
+ Timeout,
+ SecurityProtocolId,
+ SecurityProtocolSpecificData,
+ PayloadBufferSize,
+ PayloadBuffer,
+ NULL,
+ FALSE
+ );
+
+ return Status;
+}
+
+/**
+ Set the erase start address through sync or async I/O request.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] StartLba The starting logical block address to be erased.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcEraseBlockStart (
+ IN EMMC_PARTITION *Partition,
+ IN EFI_LBA StartLba,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EMMC_DEVICE *Device;
+ EMMC_REQUEST *EraseBlockStart;
+ EFI_TPL OldTpl;
+
+ EraseBlockStart = NULL;
+
+ Device = Partition->Device;
+ PassThru = Device->Private->PassThru;
+
+ EraseBlockStart = AllocateZeroPool (sizeof (EMMC_REQUEST));
+ if (EraseBlockStart == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ EraseBlockStart->Signature = EMMC_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Partition->Queue, &EraseBlockStart->Link);
+ gBS->RestoreTPL (OldTpl);
+ EraseBlockStart->Packet.SdMmcCmdBlk = &EraseBlockStart->SdMmcCmdBlk;
+ EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;
+ EraseBlockStart->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ EraseBlockStart->SdMmcCmdBlk.CommandIndex = EMMC_ERASE_GROUP_START;
+ EraseBlockStart->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+ if (Device->SectorAddressing) {
+ EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;
+ } else {
+ EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (StartLba, Partition->BlockMedia.BlockSize);
+ }
+
+ EraseBlockStart->IsEnd = IsEnd;
+ EraseBlockStart->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ EraseBlockStart,
+ &EraseBlockStart->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ EraseBlockStart->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockStart->Packet, EraseBlockStart->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (EraseBlockStart != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlockStart->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (EraseBlockStart->Event != NULL) {
+ gBS->CloseEvent (EraseBlockStart->Event);
+ }
+ FreePool (EraseBlockStart);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (EraseBlockStart != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlockStart->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (EraseBlockStart);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Set the erase end address through sync or async I/O request.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] EndLba The ending logical block address to be erased.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcEraseBlockEnd (
+ IN EMMC_PARTITION *Partition,
+ IN EFI_LBA EndLba,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EMMC_DEVICE *Device;
+ EMMC_REQUEST *EraseBlockEnd;
+ EFI_TPL OldTpl;
+
+ EraseBlockEnd = NULL;
+
+ Device = Partition->Device;
+ PassThru = Device->Private->PassThru;
+
+ EraseBlockEnd = AllocateZeroPool (sizeof (EMMC_REQUEST));
+ if (EraseBlockEnd == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ EraseBlockEnd->Signature = EMMC_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Partition->Queue, &EraseBlockEnd->Link);
+ gBS->RestoreTPL (OldTpl);
+ EraseBlockEnd->Packet.SdMmcCmdBlk = &EraseBlockEnd->SdMmcCmdBlk;
+ EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;
+ EraseBlockEnd->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ EraseBlockEnd->SdMmcCmdBlk.CommandIndex = EMMC_ERASE_GROUP_END;
+ EraseBlockEnd->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+ if (Device->SectorAddressing) {
+ EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;
+ } else {
+ EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, Partition->BlockMedia.BlockSize);
+ }
+
+ EraseBlockEnd->IsEnd = IsEnd;
+ EraseBlockEnd->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ EraseBlockEnd,
+ &EraseBlockEnd->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ EraseBlockEnd->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockEnd->Packet, EraseBlockEnd->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (EraseBlockEnd != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlockEnd->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (EraseBlockEnd->Event != NULL) {
+ gBS->CloseEvent (EraseBlockEnd->Event);
+ }
+ FreePool (EraseBlockEnd);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (EraseBlockEnd != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlockEnd->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (EraseBlockEnd);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Erase specified blocks through sync or async I/O request.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] Token A pointer to the token associated with the transaction.
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
+ This parameter is only meaningful in async I/O request.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcEraseBlock (
+ IN EMMC_PARTITION *Partition,
+ IN EFI_BLOCK_IO2_TOKEN *Token,
+ IN BOOLEAN IsEnd
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EMMC_DEVICE *Device;
+ EMMC_REQUEST *EraseBlock;
+ EFI_TPL OldTpl;
+
+ EraseBlock = NULL;
+
+ Device = Partition->Device;
+ PassThru = Device->Private->PassThru;
+
+ EraseBlock = AllocateZeroPool (sizeof (EMMC_REQUEST));
+ if (EraseBlock == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ EraseBlock->Signature = EMMC_REQUEST_SIGNATURE;
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&Partition->Queue, &EraseBlock->Link);
+ gBS->RestoreTPL (OldTpl);
+ EraseBlock->Packet.SdMmcCmdBlk = &EraseBlock->SdMmcCmdBlk;
+ EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;
+ EraseBlock->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
+
+ EraseBlock->SdMmcCmdBlk.CommandIndex = EMMC_ERASE;
+ EraseBlock->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
+ EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
+ if ((Device->ExtCsd.SecFeatureSupport & BIT4) != 0) {
+ //
+ // Perform a Trim operation which applies the erase operation to write blocks
+ // instead of erase groups. (Spec JESD84-B51, eMMC Electrical Standard 5.1,
+ // Section 6.6.10 and 6.10.4)
+ //
+ EraseBlock->SdMmcCmdBlk.CommandArgument = 1;
+ }
+
+ EraseBlock->IsEnd = IsEnd;
+ EraseBlock->Token = Token;
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ AsyncIoCallback,
+ EraseBlock,
+ &EraseBlock->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ EraseBlock->Event = NULL;
+ }
+
+ Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlock->Packet, EraseBlock->Event);
+
+Error:
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ //
+ // For asynchronous operation, only free request and event in error case.
+ // The request and event will be freed in asynchronous callback for success case.
+ //
+ if (EFI_ERROR (Status) && (EraseBlock != NULL)) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlock->Link);
+ gBS->RestoreTPL (OldTpl);
+ if (EraseBlock->Event != NULL) {
+ gBS->CloseEvent (EraseBlock->Event);
+ }
+ FreePool (EraseBlock);
+ }
+ } else {
+ //
+ // For synchronous operation, free request whatever the execution result is.
+ //
+ if (EraseBlock != NULL) {
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ RemoveEntryList (&EraseBlock->Link);
+ gBS->RestoreTPL (OldTpl);
+ FreePool (EraseBlock);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Write zeros to specified blocks.
+
+ @param[in] Partition A pointer to the EMMC_PARTITION instance.
+ @param[in] StartLba The starting logical block address to write zeros.
+ @param[in] Size The size in bytes to fill with zeros. This must be a multiple of
+ the physical block size of the device.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcWriteZeros (
+ IN EMMC_PARTITION *Partition,
+ IN EFI_LBA StartLba,
+ IN UINTN Size
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Buffer;
+ UINT32 MediaId;
+
+ Buffer = AllocateZeroPool (Size);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ MediaId = Partition->BlockMedia.MediaId;
+
+ Status = EmmcReadWrite (Partition, MediaId, StartLba, Buffer, Size, FALSE, NULL);
+ FreePool (Buffer);
+
+ return Status;
+}
+
+/**
+ Erase a specified number of device blocks.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the erase request is for.
+ @param[in] Lba The starting logical block address to be
+ erased. The caller is responsible for erasing
+ only legitimate locations.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] Size The size in bytes to be erased. This must be
+ a multiple of the physical block size of the
+ device.
+
+ @retval EFI_SUCCESS The erase request was queued if Event is not
+ NULL. The data was erased correctly to the
+ device if the Event is NULL.to the device.
+ @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
+ protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the erase operation.
+ @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
+ valid.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcEraseBlocks (
+ IN EFI_ERASE_BLOCK_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
+ IN UINTN Size
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN BlockNum;
+ EFI_LBA FirstLba;
+ EFI_LBA LastLba;
+ EFI_LBA StartGroupLba;
+ EFI_LBA EndGroupLba;
+ UINT32 EraseGroupSize;
+ UINT32 Remainder;
+ UINTN WriteZeroSize;
+ UINT8 PartitionConfig;
+ EMMC_PARTITION *Partition;
+ EMMC_DEVICE *Device;
+
+ Status = EFI_SUCCESS;
+ Partition = EMMC_PARTITION_DATA_FROM_ERASEBLK (This);
+ Device = Partition->Device;
+ Media = &Partition->BlockMedia;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Media->ReadOnly) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ //
+ // Check parameters.
+ //
+ BlockSize = Media->BlockSize;
+ if ((Size % BlockSize) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BlockNum = Size / BlockSize;
+ if ((Lba + BlockNum - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ }
+
+ FirstLba = Lba;
+ LastLba = Lba + BlockNum - 1;
+
+ //
+ // Check if needs to switch partition access.
+ //
+ PartitionConfig = Device->ExtCsd.PartitionConfig;
+ if ((PartitionConfig & 0x7) != Partition->PartitionType) {
+ PartitionConfig &= (UINT8)~0x7;
+ PartitionConfig |= Partition->PartitionType;
+ Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Device->ExtCsd.PartitionConfig = PartitionConfig;
+ }
+
+ if ((Device->ExtCsd.SecFeatureSupport & BIT4) == 0) {
+ //
+ // If the Trim operation is not supported by the device, handle the erase
+ // of blocks that do not form a complete erase group separately.
+ //
+ EraseGroupSize = This->EraseLengthGranularity;
+
+ DivU64x32Remainder (FirstLba, EraseGroupSize, &Remainder);
+ StartGroupLba = (Remainder == 0) ? FirstLba : (FirstLba + EraseGroupSize - Remainder);
+
+ DivU64x32Remainder (LastLba + 1, EraseGroupSize, &Remainder);
+ EndGroupLba = LastLba + 1 - Remainder;
+
+ //
+ // If the size to erase is smaller than the erase group size, the whole
+ // erase operation is performed by writing zeros.
+ //
+ if (BlockNum < EraseGroupSize) {
+ Status = EmmcWriteZeros (Partition, FirstLba, Size);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
+ Lba,
+ BlockNum,
+ (Token != NULL) ? Token->Event : NULL,
+ Status
+ ));
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If the starting LBA to erase is not aligned with the start of an erase
+ // group, write zeros to erase the data from starting LBA to the end of the
+ // current erase group.
+ //
+ if (StartGroupLba > FirstLba) {
+ WriteZeroSize = (UINTN)(StartGroupLba - FirstLba) * BlockSize;
+ Status = EmmcWriteZeros (Partition, FirstLba, WriteZeroSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // If the ending LBA to erase is not aligned with the end of an erase
+ // group, write zeros to erase the data from the start of the erase group
+ // to the ending LBA.
+ //
+ if (EndGroupLba <= LastLba) {
+ WriteZeroSize = (UINTN)(LastLba + 1 - EndGroupLba) * BlockSize;
+ Status = EmmcWriteZeros (Partition, EndGroupLba, WriteZeroSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Check whether there is erase group to erase.
+ //
+ if (EndGroupLba <= StartGroupLba) {
+ DEBUG ((
+ DEBUG_INFO,
+ "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
+ Lba,
+ BlockNum,
+ (Token != NULL) ? Token->Event : NULL,
+ Status
+ ));
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+ return EFI_SUCCESS;
+ }
+
+ FirstLba = StartGroupLba;
+ LastLba = EndGroupLba - 1;
+ }
+
+ Status = EmmcEraseBlockStart (Partition, FirstLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcEraseBlockEnd (Partition, LastLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcEraseBlock (Partition, (EFI_BLOCK_IO2_TOKEN*)Token, TRUE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
+ Lba,
+ BlockNum,
+ (Token != NULL) ? Token->Event : NULL,
+ Status
+ ));
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h new file mode 100644 index 000000000..62e70ae91 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h @@ -0,0 +1,497 @@ +/** @file
+ Header file for EmmcDxe Driver.
+
+ This file defines common data structures, macro definitions and some module
+ internal function header files.
+
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EMMC_BLOCK_IO_H_
+#define _EMMC_BLOCK_IO_H_
+
+/**
+ Reset the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written. The caller is
+ responsible for writing to only legitimate locations.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flush the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ );
+
+/**
+ Reset the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcResetEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[out] Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The read request was queued if Event is not NULL.
+ The data was read correctly from the device if
+ the Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing
+ the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written. The
+ caller is responsible for writing to only legitimate
+ locations.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcWriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flush the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcFlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ );
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given MediaId.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function shall
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
+ the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId ID of the medium to receive data from.
+ @param[in] Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param[in] SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param[in] SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
+ @param[out] PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param[out] PayloadTransferSize A pointer to a buffer to store the size in bytes of the
+ data written to the payload data buffer.
+ @param[in] IsRead Indicates it is a read or write operation.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
+ data from the device. The PayloadBuffer contains the truncated data.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
+ PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcSecurityProtocolInOut (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize,
+ IN BOOLEAN IsRead
+ );
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given MediaId.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function shall
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
+ the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
+ data written to the payload data buffer.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
+ data from the device. The PayloadBuffer contains the truncated data.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
+ PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcSecurityProtocolIn (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize
+ );
+
+/**
+ Send a security protocol command to a device.
+
+ The SendData function sends a security protocol command containing the payload
+ PayloadBuffer to the given MediaId. The security protocol command sent is
+ defined by SecurityProtocolId and contains the security protocol specific data
+ SecurityProtocolSpecificData. If the underlying protocol command requires a
+ specific padding for the command payload, the SendData function shall add padding
+ bytes to the command payload to satisfy the padding requirements.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command is
+ sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+ return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED. If there is no media in the device, the function
+ returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
+ device, the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall return
+ EFI_SUCCESS. If the security protocol command completes with an error, the function
+ shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcSecurityProtocolOut (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ IN VOID *PayloadBuffer
+ );
+
+/**
+ Erase a specified number of device blocks.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the erase request is for.
+ @param[in] Lba The starting logical block address to be
+ erased. The caller is responsible for erasing
+ only legitimate locations.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] Size The size in bytes to be erased. This must be
+ a multiple of the physical block size of the
+ device.
+
+ @retval EFI_SUCCESS The erase request was queued if Event is not
+ NULL. The data was erased correctly to the
+ device if the Event is NULL.to the device.
+ @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
+ protection.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the erase operation.
+ @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
+ valid.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcEraseBlocks (
+ IN EFI_ERASE_BLOCK_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
+ IN UINTN Size
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.c b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.c new file mode 100644 index 000000000..e9e31aa2c --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.c @@ -0,0 +1,134 @@ +/** @file
+ Implement the EFI_DISK_INFO_PROTOCOL interface on EMMC devices.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EmmcDxe.h"
+
+/**
+ Provides inquiry information for the controller type.
+
+ This function is used by the driver entity to get inquiry data. Data format of
+ Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in,out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in,out] InquiryDataSize Pointer to the value for the inquiry data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class.
+ @retval EFI_DEVICE_ERROR Error reading InquiryData from device.
+ @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+ EMMC_DEVICE *Device;
+
+ Partition = EMMC_PARTITION_DATA_FROM_DISKINFO (This);
+ Device = Partition->Device;
+
+ if (*InquiryDataSize >= sizeof (Device->Cid)) {
+ Status = EFI_SUCCESS;
+ CopyMem (InquiryData, &Device->Cid, sizeof (Device->Cid));
+ } else {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *InquiryDataSize = sizeof (Device->Cid);
+
+ return Status;
+}
+
+/**
+ Provides identify information for the controller type.
+
+ This function is used by the driver entity to get identify data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in,out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in,out] IdentifyDataSize Pointer to the value for the identify data
+ size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class.
+ @retval EFI_DEVICE_ERROR Error reading IdentifyData from device.
+ @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ )
+{
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Provides sense data information for the controller type.
+
+ This function is used by the driver entity to get sense data. Data format of
+ Sense data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in,out] SenseData Pointer to the SenseData.
+ @param[in,out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class.
+ @retval EFI_DEVICE_ERROR Error reading SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDiskInfoSenseData (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *SenseData,
+ IN OUT UINT32 *SenseDataSize,
+ OUT UINT8 *SenseDataNumber
+ )
+{
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Provides IDE channel and device information for the interface.
+
+ This function is used by the driver entity to get controller information.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
+
+ @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
+ @retval EFI_UNSUPPORTED This is not an IDE device.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.h b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.h new file mode 100644 index 000000000..44e691ac3 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.h @@ -0,0 +1,109 @@ +/** @file
+ Header file for EFI_DISK_INFO_PROTOCOL interface on EMMC devices.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EMMC_DISKINFO_H_
+#define _EMMC_DISKINFO_H_
+
+/**
+ Provides inquiry information for the controller type.
+
+ This function is used by the driver entity to get inquiry data. Data format of
+ Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in,out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in,out] InquiryDataSize Pointer to the value for the inquiry data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class.
+ @retval EFI_DEVICE_ERROR Error reading InquiryData from device.
+ @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ );
+
+/**
+ Provides identify information for the controller type.
+
+ This function is used by the driver entity to get identify data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in,out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in,out] IdentifyDataSize Pointer to the value for the identify data
+ size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class.
+ @retval EFI_DEVICE_ERROR Error reading IdentifyData from device.
+ @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ );
+
+/**
+ Provides sense data information for the controller type.
+
+ This function is used by the driver entity to get sense data. Data format of
+ Sense data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in,out] SenseData Pointer to the SenseData.
+ @param[in,out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class.
+ @retval EFI_DEVICE_ERROR Error reading SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDiskInfoSenseData (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *SenseData,
+ IN OUT UINT32 *SenseDataSize,
+ OUT UINT8 *SenseDataNumber
+ );
+
+/**
+ Provides IDE channel and device information for the interface.
+
+ This function is used by the driver entity to get controller information.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
+
+ @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
+ @retval EFI_UNSUPPORTED This is not an IDE device.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c new file mode 100644 index 000000000..e9095b904 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c @@ -0,0 +1,1205 @@ +/** @file
+ The EmmcDxe driver is used to manage the EMMC device.
+
+ It produces BlockIo, BlockIo2 and StorageSecurity protocols to allow upper layer
+ access the EMMC device.
+
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EmmcDxe.h"
+
+//
+// EmmcDxe Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gEmmcDxeDriverBinding = {
+ EmmcDxeDriverBindingSupported,
+ EmmcDxeDriverBindingStart,
+ EmmcDxeDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+//
+// Template for Emmc Partitions.
+//
+EMMC_PARTITION mEmmcPartitionTemplate = {
+ EMMC_PARTITION_SIGNATURE, // Signature
+ FALSE, // Enable
+ EmmcPartitionUnknown, // PartitionType
+ NULL, // Handle
+ NULL, // DevicePath
+ { // BlockIo
+ EFI_BLOCK_IO_PROTOCOL_REVISION,
+ NULL,
+ EmmcReset,
+ EmmcReadBlocks,
+ EmmcWriteBlocks,
+ EmmcFlushBlocks
+ },
+ { // BlockIo2
+ NULL,
+ EmmcResetEx,
+ EmmcReadBlocksEx,
+ EmmcWriteBlocksEx,
+ EmmcFlushBlocksEx
+ },
+ { // BlockMedia
+ 0, // MediaId
+ FALSE, // RemovableMedia
+ TRUE, // MediaPresent
+ FALSE, // LogicPartition
+ FALSE, // ReadOnly
+ FALSE, // WritingCache
+ 0x200, // BlockSize
+ 0, // IoAlign
+ 0 // LastBlock
+ },
+ { // StorageSecurity
+ EmmcSecurityProtocolIn,
+ EmmcSecurityProtocolOut
+ },
+ { // EraseBlock
+ EFI_ERASE_BLOCK_PROTOCOL_REVISION,
+ 1,
+ EmmcEraseBlocks
+ },
+ { // DiskInfo
+ EFI_DISK_INFO_SD_MMC_INTERFACE_GUID,
+ EmmcDiskInfoInquiry,
+ EmmcDiskInfoIdentify,
+ EmmcDiskInfoSenseData,
+ EmmcDiskInfoWhichIde
+ },
+ {
+ NULL,
+ NULL
+ },
+ NULL // Device
+};
+
+/**
+ Decode and print EMMC CSD Register content.
+
+ @param[in] Csd Pointer to EMMC_CSD data structure.
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+DumpCsd (
+ IN EMMC_CSD *Csd
+ )
+{
+ DEBUG((DEBUG_INFO, "== Dump Emmc Csd Register==\n"));
+ DEBUG((DEBUG_INFO, " CSD structure 0x%x\n", Csd->CsdStructure));
+ DEBUG((DEBUG_INFO, " System specification version 0x%x\n", Csd->SpecVers));
+ DEBUG((DEBUG_INFO, " Data read access-time 1 0x%x\n", Csd->Taac));
+ DEBUG((DEBUG_INFO, " Data read access-time 2 0x%x\n", Csd->Nsac));
+ DEBUG((DEBUG_INFO, " Max. bus clock frequency 0x%x\n", Csd->TranSpeed));
+ DEBUG((DEBUG_INFO, " Device command classes 0x%x\n", Csd->Ccc));
+ DEBUG((DEBUG_INFO, " Max. read data block length 0x%x\n", Csd->ReadBlLen));
+ DEBUG((DEBUG_INFO, " Partial blocks for read allowed 0x%x\n", Csd->ReadBlPartial));
+ DEBUG((DEBUG_INFO, " Write block misalignment 0x%x\n", Csd->WriteBlkMisalign));
+ DEBUG((DEBUG_INFO, " Read block misalignment 0x%x\n", Csd->ReadBlkMisalign));
+ DEBUG((DEBUG_INFO, " DSR implemented 0x%x\n", Csd->DsrImp));
+ DEBUG((DEBUG_INFO, " Device size 0x%x\n", Csd->CSizeLow | (Csd->CSizeHigh << 2)));
+ DEBUG((DEBUG_INFO, " Max. read current @ VDD min 0x%x\n", Csd->VddRCurrMin));
+ DEBUG((DEBUG_INFO, " Max. read current @ VDD max 0x%x\n", Csd->VddRCurrMax));
+ DEBUG((DEBUG_INFO, " Max. write current @ VDD min 0x%x\n", Csd->VddWCurrMin));
+ DEBUG((DEBUG_INFO, " Max. write current @ VDD max 0x%x\n", Csd->VddWCurrMax));
+ DEBUG((DEBUG_INFO, " Device size multiplier 0x%x\n", Csd->CSizeMult));
+ DEBUG((DEBUG_INFO, " Erase group size 0x%x\n", Csd->EraseGrpSize));
+ DEBUG((DEBUG_INFO, " Erase group size multiplier 0x%x\n", Csd->EraseGrpMult));
+ DEBUG((DEBUG_INFO, " Write protect group size 0x%x\n", Csd->WpGrpSize));
+ DEBUG((DEBUG_INFO, " Write protect group enable 0x%x\n", Csd->WpGrpEnable));
+ DEBUG((DEBUG_INFO, " Manufacturer default ECC 0x%x\n", Csd->DefaultEcc));
+ DEBUG((DEBUG_INFO, " Write speed factor 0x%x\n", Csd->R2WFactor));
+ DEBUG((DEBUG_INFO, " Max. write data block length 0x%x\n", Csd->WriteBlLen));
+ DEBUG((DEBUG_INFO, " Partial blocks for write allowed 0x%x\n", Csd->WriteBlPartial));
+ DEBUG((DEBUG_INFO, " Content protection application 0x%x\n", Csd->ContentProtApp));
+ DEBUG((DEBUG_INFO, " File format group 0x%x\n", Csd->FileFormatGrp));
+ DEBUG((DEBUG_INFO, " Copy flag (OTP) 0x%x\n", Csd->Copy));
+ DEBUG((DEBUG_INFO, " Permanent write protection 0x%x\n", Csd->PermWriteProtect));
+ DEBUG((DEBUG_INFO, " Temporary write protection 0x%x\n", Csd->TmpWriteProtect));
+ DEBUG((DEBUG_INFO, " File format 0x%x\n", Csd->FileFormat));
+ DEBUG((DEBUG_INFO, " ECC code 0x%x\n", Csd->Ecc));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Decode and print EMMC EXT_CSD Register content.
+
+ @param[in] ExtCsd Pointer to the EMMC_EXT_CSD data structure.
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+DumpExtCsd (
+ IN EMMC_EXT_CSD *ExtCsd
+ )
+{
+ DEBUG((DEBUG_INFO, "==Dump Emmc ExtCsd Register==\n"));
+ DEBUG((DEBUG_INFO, " Supported Command Sets 0x%x\n", ExtCsd->CmdSet));
+ DEBUG((DEBUG_INFO, " HPI features 0x%x\n", ExtCsd->HpiFeatures));
+ DEBUG((DEBUG_INFO, " Background operations support 0x%x\n", ExtCsd->BkOpsSupport));
+ DEBUG((DEBUG_INFO, " Background operations status 0x%x\n", ExtCsd->BkopsStatus));
+ DEBUG((DEBUG_INFO, " Number of correctly programmed sectors 0x%x\n", *((UINT32*)&ExtCsd->CorrectlyPrgSectorsNum[0])));
+ DEBUG((DEBUG_INFO, " Initialization time after partitioning 0x%x\n", ExtCsd->IniTimeoutAp));
+ DEBUG((DEBUG_INFO, " TRIM Multiplier 0x%x\n", ExtCsd->TrimMult));
+ DEBUG((DEBUG_INFO, " Secure Feature support 0x%x\n", ExtCsd->SecFeatureSupport));
+ DEBUG((DEBUG_INFO, " Secure Erase Multiplier 0x%x\n", ExtCsd->SecEraseMult));
+ DEBUG((DEBUG_INFO, " Secure TRIM Multiplier 0x%x\n", ExtCsd->SecTrimMult));
+ DEBUG((DEBUG_INFO, " Boot information 0x%x\n", ExtCsd->BootInfo));
+ DEBUG((DEBUG_INFO, " Boot partition size 0x%x\n", ExtCsd->BootSizeMult));
+ DEBUG((DEBUG_INFO, " Access size 0x%x\n", ExtCsd->AccSize));
+ DEBUG((DEBUG_INFO, " High-capacity erase unit size 0x%x\n", ExtCsd->HcEraseGrpSize));
+ DEBUG((DEBUG_INFO, " High-capacity erase timeout 0x%x\n", ExtCsd->EraseTimeoutMult));
+ DEBUG((DEBUG_INFO, " Reliable write sector count 0x%x\n", ExtCsd->RelWrSecC));
+ DEBUG((DEBUG_INFO, " High-capacity write protect group size 0x%x\n", ExtCsd->HcWpGrpSize));
+ DEBUG((DEBUG_INFO, " Sleep/awake timeout 0x%x\n", ExtCsd->SATimeout));
+ DEBUG((DEBUG_INFO, " Sector Count 0x%x\n", *((UINT32*)&ExtCsd->SecCount[0])));
+ DEBUG((DEBUG_INFO, " Partition switching timing 0x%x\n", ExtCsd->PartitionSwitchTime));
+ DEBUG((DEBUG_INFO, " Out-of-interrupt busy timing 0x%x\n", ExtCsd->OutOfInterruptTime));
+ DEBUG((DEBUG_INFO, " I/O Driver Strength 0x%x\n", ExtCsd->DriverStrength));
+ DEBUG((DEBUG_INFO, " Device type 0x%x\n", ExtCsd->DeviceType));
+ DEBUG((DEBUG_INFO, " CSD STRUCTURE 0x%x\n", ExtCsd->CsdStructure));
+ DEBUG((DEBUG_INFO, " Extended CSD revision 0x%x\n", ExtCsd->ExtCsdRev));
+ DEBUG((DEBUG_INFO, " Command set 0x%x\n", ExtCsd->CmdSet));
+ DEBUG((DEBUG_INFO, " Command set revision 0x%x\n", ExtCsd->CmdSetRev));
+ DEBUG((DEBUG_INFO, " Power class 0x%x\n", ExtCsd->PowerClass));
+ DEBUG((DEBUG_INFO, " High-speed interface timing 0x%x\n", ExtCsd->HsTiming));
+ DEBUG((DEBUG_INFO, " Bus width mode 0x%x\n", ExtCsd->BusWidth));
+ DEBUG((DEBUG_INFO, " Erased memory content 0x%x\n", ExtCsd->ErasedMemCont));
+ DEBUG((DEBUG_INFO, " Partition configuration 0x%x\n", ExtCsd->PartitionConfig));
+ DEBUG((DEBUG_INFO, " Boot config protection 0x%x\n", ExtCsd->BootConfigProt));
+ DEBUG((DEBUG_INFO, " Boot bus Conditions 0x%x\n", ExtCsd->BootBusConditions));
+ DEBUG((DEBUG_INFO, " High-density erase group definition 0x%x\n", ExtCsd->EraseGroupDef));
+ DEBUG((DEBUG_INFO, " Boot write protection status register 0x%x\n", ExtCsd->BootWpStatus));
+ DEBUG((DEBUG_INFO, " Boot area write protection register 0x%x\n", ExtCsd->BootWp));
+ DEBUG((DEBUG_INFO, " User area write protection register 0x%x\n", ExtCsd->UserWp));
+ DEBUG((DEBUG_INFO, " FW configuration 0x%x\n", ExtCsd->FwConfig));
+ DEBUG((DEBUG_INFO, " RPMB Size 0x%x\n", ExtCsd->RpmbSizeMult));
+ DEBUG((DEBUG_INFO, " H/W reset function 0x%x\n", ExtCsd->RstFunction));
+ DEBUG((DEBUG_INFO, " Partitioning Support 0x%x\n", ExtCsd->PartitioningSupport));
+ DEBUG((DEBUG_INFO, " Max Enhanced Area Size 0x%02x%02x%02x\n", \
+ ExtCsd->MaxEnhSizeMult[2], ExtCsd->MaxEnhSizeMult[1], ExtCsd->MaxEnhSizeMult[0]));
+ DEBUG((DEBUG_INFO, " Partitions attribute 0x%x\n", ExtCsd->PartitionsAttribute));
+ DEBUG((DEBUG_INFO, " Partitioning Setting 0x%x\n", ExtCsd->PartitionSettingCompleted));
+ DEBUG((DEBUG_INFO, " General Purpose Partition 1 Size 0x%02x%02x%02x\n", \
+ ExtCsd->GpSizeMult[2], ExtCsd->GpSizeMult[1], ExtCsd->GpSizeMult[0]));
+ DEBUG((DEBUG_INFO, " General Purpose Partition 2 Size 0x%02x%02x%02x\n", \
+ ExtCsd->GpSizeMult[5], ExtCsd->GpSizeMult[4], ExtCsd->GpSizeMult[3]));
+ DEBUG((DEBUG_INFO, " General Purpose Partition 3 Size 0x%02x%02x%02x\n", \
+ ExtCsd->GpSizeMult[8], ExtCsd->GpSizeMult[7], ExtCsd->GpSizeMult[6]));
+ DEBUG((DEBUG_INFO, " General Purpose Partition 4 Size 0x%02x%02x%02x\n", \
+ ExtCsd->GpSizeMult[11], ExtCsd->GpSizeMult[10], ExtCsd->GpSizeMult[9]));
+ DEBUG((DEBUG_INFO, " Enhanced User Data Area Size 0x%02x%02x%02x\n", \
+ ExtCsd->EnhSizeMult[2], ExtCsd->EnhSizeMult[1], ExtCsd->EnhSizeMult[0]));
+ DEBUG((DEBUG_INFO, " Enhanced User Data Start Address 0x%x\n", *((UINT32*)&ExtCsd->EnhStartAddr[0])));
+ DEBUG((DEBUG_INFO, " Bad Block Management mode 0x%x\n", ExtCsd->SecBadBlkMgmnt));
+ DEBUG((DEBUG_INFO, " Native sector size 0x%x\n", ExtCsd->NativeSectorSize));
+ DEBUG((DEBUG_INFO, " Sector size emulation 0x%x\n", ExtCsd->UseNativeSector));
+ DEBUG((DEBUG_INFO, " Sector size 0x%x\n", ExtCsd->DataSectorSize));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get EMMC device model name.
+
+ @param[in, out] Device The pointer to the EMMC_DEVICE data structure.
+ @param[in] Cid Pointer to EMMC_CID data structure.
+
+ @retval EFI_SUCCESS The function completed successfully
+
+**/
+EFI_STATUS
+GetEmmcModelName (
+ IN OUT EMMC_DEVICE *Device,
+ IN EMMC_CID *Cid
+ )
+{
+ CHAR8 String[EMMC_MODEL_NAME_MAX_LEN];
+
+ ZeroMem (String, sizeof (String));
+ CopyMem (String, &Cid->OemId, sizeof (Cid->OemId));
+ String[sizeof (Cid->OemId)] = ' ';
+ CopyMem (String + sizeof (Cid->OemId) + 1, Cid->ProductName, sizeof (Cid->ProductName));
+ String[sizeof (Cid->OemId) + sizeof (Cid->ProductName)] = ' ';
+ CopyMem (String + sizeof (Cid->OemId) + sizeof (Cid->ProductName) + 1, Cid->ProductSerialNumber, sizeof (Cid->ProductSerialNumber));
+
+ AsciiStrToUnicodeStrS (String, Device->ModelName, sizeof (Device->ModelName) / sizeof (Device->ModelName[0]));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Discover all partitions in the EMMC device.
+
+ @param[in] Device The pointer to the EMMC_DEVICE data structure.
+
+ @retval EFI_SUCCESS All the partitions in the device are successfully enumerated.
+ @return Others Some error occurs when enumerating the partitions.
+
+**/
+EFI_STATUS
+DiscoverAllPartitions (
+ IN EMMC_DEVICE *Device
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+ EMMC_CSD *Csd;
+ EMMC_CID *Cid;
+ EMMC_EXT_CSD *ExtCsd;
+ UINT8 Slot;
+ UINT64 Capacity;
+ UINT32 DevStatus;
+ UINT8 Index;
+ UINT32 SecCount;
+ UINT32 GpSizeMult;
+
+ Slot = Device->Slot;
+
+ Status = EmmcSendStatus (Device, Slot + 1, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Deselect the device to force it enter stby mode before getting CSD
+ // register content.
+ // Note here we don't judge return status as some EMMC devices return
+ // error but the state has been stby.
+ //
+ EmmcSelect (Device, 0);
+
+ Status = EmmcSendStatus (Device, Slot + 1, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Csd = &Device->Csd;
+ Status = EmmcGetCsd (Device, Slot + 1, Csd);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DumpCsd (Csd);
+
+ if ((Csd->CSizeLow | Csd->CSizeHigh << 2) == 0xFFF) {
+ Device->SectorAddressing = TRUE;
+ } else {
+ Device->SectorAddressing = FALSE;
+ }
+
+ Cid = &Device->Cid;
+ Status = EmmcGetCid (Device, Slot + 1, Cid);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EmmcSelect (Device, Slot + 1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ExtCsd = &Device->ExtCsd;
+ Status = EmmcGetExtCsd (Device, ExtCsd);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DumpExtCsd (ExtCsd);
+
+ if (ExtCsd->ExtCsdRev < 5) {
+ DEBUG ((EFI_D_ERROR, "The EMMC device version is too low, we don't support!!!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((ExtCsd->PartitioningSupport & BIT0) != BIT0) {
+ DEBUG ((EFI_D_ERROR, "The EMMC device doesn't support Partition Feature!!!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ for (Index = 0; Index < EMMC_MAX_PARTITIONS; Index++) {
+ Partition = &Device->Partition[Index];
+ CopyMem (Partition, &mEmmcPartitionTemplate, sizeof (EMMC_PARTITION));
+ Partition->Device = Device;
+ InitializeListHead (&Partition->Queue);
+ Partition->BlockIo.Media = &Partition->BlockMedia;
+ Partition->BlockIo2.Media = &Partition->BlockMedia;
+ Partition->PartitionType = Index;
+ Partition->BlockMedia.IoAlign = Device->Private->PassThru->IoAlign;
+ Partition->BlockMedia.BlockSize = 0x200;
+ Partition->BlockMedia.LastBlock = 0x00;
+ Partition->BlockMedia.RemovableMedia = FALSE;
+ Partition->BlockMedia.MediaPresent = TRUE;
+ Partition->BlockMedia.LogicalPartition = FALSE;
+
+ switch (Index) {
+ case EmmcPartitionUserData:
+ SecCount = *(UINT32*)&ExtCsd->SecCount;
+ Capacity = MultU64x32 ((UINT64) SecCount, 0x200);
+ break;
+ case EmmcPartitionBoot1:
+ case EmmcPartitionBoot2:
+ Capacity = ExtCsd->BootSizeMult * SIZE_128KB;
+ break;
+ case EmmcPartitionRPMB:
+ Capacity = ExtCsd->RpmbSizeMult * SIZE_128KB;
+ break;
+ case EmmcPartitionGP1:
+ GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[0] | (ExtCsd->GpSizeMult[1] << 8) | (ExtCsd->GpSizeMult[2] << 16));
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
+ break;
+ case EmmcPartitionGP2:
+ GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[3] | (ExtCsd->GpSizeMult[4] << 8) | (ExtCsd->GpSizeMult[5] << 16));
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
+ break;
+ case EmmcPartitionGP3:
+ GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[6] | (ExtCsd->GpSizeMult[7] << 8) | (ExtCsd->GpSizeMult[8] << 16));
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
+ break;
+ case EmmcPartitionGP4:
+ GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[9] | (ExtCsd->GpSizeMult[10] << 8) | (ExtCsd->GpSizeMult[11] << 16));
+ Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
+ break;
+ default:
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Capacity != 0) {
+ Partition->Enable = TRUE;
+ Partition->BlockMedia.LastBlock = DivU64x32 (Capacity, Partition->BlockMedia.BlockSize) - 1;
+ }
+
+ if ((ExtCsd->EraseGroupDef & BIT0) == 0) {
+ if (Csd->WriteBlLen < 9) {
+ Partition->EraseBlock.EraseLengthGranularity = 1;
+ } else {
+ Partition->EraseBlock.EraseLengthGranularity = (Csd->EraseGrpMult + 1) * (Csd->EraseGrpSize + 1) * (1 << (Csd->WriteBlLen - 9));
+ }
+ } else {
+ Partition->EraseBlock.EraseLengthGranularity = 1024 * ExtCsd->HcEraseGrpSize;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Install BlkIo, BlkIo2 and Ssp protocols for the specified partition in the EMMC device.
+
+ @param[in] Device The pointer to the EMMC_DEVICE data structure.
+ @param[in] Index The index of the partition.
+
+ @retval EFI_SUCCESS The protocols are installed successfully.
+ @retval Others Some error occurs when installing the protocols.
+
+**/
+EFI_STATUS
+InstallProtocolOnPartition (
+ IN EMMC_DEVICE *Device,
+ IN UINT8 Index
+ )
+{
+ EFI_STATUS Status;
+ EMMC_PARTITION *Partition;
+ CONTROLLER_DEVICE_PATH ControlNode;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ EFI_HANDLE DeviceHandle;
+
+ //
+ // Build device path
+ //
+ ParentDevicePath = Device->DevicePath;
+
+ ControlNode.Header.Type = HARDWARE_DEVICE_PATH;
+ ControlNode.Header.SubType = HW_CONTROLLER_DP;
+ SetDevicePathNodeLength (&ControlNode.Header, sizeof (CONTROLLER_DEVICE_PATH));
+ ControlNode.ControllerNumber = Index;
+
+ DevicePath = AppendDevicePathNode (ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*)&ControlNode);
+ if (DevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ DeviceHandle = NULL;
+ RemainingDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);
+ if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {
+ Status = EFI_ALREADY_STARTED;
+ goto Error;
+ }
+
+ Partition = &Device->Partition[Index];
+ Partition->DevicePath = DevicePath;
+ if (Partition->Enable) {
+ //
+ // Install BlkIo/BlkIo2/Ssp for the specified partition
+ //
+ if (Partition->PartitionType != EmmcPartitionRPMB) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Partition->Handle,
+ &gEfiDevicePathProtocolGuid,
+ Partition->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Partition->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Partition->BlockIo2,
+ &gEfiEraseBlockProtocolGuid,
+ &Partition->EraseBlock,
+ &gEfiDiskInfoProtocolGuid,
+ &Partition->DiskInfo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ if (((Partition->PartitionType == EmmcPartitionUserData) ||
+ (Partition->PartitionType == EmmcPartitionBoot1) ||
+ (Partition->PartitionType == EmmcPartitionBoot2)) &&
+ ((Device->Csd.Ccc & BIT10) != 0)) {
+ Status = gBS->InstallProtocolInterface (
+ &Partition->Handle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Partition->StorageSecurity
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Partition->Handle,
+ &gEfiDevicePathProtocolGuid,
+ Partition->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Partition->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Partition->BlockIo2,
+ &gEfiEraseBlockProtocolGuid,
+ &Partition->EraseBlock,
+ &gEfiDiskInfoProtocolGuid,
+ &Partition->DiskInfo,
+ NULL
+ );
+ goto Error;
+ }
+ }
+
+ gBS->OpenProtocol (
+ Device->Private->Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID **) &(Device->Private->PassThru),
+ Device->Private->DriverBindingHandle,
+ Partition->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ }
+
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+Error:
+ if (EFI_ERROR (Status) && (DevicePath != NULL)) {
+ FreePool (DevicePath);
+ }
+
+ return Status;
+}
+
+/**
+ Scan EMMC Bus to discover the device.
+
+ @param[in] Private The EMMC driver private data structure.
+ @param[in] Slot The slot number to check device present.
+ @param[in] RemainingDevicePath The pointer to the remaining device path.
+
+ @retval EFI_SUCCESS Successfully to discover the device and attach
+ SdMmcIoProtocol to it.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+ @retval EFI_ALREADY_STARTED The device was discovered before.
+ @retval Others Fail to discover the device.
+
+**/
+EFI_STATUS
+EFIAPI
+DiscoverEmmcDevice (
+ IN EMMC_DRIVER_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EMMC_DEVICE *Device;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingEmmcDevPath;
+ EFI_DEV_PATH *Node;
+ EFI_HANDLE DeviceHandle;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ UINT8 Index;
+
+ Device = NULL;
+ DevicePath = NULL;
+ NewDevicePath = NULL;
+ RemainingDevicePath = NULL;
+ PassThru = Private->PassThru;
+ Device = &Private->Device[Slot];
+
+ //
+ // Build Device Path to check if the EMMC device present at the slot.
+ //
+ Status = PassThru->BuildDevicePath (
+ PassThru,
+ Slot,
+ &DevicePath
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (DevicePath->SubType != MSG_EMMC_DP) {
+ Status = EFI_UNSUPPORTED;
+ goto Error;
+ }
+
+ NewDevicePath = AppendDevicePathNode (
+ Private->ParentDevicePath,
+ DevicePath
+ );
+ if (NewDevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ DeviceHandle = NULL;
+ RemainingEmmcDevPath = NewDevicePath;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingEmmcDevPath, &DeviceHandle);
+ //
+ // The device path to the EMMC device doesn't exist. It means the corresponding device private data hasn't been initialized.
+ //
+ if (EFI_ERROR (Status) || (DeviceHandle == NULL) || !IsDevicePathEnd (RemainingEmmcDevPath)) {
+ Device->DevicePath = NewDevicePath;
+ Device->Slot = Slot;
+ Device->Private = Private;
+ //
+ // Expose user area in the Sd memory card to upper layer.
+ //
+ Status = DiscoverAllPartitions (Device);
+ if (EFI_ERROR(Status)) {
+ FreePool (NewDevicePath);
+ goto Error;
+ }
+
+ Status = gBS->InstallProtocolInterface (
+ &Device->Handle,
+ &gEfiDevicePathProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ Device->DevicePath
+ );
+ if (EFI_ERROR(Status)) {
+ FreePool (NewDevicePath);
+ goto Error;
+ }
+
+ Device->ControllerNameTable = NULL;
+ GetEmmcModelName (Device, &Device->Cid);
+ AddUnicodeString2 (
+ "eng",
+ gEmmcDxeComponentName.SupportedLanguages,
+ &Device->ControllerNameTable,
+ Device->ModelName,
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gEmmcDxeComponentName2.SupportedLanguages,
+ &Device->ControllerNameTable,
+ Device->ModelName,
+ FALSE
+ );
+ }
+
+ if (RemainingDevicePath == NULL) {
+ //
+ // Expose all partitions in the Emmc device to upper layer.
+ //
+ for (Index = 0; Index < EMMC_MAX_PARTITIONS; Index++) {
+ InstallProtocolOnPartition (Device, Index);
+ }
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // Enumerate the specified partition
+ //
+ Node = (EFI_DEV_PATH *) RemainingDevicePath;
+ if ((DevicePathType (&Node->DevPath) != HARDWARE_DEVICE_PATH) ||
+ (DevicePathSubType (&Node->DevPath) != HW_CONTROLLER_DP) ||
+ (DevicePathNodeLength (&Node->DevPath) != sizeof (CONTROLLER_DEVICE_PATH))) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Error;
+ }
+
+ Index = (UINT8)Node->Controller.ControllerNumber;
+ if (Index >= EMMC_MAX_PARTITIONS) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Error;
+ }
+
+ Status = InstallProtocolOnPartition (Device, Index);
+ }
+
+Error:
+ FreePool (DevicePath);
+
+ return Status;
+}
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+EmmcDxeDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ UINT8 Slot;
+
+ //
+ // Test EFI_SD_MMC_PASS_THRU_PROTOCOL on the controller handle.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID**) &PassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Test RemainingDevicePath is valid or not.
+ //
+ if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {
+ Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);
+ if (EFI_ERROR (Status)) {
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+ }
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Open the EFI Device Path protocol needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ return Status;
+}
+
+/**
+ Starts a device controller or a bus controller.
+
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().
+ As a result, much of the error checking on the parameters to Start() has been moved into this
+ common boot service. It is legal to call Start() from other locations,
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+ EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to start. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The driver failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDxeDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EMMC_DRIVER_PRIVATE_DATA *Private;
+ UINT8 Slot;
+
+ Private = NULL;
+ PassThru = NULL;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID **) &PassThru,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
+ return Status;
+ }
+
+ //
+ // Check EFI_ALREADY_STARTED to reuse the original EMMC_DRIVER_PRIVATE_DATA.
+ //
+ if (Status != EFI_ALREADY_STARTED) {
+ Private = AllocateZeroPool (sizeof (EMMC_DRIVER_PRIVATE_DATA));
+ if (Private == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ ASSERT_EFI_ERROR (Status);
+ Private->PassThru = PassThru;
+ Private->Controller = Controller;
+ Private->ParentDevicePath = ParentDevicePath;
+ Private->DriverBindingHandle = This->DriverBindingHandle;
+
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiCallerIdGuid,
+ EFI_NATIVE_INTERFACE,
+ Private
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &Private,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ }
+
+ if (RemainingDevicePath == NULL) {
+ Slot = 0xFF;
+ while (TRUE) {
+ Status = PassThru->GetNextSlot (PassThru, &Slot);
+ if (EFI_ERROR (Status)) {
+ //
+ // Cannot find more legal slots.
+ //
+ Status = EFI_SUCCESS;
+ break;
+ }
+
+ Status = DiscoverEmmcDevice (Private, Slot, NULL);
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ break;
+ }
+ }
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {
+ Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);
+ if (!EFI_ERROR (Status)) {
+ Status = DiscoverEmmcDevice (Private, Slot, NextDevicePathNode (RemainingDevicePath));
+ }
+ }
+
+Error:
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ if (Private != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiCallerIdGuid,
+ Private,
+ NULL
+ );
+ FreePool (Private);
+ }
+ }
+ return Status;
+}
+
+/**
+ Stops a device controller or a bus controller.
+
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+ As a result, much of the error checking on the parameters to Stop() has been moved
+ into this common boot service. It is legal to call Stop() from other locations,
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+ same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+ Start() function, and the Start() function must have called OpenProtocol() on
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must
+ support a bus specific I/O protocol for the driver
+ to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
+ if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDxeDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN AllChildrenStopped;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EMMC_DRIVER_PRIVATE_DATA *Private;
+ EMMC_DEVICE *Device;
+ EMMC_PARTITION *Partition;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ EMMC_REQUEST *Request;
+
+ BlockIo = NULL;
+ BlockIo2 = NULL;
+ if (NumberOfChildren == 0) {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &Private,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ for (Index = 0; Index < EMMC_MAX_DEVICES; Index++) {
+ Device = &Private->Device[Index];
+ Status = gBS->OpenProtocol (
+ Device->Handle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ ASSERT (DevicePath == Device->DevicePath);
+ gBS->UninstallProtocolInterface (
+ Device->Handle,
+ &gEfiDevicePathProtocolGuid,
+ DevicePath
+ );
+ FreePool (Device->DevicePath);
+ }
+
+ gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiCallerIdGuid,
+ Private
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ FreePool (Private);
+
+ return EFI_SUCCESS;
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIo2ProtocolGuid,
+ (VOID **) &BlockIo2,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ continue;
+ }
+ }
+
+ if (BlockIo != NULL) {
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO (BlockIo);
+ } else {
+ ASSERT (BlockIo2 != NULL);
+ Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (BlockIo2);
+ }
+
+ for (Link = GetFirstNode (&Partition->Queue);
+ !IsNull (&Partition->Queue, Link);
+ Link = NextLink) {
+ NextLink = GetNextNode (&Partition->Queue, Link);
+
+ RemoveEntryList (Link);
+ Request = EMMC_REQUEST_FROM_LINK (Link);
+
+ gBS->CloseEvent (Request->Event);
+ Request->Token->TransactionStatus = EFI_ABORTED;
+
+ if (Request->IsEnd) {
+ gBS->SignalEvent (Request->Token->Event);
+ }
+
+ FreePool (Request);
+ }
+
+ //
+ // Close the child handle
+ //
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ Partition->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Partition->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Partition->BlockIo2,
+ &gEfiEraseBlockProtocolGuid,
+ &Partition->EraseBlock,
+ &gEfiDiskInfoProtocolGuid,
+ &Partition->DiskInfo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID **)&Partition->Device->Private->PassThru,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ continue;
+ }
+
+ //
+ // If Storage Security Command Protocol is installed, then uninstall this protocol.
+ //
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiStorageSecurityCommandProtocolGuid,
+ (VOID **) &StorageSecurity,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->UninstallProtocolInterface (
+ ChildHandleBuffer[Index],
+ &gEfiStorageSecurityCommandProtocolGuid,
+ &Partition->StorageSecurity
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiSdMmcPassThruProtocolGuid,
+ (VOID **) &Partition->Device->Private->PassThru,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ AllChildrenStopped = FALSE;
+ continue;
+ }
+ }
+
+ FreePool (Partition->DevicePath);
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The user Entry Point for module EmmcDxe. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some errors occur when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeEmmcDxe (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gEmmcDxeDriverBinding,
+ ImageHandle,
+ &gEmmcDxeComponentName,
+ &gEmmcDxeComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h new file mode 100644 index 000000000..5ecce41de --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h @@ -0,0 +1,501 @@ +/** @file
+ Header file for EmmcDxe Driver.
+
+ This file defines common data structures, macro definitions and some module
+ internal function header files.
+
+ Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EMMC_DXE_H_
+#define _EMMC_DXE_H_
+
+#include <Uefi.h>
+#include <IndustryStandard/Emmc.h>
+
+#include <Protocol/SdMmcPassThru.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/BlockIo2.h>
+#include <Protocol/StorageSecurityCommand.h>
+#include <Protocol/EraseBlock.h>
+#include <Protocol/DiskInfo.h>
+
+#include <Protocol/DevicePath.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include "EmmcBlockIo.h"
+#include "EmmcDiskInfo.h"
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gEmmcDxeDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gEmmcDxeComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gEmmcDxeComponentName2;
+
+#define EMMC_PARTITION_SIGNATURE SIGNATURE_32 ('E', 'm', 'm', 'P')
+
+#define EMMC_PARTITION_DATA_FROM_BLKIO(a) \
+ CR(a, EMMC_PARTITION, BlockIo, EMMC_PARTITION_SIGNATURE)
+
+#define EMMC_PARTITION_DATA_FROM_BLKIO2(a) \
+ CR(a, EMMC_PARTITION, BlockIo2, EMMC_PARTITION_SIGNATURE)
+
+#define EMMC_PARTITION_DATA_FROM_SSP(a) \
+ CR(a, EMMC_PARTITION, StorageSecurity, EMMC_PARTITION_SIGNATURE)
+
+#define EMMC_PARTITION_DATA_FROM_ERASEBLK(a) \
+ CR(a, EMMC_PARTITION, EraseBlock, EMMC_PARTITION_SIGNATURE)
+
+#define EMMC_PARTITION_DATA_FROM_DISKINFO(a) \
+ CR(a, EMMC_PARTITION, DiskInfo, EMMC_PARTITION_SIGNATURE)
+
+//
+// Take 2.5 seconds as generic time out value, 1 microsecond as unit.
+//
+#define EMMC_GENERIC_TIMEOUT 2500 * 1000
+
+#define EMMC_REQUEST_SIGNATURE SIGNATURE_32 ('E', 'm', 'R', 'e')
+
+typedef struct _EMMC_DEVICE EMMC_DEVICE;
+typedef struct _EMMC_DRIVER_PRIVATE_DATA EMMC_DRIVER_PRIVATE_DATA;
+
+//
+// Asynchronous I/O request.
+//
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
+ EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
+ EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
+
+ BOOLEAN IsEnd;
+
+ EFI_BLOCK_IO2_TOKEN *Token;
+ EFI_EVENT Event;
+} EMMC_REQUEST;
+
+#define EMMC_REQUEST_FROM_LINK(a) \
+ CR(a, EMMC_REQUEST, Link, EMMC_REQUEST_SIGNATURE)
+
+typedef struct {
+ UINT32 Signature;
+ BOOLEAN Enable;
+ EMMC_PARTITION_TYPE PartitionType;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL BlockIo2;
+ EFI_BLOCK_IO_MEDIA BlockMedia;
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL StorageSecurity;
+ EFI_ERASE_BLOCK_PROTOCOL EraseBlock;
+ EFI_DISK_INFO_PROTOCOL DiskInfo;
+
+ LIST_ENTRY Queue;
+
+ EMMC_DEVICE *Device;
+} EMMC_PARTITION;
+
+//
+// Up to 6 slots per EMMC PCI host controller
+//
+#define EMMC_MAX_DEVICES 6
+//
+// Up to 8 partitions per EMMC device.
+//
+#define EMMC_MAX_PARTITIONS 8
+#define EMMC_MODEL_NAME_MAX_LEN 32
+
+struct _EMMC_DEVICE {
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINT8 Slot;
+ BOOLEAN SectorAddressing;
+
+ EMMC_PARTITION Partition[EMMC_MAX_PARTITIONS];
+ EMMC_CSD Csd;
+ EMMC_CID Cid;
+ EMMC_EXT_CSD ExtCsd;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+ //
+ // The model name consists of three fields in CID register
+ // 1) OEM/Application ID (2 bytes)
+ // 2) Product Name (5 bytes)
+ // 3) Product Serial Number (4 bytes)
+ // The delimiters of these fields are whitespace.
+ //
+ CHAR16 ModelName[EMMC_MODEL_NAME_MAX_LEN];
+ EMMC_DRIVER_PRIVATE_DATA *Private;
+} ;
+
+//
+// EMMC DXE driver private data structure
+//
+struct _EMMC_DRIVER_PRIVATE_DATA {
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
+ EFI_HANDLE Controller;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_HANDLE DriverBindingHandle;
+
+ EMMC_DEVICE Device[EMMC_MAX_DEVICES];
+} ;
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+EmmcDxeDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().
+ As a result, much of the error checking on the parameters to Start() has been moved into this
+ common boot service. It is legal to call Start() from other locations,
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+ EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to start. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The driver failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDxeDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+ As a result, much of the error checking on the parameters to Stop() has been moved
+ into this common boot service. It is legal to call Stop() from other locations,
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+ same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+ Start() function, and the Start() function must have called OpenProtocol() on
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must
+ support a bus specific I/O protocol for the driver
+ to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
+ if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDxeDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDxeComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+EmmcDxeComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Send command SELECT to the device to select/deselect the device.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcSelect (
+ IN EMMC_DEVICE *Device,
+ IN UINT16 Rca
+ );
+
+/**
+ Send command SEND_STATUS to the device to get device status.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] DevStatus The buffer to store the device status.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcSendStatus (
+ IN EMMC_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT UINT32 *DevStatus
+ );
+
+/**
+ Send command SEND_CSD to the device to get the CSD register data.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] Csd The buffer to store the EMMC_CSD register data.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcGetCsd (
+ IN EMMC_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT EMMC_CSD *Csd
+ );
+
+/**
+ Send command SEND_CID to the device to get the CID register data.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[in] Rca The relative device address to use.
+ @param[out] Cid The buffer to store the EMMC_CID register data.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcGetCid (
+ IN EMMC_DEVICE *Device,
+ IN UINT16 Rca,
+ OUT EMMC_CID *Cid
+ );
+
+/**
+ Send command SEND_EXT_CSD to the device to get the EXT_CSD register data.
+
+ @param[in] Device A pointer to the EMMC_DEVICE instance.
+ @param[out] ExtCsd The buffer to store the EXT_CSD register data.
+
+ @retval EFI_SUCCESS The request is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
+ @retval Others The request could not be executed successfully.
+
+**/
+EFI_STATUS
+EmmcGetExtCsd (
+ IN EMMC_DEVICE *Device,
+ OUT EMMC_EXT_CSD *ExtCsd
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf new file mode 100644 index 000000000..2afe4f42a --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf @@ -0,0 +1,65 @@ +## @file
+# EmmcDxe driver is used to manage the EMMC device.
+#
+# It produces BlockIo, BlockIo2 and StorageSecurity protocols to allow upper layer
+# access the EMMC device.
+#
+# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EmmcDxe
+ MODULE_UNI_FILE = EmmcDxe.uni
+ FILE_GUID = 2145F72F-E6F1-4440-A828-59DC9AAB5F89
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeEmmcDxe
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gEmmcDxeDriverBinding
+# COMPONENT_NAME = gEmmcDxeComponentName
+# COMPONENT_NAME2 = gEmmcDxeComponentName2
+#
+
+[Sources.common]
+ ComponentName.c
+ EmmcDxe.c
+ EmmcDxe.h
+ EmmcBlockIo.c
+ EmmcBlockIo.h
+ EmmcDiskInfo.c
+ EmmcDiskInfo.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Protocols]
+ gEfiSdMmcPassThruProtocolGuid ## TO_START
+ gEfiBlockIoProtocolGuid ## BY_START
+ gEfiBlockIo2ProtocolGuid ## BY_START
+ gEfiStorageSecurityCommandProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiEraseBlockProtocolGuid ## BY_START
+ gEfiDiskInfoProtocolGuid ## BY_START
+ ## TO_START
+ ## BY_START
+ gEfiDevicePathProtocolGuid
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.uni b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.uni new file mode 100644 index 000000000..b47ce27bd --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.uni @@ -0,0 +1,15 @@ +// /** @file
+// EMMC device driver to manage the EMMC device and provide interface for upper layer
+// access.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "EMMC device driver to manage the EMMC device and provide interface for upper layer access"
+
+#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."
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxeExtra.uni new file mode 100644 index 000000000..0f75ea64c --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxeExtra.uni @@ -0,0 +1,14 @@ +// /** @file
+// EmmcDxe Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"EMMC Device Driver"
+
+
|