diff options
| author | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
|---|---|---|
| committer | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
| commit | 7e2ccccace24636f29ddc210b94606abd4c7e42b (patch) | |
| tree | 545d43ea12671048956cafeb12303e84d601e571 /MdeModulePkg/Bus/Sd | |
| parent | 27b044605cd5f6b33a3d231576003850b3fe305b (diff) | |
| download | edk2-trunk.tar.xz | |
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'MdeModulePkg/Bus/Sd')
40 files changed, 19449 insertions, 19449 deletions
diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/DmaMem.c b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/DmaMem.c index df2f18024e..4a5896b3e5 100644 --- a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/DmaMem.c +++ b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/DmaMem.c @@ -1,249 +1,249 @@ -/** @file
- The DMA memory help function.
-
- Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
-
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "EmmcBlockIoPei.h"
-
-EDKII_IOMMU_PPI *mIoMmu;
-
-/**
- Provides the controller-specific addresses required to access system memory from a
- DMA bus master.
-
- @param Operation Indicates if the bus master is going to read or write to system memory.
- @param HostAddress The system memory address to map to the PCI controller.
- @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
- that were mapped.
- @param DeviceAddress The resulting map address for the bus master PCI controller to use to
- access the hosts HostAddress.
- @param Mapping A resulting value to pass to Unmap().
-
- @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
- @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
- @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
- @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
-
-**/
-EFI_STATUS
-IoMmuMap (
- IN EDKII_IOMMU_OPERATION Operation,
- IN VOID *HostAddress,
- IN OUT UINTN *NumberOfBytes,
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
- OUT VOID **Mapping
- )
-{
- EFI_STATUS Status;
- UINT64 Attribute;
-
- if (mIoMmu != NULL) {
- Status = mIoMmu->Map (
- mIoMmu,
- Operation,
- HostAddress,
- NumberOfBytes,
- DeviceAddress,
- Mapping
- );
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- switch (Operation) {
- case EdkiiIoMmuOperationBusMasterRead:
- case EdkiiIoMmuOperationBusMasterRead64:
- Attribute = EDKII_IOMMU_ACCESS_READ;
- break;
- case EdkiiIoMmuOperationBusMasterWrite:
- case EdkiiIoMmuOperationBusMasterWrite64:
- Attribute = EDKII_IOMMU_ACCESS_WRITE;
- break;
- case EdkiiIoMmuOperationBusMasterCommonBuffer:
- case EdkiiIoMmuOperationBusMasterCommonBuffer64:
- Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;
- break;
- default:
- ASSERT (FALSE);
- return EFI_INVALID_PARAMETER;
- }
-
- Status = mIoMmu->SetAttribute (
- mIoMmu,
- *Mapping,
- Attribute
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- } else {
- *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
- *Mapping = NULL;
- Status = EFI_SUCCESS;
- }
-
- return Status;
-}
-
-/**
- Completes the Map() operation and releases any corresponding resources.
-
- @param Mapping The mapping value returned from Map().
-
- @retval EFI_SUCCESS The range was unmapped.
- @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
- @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
-**/
-EFI_STATUS
-IoMmuUnmap (
- IN VOID *Mapping
- )
-{
- EFI_STATUS Status;
-
- if (mIoMmu != NULL) {
- Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);
- Status = mIoMmu->Unmap (mIoMmu, Mapping);
- } else {
- Status = EFI_SUCCESS;
- }
-
- return Status;
-}
-
-/**
- Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
- OperationBusMasterCommonBuffer64 mapping.
-
- @param Pages The number of pages to allocate.
- @param HostAddress A pointer to store the base system memory address of the
- allocated range.
- @param DeviceAddress The resulting map address for the bus master PCI controller to use to
- access the hosts HostAddress.
- @param Mapping A resulting value to pass to Unmap().
-
- @retval EFI_SUCCESS The requested memory pages were allocated.
- @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
- MEMORY_WRITE_COMBINE and MEMORY_CACHED.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
- @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
-
-**/
-EFI_STATUS
-IoMmuAllocateBuffer (
- IN UINTN Pages,
- OUT VOID **HostAddress,
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
- OUT VOID **Mapping
- )
-{
- EFI_STATUS Status;
- UINTN NumberOfBytes;
- EFI_PHYSICAL_ADDRESS HostPhyAddress;
-
- *HostAddress = NULL;
- *DeviceAddress = 0;
-
- if (mIoMmu != NULL) {
- Status = mIoMmu->AllocateBuffer (
- mIoMmu,
- EfiBootServicesData,
- Pages,
- HostAddress,
- 0
- );
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
- Status = mIoMmu->Map (
- mIoMmu,
- EdkiiIoMmuOperationBusMasterCommonBuffer,
- *HostAddress,
- &NumberOfBytes,
- DeviceAddress,
- Mapping
- );
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Status = mIoMmu->SetAttribute (
- mIoMmu,
- *Mapping,
- EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- } else {
- Status = PeiServicesAllocatePages (
- EfiBootServicesData,
- Pages,
- &HostPhyAddress
- );
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- *HostAddress = (VOID *)(UINTN)HostPhyAddress;
- *DeviceAddress = HostPhyAddress;
- *Mapping = NULL;
- }
-
- return Status;
-}
-
-/**
- Frees memory that was allocated with AllocateBuffer().
-
- @param Pages The number of pages to free.
- @param HostAddress The base system memory address of the allocated range.
- @param Mapping The mapping value returned from Map().
-
- @retval EFI_SUCCESS The requested memory pages were freed.
- @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
- was not allocated with AllocateBuffer().
-
-**/
-EFI_STATUS
-IoMmuFreeBuffer (
- IN UINTN Pages,
- IN VOID *HostAddress,
- IN VOID *Mapping
- )
-{
- EFI_STATUS Status;
-
- if (mIoMmu != NULL) {
- Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);
- Status = mIoMmu->Unmap (mIoMmu, Mapping);
- Status = mIoMmu->FreeBuffer (mIoMmu, Pages, HostAddress);
- } else {
- Status = EFI_SUCCESS;
- }
-
- return Status;
-}
-
-/**
- Initialize IOMMU.
-**/
-VOID
-IoMmuInit (
- VOID
- )
-{
- PeiServicesLocatePpi (
- &gEdkiiIoMmuPpiGuid,
- 0,
- NULL,
- (VOID **)&mIoMmu
- );
-}
+/** @file + The DMA memory help function. + + Copyright (c) 2017, Intel Corporation. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "EmmcBlockIoPei.h" + +EDKII_IOMMU_PPI *mIoMmu; + +/** + Provides the controller-specific addresses required to access system memory from a + DMA bus master. + + @param Operation Indicates if the bus master is going to read or write to system memory. + @param HostAddress The system memory address to map to the PCI controller. + @param NumberOfBytes On input the number of bytes to map. On output the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + +**/ +EFI_STATUS +IoMmuMap ( + IN EDKII_IOMMU_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + EFI_STATUS Status; + UINT64 Attribute; + + if (mIoMmu != NULL) { + Status = mIoMmu->Map ( + mIoMmu, + Operation, + HostAddress, + NumberOfBytes, + DeviceAddress, + Mapping + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + switch (Operation) { + case EdkiiIoMmuOperationBusMasterRead: + case EdkiiIoMmuOperationBusMasterRead64: + Attribute = EDKII_IOMMU_ACCESS_READ; + break; + case EdkiiIoMmuOperationBusMasterWrite: + case EdkiiIoMmuOperationBusMasterWrite64: + Attribute = EDKII_IOMMU_ACCESS_WRITE; + break; + case EdkiiIoMmuOperationBusMasterCommonBuffer: + case EdkiiIoMmuOperationBusMasterCommonBuffer64: + Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE; + break; + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + Status = mIoMmu->SetAttribute ( + mIoMmu, + *Mapping, + Attribute + ); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress; + *Mapping = NULL; + Status = EFI_SUCCESS; + } + + return Status; +} + +/** + Completes the Map() operation and releases any corresponding resources. + + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map(). + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. +**/ +EFI_STATUS +IoMmuUnmap ( + IN VOID *Mapping + ) +{ + EFI_STATUS Status; + + if (mIoMmu != NULL) { + Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0); + Status = mIoMmu->Unmap (mIoMmu, Mapping); + } else { + Status = EFI_SUCCESS; + } + + return Status; +} + +/** + Allocates pages that are suitable for an OperationBusMasterCommonBuffer or + OperationBusMasterCommonBuffer64 mapping. + + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +IoMmuAllocateBuffer ( + IN UINTN Pages, + OUT VOID **HostAddress, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + EFI_STATUS Status; + UINTN NumberOfBytes; + EFI_PHYSICAL_ADDRESS HostPhyAddress; + + *HostAddress = NULL; + *DeviceAddress = 0; + + if (mIoMmu != NULL) { + Status = mIoMmu->AllocateBuffer ( + mIoMmu, + EfiBootServicesData, + Pages, + HostAddress, + 0 + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + NumberOfBytes = EFI_PAGES_TO_SIZE (Pages); + Status = mIoMmu->Map ( + mIoMmu, + EdkiiIoMmuOperationBusMasterCommonBuffer, + *HostAddress, + &NumberOfBytes, + DeviceAddress, + Mapping + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + Status = mIoMmu->SetAttribute ( + mIoMmu, + *Mapping, + EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE + ); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + Status = PeiServicesAllocatePages ( + EfiBootServicesData, + Pages, + &HostPhyAddress + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + *HostAddress = (VOID *)(UINTN)HostPhyAddress; + *DeviceAddress = HostPhyAddress; + *Mapping = NULL; + } + + return Status; +} + +/** + Frees memory that was allocated with AllocateBuffer(). + + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages + was not allocated with AllocateBuffer(). + +**/ +EFI_STATUS +IoMmuFreeBuffer ( + IN UINTN Pages, + IN VOID *HostAddress, + IN VOID *Mapping + ) +{ + EFI_STATUS Status; + + if (mIoMmu != NULL) { + Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0); + Status = mIoMmu->Unmap (mIoMmu, Mapping); + Status = mIoMmu->FreeBuffer (mIoMmu, Pages, HostAddress); + } else { + Status = EFI_SUCCESS; + } + + return Status; +} + +/** + Initialize IOMMU. +**/ +VOID +IoMmuInit ( + VOID + ) +{ + PeiServicesLocatePpi ( + &gEdkiiIoMmuPpiGuid, + 0, + NULL, + (VOID **)&mIoMmu + ); +} diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.c b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.c index a87eb2092f..a7cf38a864 100644 --- a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.c +++ b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.c @@ -1,857 +1,857 @@ -/** @file
-
- Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "EmmcBlockIoPei.h"
-
-//
-// Template for EMMC HC Slot Data.
-//
-EMMC_PEIM_HC_SLOT gEmmcHcSlotTemplate = {
- EMMC_PEIM_SLOT_SIG, // Signature
- { // Media
- {
- MSG_EMMC_DP,
- FALSE,
- TRUE,
- FALSE,
- 0x200,
- 0
- },
- {
- MSG_EMMC_DP,
- FALSE,
- TRUE,
- FALSE,
- 0x200,
- 0
- },
- {
- MSG_EMMC_DP,
- FALSE,
- TRUE,
- FALSE,
- 0x200,
- 0
- },
- {
- MSG_EMMC_DP,
- FALSE,
- TRUE,
- FALSE,
- 0x200,
- 0
- },
- {
- MSG_EMMC_DP,
- FALSE,
- TRUE,
- FALSE,
- 0x200,
- 0
- },
- {
- MSG_EMMC_DP,
- FALSE,
- TRUE,
- FALSE,
- 0x200,
- 0
- },
- {
- MSG_EMMC_DP,
- FALSE,
- TRUE,
- FALSE,
- 0x200,
- 0
- },
- {
- MSG_EMMC_DP,
- FALSE,
- TRUE,
- FALSE,
- 0x200,
- 0
- }
- },
- 0, // MediaNum
- { // PartitionType
- EmmcPartitionUnknown,
- EmmcPartitionUnknown,
- EmmcPartitionUnknown,
- EmmcPartitionUnknown,
- EmmcPartitionUnknown,
- EmmcPartitionUnknown,
- EmmcPartitionUnknown,
- EmmcPartitionUnknown
- },
- 0, // EmmcHcBase
- { // Capability
- 0,
- },
- { // Csd
- 0,
- },
- { // ExtCsd
- { 0 },
- },
- TRUE, // SectorAddressing
- NULL // Private
-};
-
-//
-// Template for EMMC HC Private Data.
-//
-EMMC_PEIM_HC_PRIVATE_DATA gEmmcHcPrivateTemplate = {
- EMMC_PEIM_SIG, // Signature
- NULL, // Pool
- { // BlkIoPpi
- EmmcBlockIoPeimGetDeviceNo,
- EmmcBlockIoPeimGetMediaInfo,
- EmmcBlockIoPeimReadBlocks
- },
- { // BlkIo2Ppi
- EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,
- EmmcBlockIoPeimGetDeviceNo2,
- EmmcBlockIoPeimGetMediaInfo2,
- EmmcBlockIoPeimReadBlocks2
- },
- { // BlkIoPpiList
- EFI_PEI_PPI_DESCRIPTOR_PPI,
- &gEfiPeiVirtualBlockIoPpiGuid,
- NULL
- },
- { // BlkIo2PpiList
- EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
- &gEfiPeiVirtualBlockIo2PpiGuid,
- NULL
- },
- { // EndOfPeiNotifyList
- (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
- &gEfiEndOfPeiSignalPpiGuid,
- EmmcBlockIoPeimEndOfPei
- },
- { // Slot
- {
- 0,
- },
- {
- 0,
- },
- {
- 0,
- },
- {
- 0,
- },
- {
- 0,
- },
- {
- 0,
- }
- },
- 0, // SlotNum
- 0 // TotalBlkIoDevices
-};
-
-/**
- Gets the count of block I/O devices that one specific block driver detects.
-
- This function is used for getting the count of block I/O devices that one
- specific block driver detects. To the PEI ATAPI driver, it returns the number
- of all the detected ATAPI devices it detects during the enumeration process.
- To the PEI legacy floppy driver, it returns the number of all the legacy
- devices it finds during its enumeration process. If no device is detected,
- then the function will return zero.
-
- @param[in] PeiServices General-purpose services that are available
- to every PEIM.
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
- instance.
- @param[out] NumberBlockDevices The number of block I/O devices discovered.
-
- @retval EFI_SUCCESS The operation performed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcBlockIoPeimGetDeviceNo (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
- OUT UINTN *NumberBlockDevices
- )
-{
- EMMC_PEIM_HC_PRIVATE_DATA *Private;
-
- Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
- *NumberBlockDevices = Private->TotalBlkIoDevices;
- return EFI_SUCCESS;
-}
-
-/**
- Gets a block device's media information.
-
- This function will provide the caller with the specified block device's media
- information. If the media changes, calling this function will update the media
- information accordingly.
-
- @param[in] PeiServices General-purpose services that are available to every
- PEIM
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
- @param[in] DeviceIndex Specifies the block device to which the function wants
- to talk. Because the driver that implements Block I/O
- PPIs will manage multiple block devices, the PPIs that
- want to talk to a single device must specify the
- device index that was assigned during the enumeration
- process. This index is a number from one to
- NumberBlockDevices.
- @param[out] MediaInfo The media information of the specified block media.
- The caller is responsible for the ownership of this
- data structure.
-
- @par Note:
- The MediaInfo structure describes an enumeration of possible block device
- types. This enumeration exists because no device paths are actually passed
- across interfaces that describe the type or class of hardware that is publishing
- the block I/O interface. This enumeration will allow for policy decisions
- in the Recovery PEIM, such as "Try to recover from legacy floppy first,
- LS-120 second, CD-ROM third." If there are multiple partitions abstracted
- by a given device type, they should be reported in ascending order; this
- order also applies to nested partitions, such as legacy MBR, where the
- outermost partitions would have precedence in the reporting order. The
- same logic applies to systems such as IDE that have precedence relationships
- like "Master/Slave" or "Primary/Secondary". The master device should be
- reported first, the slave second.
-
- @retval EFI_SUCCESS Media information about the specified block device
- was obtained successfully.
- @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
- error.
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcBlockIoPeimGetMediaInfo (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
- IN UINTN DeviceIndex,
- OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
- )
-{
- EMMC_PEIM_HC_PRIVATE_DATA *Private;
- UINT8 SlotNum;
- UINT8 MediaNum;
- UINT8 Location;
- BOOLEAN Found;
-
- Found = FALSE;
- Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
-
- if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Location = 0;
- MediaNum = 0;
- for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {
- for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {
- Location++;
- if (Location == DeviceIndex) {
- Found = TRUE;
- break;
- }
- }
-
- if (Found) {
- break;
- }
- }
-
- MediaInfo->DeviceType = EMMC;
- MediaInfo->MediaPresent = TRUE;
- MediaInfo->LastBlock = (UINTN)Private->Slot[SlotNum].Media[MediaNum].LastBlock;
- MediaInfo->BlockSize = Private->Slot[SlotNum].Media[MediaNum].BlockSize;
-
- return EFI_SUCCESS;
-}
-
-/**
- Reads the requested number of blocks from the specified block device.
-
- The function reads the requested number of blocks from the device. All the
- blocks are read, or an error is returned. If there is no media in the device,
- the function returns EFI_NO_MEDIA.
-
- @param[in] PeiServices General-purpose services that are available to
- every PEIM.
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
- @param[in] DeviceIndex Specifies the block device to which the function wants
- to talk. Because the driver that implements Block I/O
- PPIs will manage multiple block devices, PPIs that
- want to talk to a single device must specify the device
- index that was assigned during the enumeration process.
- This index is a number from one to NumberBlockDevices.
- @param[in] StartLBA The starting logical block address (LBA) to read from
- on the device
- @param[in] BufferSize The size of the Buffer in bytes. This number must be
- a multiple of the intrinsic block size of the device.
- @param[out] Buffer A pointer to the destination buffer for the data.
- The caller is responsible for the 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 attempting
- to perform the read operation.
- @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
- valid, or the buffer is not properly aligned.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
- the intrinsic block size of the device.
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcBlockIoPeimReadBlocks (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
- IN UINTN DeviceIndex,
- IN EFI_PEI_LBA StartLBA,
- IN UINTN BufferSize,
- OUT VOID *Buffer
- )
-{
- EFI_STATUS Status;
- UINT32 BlockSize;
- UINTN NumberOfBlocks;
- EMMC_PEIM_HC_PRIVATE_DATA *Private;
- UINT8 SlotNum;
- UINT8 MediaNum;
- UINT8 Location;
- UINT8 PartitionConfig;
- UINTN Remaining;
- UINT32 MaxBlock;
- BOOLEAN Found;
-
- Status = EFI_SUCCESS;
- Found = FALSE;
- Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
-
- //
- // Check parameters
- //
- if (Buffer == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (BufferSize == 0) {
- return EFI_SUCCESS;
- }
-
- if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Location = 0;
- MediaNum = 0;
- for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {
- for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {
- Location++;
- if (Location == DeviceIndex) {
- Found = TRUE;
- break;
- }
- }
-
- if (Found) {
- break;
- }
- }
-
- BlockSize = Private->Slot[SlotNum].Media[MediaNum].BlockSize;
- if (BufferSize % BlockSize != 0) {
- return EFI_BAD_BUFFER_SIZE;
- }
-
- if (StartLBA > Private->Slot[SlotNum].Media[MediaNum].LastBlock) {
- return EFI_INVALID_PARAMETER;
- }
-
- NumberOfBlocks = BufferSize / BlockSize;
-
- //
- // Check if needs to switch partition access.
- //
- PartitionConfig = Private->Slot[SlotNum].ExtCsd.PartitionConfig;
- if ((PartitionConfig & 0x7) != Private->Slot[SlotNum].PartitionType[MediaNum]) {
- PartitionConfig &= (UINT8) ~0x7;
- PartitionConfig |= Private->Slot[SlotNum].PartitionType[MediaNum];
- Status = EmmcPeimSwitch (
- &Private->Slot[SlotNum],
- 0x3,
- OFFSET_OF (EMMC_EXT_CSD, PartitionConfig),
- PartitionConfig,
- 0x0
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Private->Slot[SlotNum].ExtCsd.PartitionConfig = PartitionConfig;
- }
-
- //
- // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
- //
- Remaining = NumberOfBlocks;
- MaxBlock = 0xFFFF;
-
- while (Remaining > 0) {
- if (Remaining <= MaxBlock) {
- NumberOfBlocks = Remaining;
- } else {
- NumberOfBlocks = MaxBlock;
- }
-
- Status = EmmcPeimSetBlkCount (&Private->Slot[SlotNum], (UINT16)NumberOfBlocks);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- BufferSize = NumberOfBlocks * BlockSize;
- Status = EmmcPeimRwMultiBlocks (&Private->Slot[SlotNum], StartLBA, BlockSize, Buffer, BufferSize, TRUE);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- StartLBA += NumberOfBlocks;
- Buffer = (UINT8 *)Buffer + BufferSize;
- Remaining -= NumberOfBlocks;
- }
-
- return Status;
-}
-
-/**
- Gets the count of block I/O devices that one specific block driver detects.
-
- This function is used for getting the count of block I/O devices that one
- specific block driver detects. To the PEI ATAPI driver, it returns the number
- of all the detected ATAPI devices it detects during the enumeration process.
- To the PEI legacy floppy driver, it returns the number of all the legacy
- devices it finds during its enumeration process. If no device is detected,
- then the function will return zero.
-
- @param[in] PeiServices General-purpose services that are available
- to every PEIM.
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
- instance.
- @param[out] NumberBlockDevices The number of block I/O devices discovered.
-
- @retval EFI_SUCCESS The operation performed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcBlockIoPeimGetDeviceNo2 (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
- OUT UINTN *NumberBlockDevices
- )
-{
- EMMC_PEIM_HC_PRIVATE_DATA *Private;
-
- Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
- *NumberBlockDevices = Private->TotalBlkIoDevices;
-
- return EFI_SUCCESS;
-}
-
-/**
- Gets a block device's media information.
-
- This function will provide the caller with the specified block device's media
- information. If the media changes, calling this function will update the media
- information accordingly.
-
- @param[in] PeiServices General-purpose services that are available to every
- PEIM
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
- @param[in] DeviceIndex Specifies the block device to which the function wants
- to talk. Because the driver that implements Block I/O
- PPIs will manage multiple block devices, the PPIs that
- want to talk to a single device must specify the
- device index that was assigned during the enumeration
- process. This index is a number from one to
- NumberBlockDevices.
- @param[out] MediaInfo The media information of the specified block media.
- The caller is responsible for the ownership of this
- data structure.
-
- @par Note:
- The MediaInfo structure describes an enumeration of possible block device
- types. This enumeration exists because no device paths are actually passed
- across interfaces that describe the type or class of hardware that is publishing
- the block I/O interface. This enumeration will allow for policy decisions
- in the Recovery PEIM, such as "Try to recover from legacy floppy first,
- LS-120 second, CD-ROM third." If there are multiple partitions abstracted
- by a given device type, they should be reported in ascending order; this
- order also applies to nested partitions, such as legacy MBR, where the
- outermost partitions would have precedence in the reporting order. The
- same logic applies to systems such as IDE that have precedence relationships
- like "Master/Slave" or "Primary/Secondary". The master device should be
- reported first, the slave second.
-
- @retval EFI_SUCCESS Media information about the specified block device
- was obtained successfully.
- @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
- error.
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcBlockIoPeimGetMediaInfo2 (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
- IN UINTN DeviceIndex,
- OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
- )
-{
- EFI_STATUS Status;
- EMMC_PEIM_HC_PRIVATE_DATA *Private;
- EFI_PEI_BLOCK_IO_MEDIA Media;
- UINT8 SlotNum;
- UINT8 MediaNum;
- UINT8 Location;
- BOOLEAN Found;
-
- Found = FALSE;
- Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
-
- Status = EmmcBlockIoPeimGetMediaInfo (
- PeiServices,
- &Private->BlkIoPpi,
- DeviceIndex,
- &Media
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Location = 0;
- MediaNum = 0;
- for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {
- for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {
- Location++;
- if (Location == DeviceIndex) {
- Found = TRUE;
- break;
- }
- }
-
- if (Found) {
- break;
- }
- }
-
- CopyMem (MediaInfo, &(Private->Slot[SlotNum].Media[MediaNum]), sizeof (EFI_PEI_BLOCK_IO2_MEDIA));
- return EFI_SUCCESS;
-}
-
-/**
- Reads the requested number of blocks from the specified block device.
-
- The function reads the requested number of blocks from the device. All the
- blocks are read, or an error is returned. If there is no media in the device,
- the function returns EFI_NO_MEDIA.
-
- @param[in] PeiServices General-purpose services that are available to
- every PEIM.
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
- @param[in] DeviceIndex Specifies the block device to which the function wants
- to talk. Because the driver that implements Block I/O
- PPIs will manage multiple block devices, PPIs that
- want to talk to a single device must specify the device
- index that was assigned during the enumeration process.
- This index is a number from one to NumberBlockDevices.
- @param[in] StartLBA The starting logical block address (LBA) to read from
- on the device
- @param[in] BufferSize The size of the Buffer in bytes. This number must be
- a multiple of the intrinsic block size of the device.
- @param[out] Buffer A pointer to the destination buffer for the data.
- The caller is responsible for the 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 attempting
- to perform the read operation.
- @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
- valid, or the buffer is not properly aligned.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
- the intrinsic block size of the device.
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcBlockIoPeimReadBlocks2 (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
- IN UINTN DeviceIndex,
- IN EFI_PEI_LBA StartLBA,
- IN UINTN BufferSize,
- OUT VOID *Buffer
- )
-{
- EFI_STATUS Status;
- EMMC_PEIM_HC_PRIVATE_DATA *Private;
-
- Status = EFI_SUCCESS;
- Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
-
- Status = EmmcBlockIoPeimReadBlocks (
- PeiServices,
- &Private->BlkIoPpi,
- DeviceIndex,
- StartLBA,
- BufferSize,
- Buffer
- );
- return Status;
-}
-
-/**
- One notified function to cleanup the allocated DMA buffers at the end of PEI.
-
- @param[in] PeiServices Pointer to PEI Services Table.
- @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
- event that caused this function to execute.
- @param[in] Ppi Pointer to the PPI data associated with this function.
-
- @retval EFI_SUCCESS The function completes successfully
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcBlockIoPeimEndOfPei (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
- IN VOID *Ppi
- )
-{
- EMMC_PEIM_HC_PRIVATE_DATA *Private;
-
- Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);
-
- if ((Private->Pool != NULL) && (Private->Pool->Head != NULL)) {
- EmmcPeimFreeMemPool (Private->Pool);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- The user code starts with this function.
-
- @param FileHandle Handle of the file being invoked.
- @param PeiServices Describes the list of possible PEI Services.
-
- @retval EFI_SUCCESS The driver is successfully initialized.
- @retval Others Can't initialize the driver.
-
-**/
-EFI_STATUS
-EFIAPI
-InitializeEmmcBlockIoPeim (
- IN EFI_PEI_FILE_HANDLE FileHandle,
- IN CONST EFI_PEI_SERVICES **PeiServices
- )
-{
- EFI_STATUS Status;
- EMMC_PEIM_HC_PRIVATE_DATA *Private;
- EDKII_SD_MMC_HOST_CONTROLLER_PPI *SdMmcHcPpi;
- UINT32 Index;
- UINT32 PartitionIndex;
- UINTN *MmioBase;
- UINT8 BarNum;
- UINT8 SlotNum;
- UINT8 MediaNum;
- UINT8 Controller;
- UINT64 Capacity;
- EMMC_EXT_CSD *ExtCsd;
- EMMC_HC_SLOT_CAP Capability;
- EMMC_PEIM_HC_SLOT *Slot;
- UINT32 SecCount;
- UINT32 GpSizeMult;
-
- //
- // Shadow this PEIM to run from memory
- //
- if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
- return EFI_SUCCESS;
- }
-
- //
- // locate Emmc host controller PPI
- //
- Status = PeiServicesLocatePpi (
- &gEdkiiPeiSdMmcHostControllerPpiGuid,
- 0,
- NULL,
- (VOID **)&SdMmcHcPpi
- );
- if (EFI_ERROR (Status)) {
- return EFI_DEVICE_ERROR;
- }
-
- IoMmuInit ();
-
- Controller = 0;
- MmioBase = NULL;
- while (TRUE) {
- Status = SdMmcHcPpi->GetSdMmcHcMmioBar (SdMmcHcPpi, Controller, &MmioBase, &BarNum);
- //
- // When status is error, meant no controller is found
- //
- if (EFI_ERROR (Status)) {
- break;
- }
-
- if (BarNum == 0) {
- Controller++;
- continue;
- }
-
- Private = AllocateCopyPool (sizeof (EMMC_PEIM_HC_PRIVATE_DATA), &gEmmcHcPrivateTemplate);
- if (Private == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- break;
- }
-
- Private->BlkIoPpiList.Ppi = (VOID *)&Private->BlkIoPpi;
- Private->BlkIo2PpiList.Ppi = (VOID *)&Private->BlkIo2Ppi;
- //
- // Initialize the memory pool which will be used in all transactions.
- //
- Status = EmmcPeimInitMemPool (Private);
- if (EFI_ERROR (Status)) {
- Status = EFI_OUT_OF_RESOURCES;
- break;
- }
-
- for (Index = 0; Index < BarNum; Index++) {
- Status = EmmcPeimHcGetCapability (MmioBase[Index], &Capability);
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- if (Capability.SlotType != 0x1) {
- DEBUG ((DEBUG_INFO, "The slot at 0x%x is not embedded slot type\n", MmioBase[Index]));
- Status = EFI_UNSUPPORTED;
- continue;
- }
-
- Status = EmmcPeimHcReset (MmioBase[Index]);
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- Status = EmmcPeimHcCardDetect (MmioBase[Index]);
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- Status = EmmcPeimHcInitHost (MmioBase[Index]);
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- SlotNum = Private->SlotNum;
- Slot = &Private->Slot[SlotNum];
- CopyMem (Slot, &gEmmcHcSlotTemplate, sizeof (EMMC_PEIM_HC_SLOT));
- Slot->Private = Private;
- Slot->EmmcHcBase = MmioBase[Index];
- CopyMem (&Slot->Capability, &Capability, sizeof (Capability));
-
- Status = EmmcPeimIdentification (Slot);
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- ExtCsd = &Slot->ExtCsd;
- if (ExtCsd->ExtCsdRev < 5) {
- DEBUG ((DEBUG_ERROR, "The EMMC device version is too low, we don't support!!!\n"));
- Status = EFI_UNSUPPORTED;
- continue;
- }
-
- if ((ExtCsd->PartitioningSupport & BIT0) != BIT0) {
- DEBUG ((DEBUG_ERROR, "The EMMC device doesn't support Partition Feature!!!\n"));
- Status = EFI_UNSUPPORTED;
- continue;
- }
-
- for (PartitionIndex = 0; PartitionIndex < EMMC_PEIM_MAX_PARTITIONS; PartitionIndex++) {
- switch (PartitionIndex) {
- 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 = (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 = (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 = (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 = (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);
- continue;
- }
-
- MediaNum = Slot->MediaNum;
- if (Capacity != 0) {
- Slot->Media[MediaNum].LastBlock = DivU64x32 (Capacity, Slot->Media[MediaNum].BlockSize) - 1;
- Slot->PartitionType[MediaNum] = PartitionIndex;
- Private->TotalBlkIoDevices++;
- Slot->MediaNum++;
- }
- }
-
- Private->SlotNum++;
- }
-
- Controller++;
-
- if (!EFI_ERROR (Status)) {
- PeiServicesInstallPpi (&Private->BlkIoPpiList);
- PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);
- } else {
- if (Private->Pool->Head != NULL) {
- EmmcPeimFreeMemPool (Private->Pool);
- }
- }
- }
-
- return EFI_SUCCESS;
-}
+/** @file + + Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "EmmcBlockIoPei.h" + +// +// Template for EMMC HC Slot Data. +// +EMMC_PEIM_HC_SLOT gEmmcHcSlotTemplate = { + EMMC_PEIM_SLOT_SIG, // Signature + { // Media + { + MSG_EMMC_DP, + FALSE, + TRUE, + FALSE, + 0x200, + 0 + }, + { + MSG_EMMC_DP, + FALSE, + TRUE, + FALSE, + 0x200, + 0 + }, + { + MSG_EMMC_DP, + FALSE, + TRUE, + FALSE, + 0x200, + 0 + }, + { + MSG_EMMC_DP, + FALSE, + TRUE, + FALSE, + 0x200, + 0 + }, + { + MSG_EMMC_DP, + FALSE, + TRUE, + FALSE, + 0x200, + 0 + }, + { + MSG_EMMC_DP, + FALSE, + TRUE, + FALSE, + 0x200, + 0 + }, + { + MSG_EMMC_DP, + FALSE, + TRUE, + FALSE, + 0x200, + 0 + }, + { + MSG_EMMC_DP, + FALSE, + TRUE, + FALSE, + 0x200, + 0 + } + }, + 0, // MediaNum + { // PartitionType + EmmcPartitionUnknown, + EmmcPartitionUnknown, + EmmcPartitionUnknown, + EmmcPartitionUnknown, + EmmcPartitionUnknown, + EmmcPartitionUnknown, + EmmcPartitionUnknown, + EmmcPartitionUnknown + }, + 0, // EmmcHcBase + { // Capability + 0, + }, + { // Csd + 0, + }, + { // ExtCsd + { 0 }, + }, + TRUE, // SectorAddressing + NULL // Private +}; + +// +// Template for EMMC HC Private Data. +// +EMMC_PEIM_HC_PRIVATE_DATA gEmmcHcPrivateTemplate = { + EMMC_PEIM_SIG, // Signature + NULL, // Pool + { // BlkIoPpi + EmmcBlockIoPeimGetDeviceNo, + EmmcBlockIoPeimGetMediaInfo, + EmmcBlockIoPeimReadBlocks + }, + { // BlkIo2Ppi + EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION, + EmmcBlockIoPeimGetDeviceNo2, + EmmcBlockIoPeimGetMediaInfo2, + EmmcBlockIoPeimReadBlocks2 + }, + { // BlkIoPpiList + EFI_PEI_PPI_DESCRIPTOR_PPI, + &gEfiPeiVirtualBlockIoPpiGuid, + NULL + }, + { // BlkIo2PpiList + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gEfiPeiVirtualBlockIo2PpiGuid, + NULL + }, + { // EndOfPeiNotifyList + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiEndOfPeiSignalPpiGuid, + EmmcBlockIoPeimEndOfPei + }, + { // Slot + { + 0, + }, + { + 0, + }, + { + 0, + }, + { + 0, + }, + { + 0, + }, + { + 0, + } + }, + 0, // SlotNum + 0 // TotalBlkIoDevices +}; + +/** + Gets the count of block I/O devices that one specific block driver detects. + + This function is used for getting the count of block I/O devices that one + specific block driver detects. To the PEI ATAPI driver, it returns the number + of all the detected ATAPI devices it detects during the enumeration process. + To the PEI legacy floppy driver, it returns the number of all the legacy + devices it finds during its enumeration process. If no device is detected, + then the function will return zero. + + @param[in] PeiServices General-purpose services that are available + to every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI + instance. + @param[out] NumberBlockDevices The number of block I/O devices discovered. + + @retval EFI_SUCCESS The operation performed successfully. + +**/ +EFI_STATUS +EFIAPI +EmmcBlockIoPeimGetDeviceNo ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + OUT UINTN *NumberBlockDevices + ) +{ + EMMC_PEIM_HC_PRIVATE_DATA *Private; + + Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This); + *NumberBlockDevices = Private->TotalBlkIoDevices; + return EFI_SUCCESS; +} + +/** + Gets a block device's media information. + + This function will provide the caller with the specified block device's media + information. If the media changes, calling this function will update the media + information accordingly. + + @param[in] PeiServices General-purpose services that are available to every + PEIM + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, the PPIs that + want to talk to a single device must specify the + device index that was assigned during the enumeration + process. This index is a number from one to + NumberBlockDevices. + @param[out] MediaInfo The media information of the specified block media. + The caller is responsible for the ownership of this + data structure. + + @par Note: + The MediaInfo structure describes an enumeration of possible block device + types. This enumeration exists because no device paths are actually passed + across interfaces that describe the type or class of hardware that is publishing + the block I/O interface. This enumeration will allow for policy decisions + in the Recovery PEIM, such as "Try to recover from legacy floppy first, + LS-120 second, CD-ROM third." If there are multiple partitions abstracted + by a given device type, they should be reported in ascending order; this + order also applies to nested partitions, such as legacy MBR, where the + outermost partitions would have precedence in the reporting order. The + same logic applies to systems such as IDE that have precedence relationships + like "Master/Slave" or "Primary/Secondary". The master device should be + reported first, the slave second. + + @retval EFI_SUCCESS Media information about the specified block device + was obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware + error. + +**/ +EFI_STATUS +EFIAPI +EmmcBlockIoPeimGetMediaInfo ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + IN UINTN DeviceIndex, + OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo + ) +{ + EMMC_PEIM_HC_PRIVATE_DATA *Private; + UINT8 SlotNum; + UINT8 MediaNum; + UINT8 Location; + BOOLEAN Found; + + Found = FALSE; + Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This); + + if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) { + return EFI_INVALID_PARAMETER; + } + + Location = 0; + MediaNum = 0; + for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) { + for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) { + Location++; + if (Location == DeviceIndex) { + Found = TRUE; + break; + } + } + + if (Found) { + break; + } + } + + MediaInfo->DeviceType = EMMC; + MediaInfo->MediaPresent = TRUE; + MediaInfo->LastBlock = (UINTN)Private->Slot[SlotNum].Media[MediaNum].LastBlock; + MediaInfo->BlockSize = Private->Slot[SlotNum].Media[MediaNum].BlockSize; + + return EFI_SUCCESS; +} + +/** + Reads the requested number of blocks from the specified block device. + + The function reads the requested number of blocks from the device. All the + blocks are read, or an error is returned. If there is no media in the device, + the function returns EFI_NO_MEDIA. + + @param[in] PeiServices General-purpose services that are available to + every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, PPIs that + want to talk to a single device must specify the device + index that was assigned during the enumeration process. + This index is a number from one to NumberBlockDevices. + @param[in] StartLBA The starting logical block address (LBA) to read from + on the device + @param[in] BufferSize The size of the Buffer in bytes. This number must be + a multiple of the intrinsic block size of the device. + @param[out] Buffer A pointer to the destination buffer for the data. + The caller is responsible for the 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 attempting + to perform the read operation. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not + valid, or the buffer is not properly aligned. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of + the intrinsic block size of the device. + +**/ +EFI_STATUS +EFIAPI +EmmcBlockIoPeimReadBlocks ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + IN UINTN DeviceIndex, + IN EFI_PEI_LBA StartLBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT32 BlockSize; + UINTN NumberOfBlocks; + EMMC_PEIM_HC_PRIVATE_DATA *Private; + UINT8 SlotNum; + UINT8 MediaNum; + UINT8 Location; + UINT8 PartitionConfig; + UINTN Remaining; + UINT32 MaxBlock; + BOOLEAN Found; + + Status = EFI_SUCCESS; + Found = FALSE; + Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This); + + // + // Check parameters + // + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) { + return EFI_INVALID_PARAMETER; + } + + Location = 0; + MediaNum = 0; + for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) { + for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) { + Location++; + if (Location == DeviceIndex) { + Found = TRUE; + break; + } + } + + if (Found) { + break; + } + } + + BlockSize = Private->Slot[SlotNum].Media[MediaNum].BlockSize; + if (BufferSize % BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (StartLBA > Private->Slot[SlotNum].Media[MediaNum].LastBlock) { + return EFI_INVALID_PARAMETER; + } + + NumberOfBlocks = BufferSize / BlockSize; + + // + // Check if needs to switch partition access. + // + PartitionConfig = Private->Slot[SlotNum].ExtCsd.PartitionConfig; + if ((PartitionConfig & 0x7) != Private->Slot[SlotNum].PartitionType[MediaNum]) { + PartitionConfig &= (UINT8) ~0x7; + PartitionConfig |= Private->Slot[SlotNum].PartitionType[MediaNum]; + Status = EmmcPeimSwitch ( + &Private->Slot[SlotNum], + 0x3, + OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), + PartitionConfig, + 0x0 + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Private->Slot[SlotNum].ExtCsd.PartitionConfig = PartitionConfig; + } + + // + // Start to execute data transfer. The max block number in single cmd is 65535 blocks. + // + Remaining = NumberOfBlocks; + MaxBlock = 0xFFFF; + + while (Remaining > 0) { + if (Remaining <= MaxBlock) { + NumberOfBlocks = Remaining; + } else { + NumberOfBlocks = MaxBlock; + } + + Status = EmmcPeimSetBlkCount (&Private->Slot[SlotNum], (UINT16)NumberOfBlocks); + if (EFI_ERROR (Status)) { + return Status; + } + + BufferSize = NumberOfBlocks * BlockSize; + Status = EmmcPeimRwMultiBlocks (&Private->Slot[SlotNum], StartLBA, BlockSize, Buffer, BufferSize, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + + StartLBA += NumberOfBlocks; + Buffer = (UINT8 *)Buffer + BufferSize; + Remaining -= NumberOfBlocks; + } + + return Status; +} + +/** + Gets the count of block I/O devices that one specific block driver detects. + + This function is used for getting the count of block I/O devices that one + specific block driver detects. To the PEI ATAPI driver, it returns the number + of all the detected ATAPI devices it detects during the enumeration process. + To the PEI legacy floppy driver, it returns the number of all the legacy + devices it finds during its enumeration process. If no device is detected, + then the function will return zero. + + @param[in] PeiServices General-purpose services that are available + to every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI + instance. + @param[out] NumberBlockDevices The number of block I/O devices discovered. + + @retval EFI_SUCCESS The operation performed successfully. + +**/ +EFI_STATUS +EFIAPI +EmmcBlockIoPeimGetDeviceNo2 ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, + OUT UINTN *NumberBlockDevices + ) +{ + EMMC_PEIM_HC_PRIVATE_DATA *Private; + + Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This); + *NumberBlockDevices = Private->TotalBlkIoDevices; + + return EFI_SUCCESS; +} + +/** + Gets a block device's media information. + + This function will provide the caller with the specified block device's media + information. If the media changes, calling this function will update the media + information accordingly. + + @param[in] PeiServices General-purpose services that are available to every + PEIM + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, the PPIs that + want to talk to a single device must specify the + device index that was assigned during the enumeration + process. This index is a number from one to + NumberBlockDevices. + @param[out] MediaInfo The media information of the specified block media. + The caller is responsible for the ownership of this + data structure. + + @par Note: + The MediaInfo structure describes an enumeration of possible block device + types. This enumeration exists because no device paths are actually passed + across interfaces that describe the type or class of hardware that is publishing + the block I/O interface. This enumeration will allow for policy decisions + in the Recovery PEIM, such as "Try to recover from legacy floppy first, + LS-120 second, CD-ROM third." If there are multiple partitions abstracted + by a given device type, they should be reported in ascending order; this + order also applies to nested partitions, such as legacy MBR, where the + outermost partitions would have precedence in the reporting order. The + same logic applies to systems such as IDE that have precedence relationships + like "Master/Slave" or "Primary/Secondary". The master device should be + reported first, the slave second. + + @retval EFI_SUCCESS Media information about the specified block device + was obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware + error. + +**/ +EFI_STATUS +EFIAPI +EmmcBlockIoPeimGetMediaInfo2 ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, + IN UINTN DeviceIndex, + OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo + ) +{ + EFI_STATUS Status; + EMMC_PEIM_HC_PRIVATE_DATA *Private; + EFI_PEI_BLOCK_IO_MEDIA Media; + UINT8 SlotNum; + UINT8 MediaNum; + UINT8 Location; + BOOLEAN Found; + + Found = FALSE; + Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This); + + Status = EmmcBlockIoPeimGetMediaInfo ( + PeiServices, + &Private->BlkIoPpi, + DeviceIndex, + &Media + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Location = 0; + MediaNum = 0; + for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) { + for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) { + Location++; + if (Location == DeviceIndex) { + Found = TRUE; + break; + } + } + + if (Found) { + break; + } + } + + CopyMem (MediaInfo, &(Private->Slot[SlotNum].Media[MediaNum]), sizeof (EFI_PEI_BLOCK_IO2_MEDIA)); + return EFI_SUCCESS; +} + +/** + Reads the requested number of blocks from the specified block device. + + The function reads the requested number of blocks from the device. All the + blocks are read, or an error is returned. If there is no media in the device, + the function returns EFI_NO_MEDIA. + + @param[in] PeiServices General-purpose services that are available to + every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, PPIs that + want to talk to a single device must specify the device + index that was assigned during the enumeration process. + This index is a number from one to NumberBlockDevices. + @param[in] StartLBA The starting logical block address (LBA) to read from + on the device + @param[in] BufferSize The size of the Buffer in bytes. This number must be + a multiple of the intrinsic block size of the device. + @param[out] Buffer A pointer to the destination buffer for the data. + The caller is responsible for the 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 attempting + to perform the read operation. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not + valid, or the buffer is not properly aligned. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of + the intrinsic block size of the device. + +**/ +EFI_STATUS +EFIAPI +EmmcBlockIoPeimReadBlocks2 ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, + IN UINTN DeviceIndex, + IN EFI_PEI_LBA StartLBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + EMMC_PEIM_HC_PRIVATE_DATA *Private; + + Status = EFI_SUCCESS; + Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This); + + Status = EmmcBlockIoPeimReadBlocks ( + PeiServices, + &Private->BlkIoPpi, + DeviceIndex, + StartLBA, + BufferSize, + Buffer + ); + return Status; +} + +/** + One notified function to cleanup the allocated DMA buffers at the end of PEI. + + @param[in] PeiServices Pointer to PEI Services Table. + @param[in] NotifyDescriptor Pointer to the descriptor for the Notification + event that caused this function to execute. + @param[in] Ppi Pointer to the PPI data associated with this function. + + @retval EFI_SUCCESS The function completes successfully + +**/ +EFI_STATUS +EFIAPI +EmmcBlockIoPeimEndOfPei ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + EMMC_PEIM_HC_PRIVATE_DATA *Private; + + Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor); + + if ((Private->Pool != NULL) && (Private->Pool->Head != NULL)) { + EmmcPeimFreeMemPool (Private->Pool); + } + + return EFI_SUCCESS; +} + +/** + The user code starts with this function. + + @param FileHandle Handle of the file being invoked. + @param PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCESS The driver is successfully initialized. + @retval Others Can't initialize the driver. + +**/ +EFI_STATUS +EFIAPI +InitializeEmmcBlockIoPeim ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + EMMC_PEIM_HC_PRIVATE_DATA *Private; + EDKII_SD_MMC_HOST_CONTROLLER_PPI *SdMmcHcPpi; + UINT32 Index; + UINT32 PartitionIndex; + UINTN *MmioBase; + UINT8 BarNum; + UINT8 SlotNum; + UINT8 MediaNum; + UINT8 Controller; + UINT64 Capacity; + EMMC_EXT_CSD *ExtCsd; + EMMC_HC_SLOT_CAP Capability; + EMMC_PEIM_HC_SLOT *Slot; + UINT32 SecCount; + UINT32 GpSizeMult; + + // + // Shadow this PEIM to run from memory + // + if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { + return EFI_SUCCESS; + } + + // + // locate Emmc host controller PPI + // + Status = PeiServicesLocatePpi ( + &gEdkiiPeiSdMmcHostControllerPpiGuid, + 0, + NULL, + (VOID **)&SdMmcHcPpi + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + IoMmuInit (); + + Controller = 0; + MmioBase = NULL; + while (TRUE) { + Status = SdMmcHcPpi->GetSdMmcHcMmioBar (SdMmcHcPpi, Controller, &MmioBase, &BarNum); + // + // When status is error, meant no controller is found + // + if (EFI_ERROR (Status)) { + break; + } + + if (BarNum == 0) { + Controller++; + continue; + } + + Private = AllocateCopyPool (sizeof (EMMC_PEIM_HC_PRIVATE_DATA), &gEmmcHcPrivateTemplate); + if (Private == NULL) { + Status = EFI_OUT_OF_RESOURCES; + break; + } + + Private->BlkIoPpiList.Ppi = (VOID *)&Private->BlkIoPpi; + Private->BlkIo2PpiList.Ppi = (VOID *)&Private->BlkIo2Ppi; + // + // Initialize the memory pool which will be used in all transactions. + // + Status = EmmcPeimInitMemPool (Private); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + break; + } + + for (Index = 0; Index < BarNum; Index++) { + Status = EmmcPeimHcGetCapability (MmioBase[Index], &Capability); + if (EFI_ERROR (Status)) { + continue; + } + + if (Capability.SlotType != 0x1) { + DEBUG ((DEBUG_INFO, "The slot at 0x%x is not embedded slot type\n", MmioBase[Index])); + Status = EFI_UNSUPPORTED; + continue; + } + + Status = EmmcPeimHcReset (MmioBase[Index]); + if (EFI_ERROR (Status)) { + continue; + } + + Status = EmmcPeimHcCardDetect (MmioBase[Index]); + if (EFI_ERROR (Status)) { + continue; + } + + Status = EmmcPeimHcInitHost (MmioBase[Index]); + if (EFI_ERROR (Status)) { + continue; + } + + SlotNum = Private->SlotNum; + Slot = &Private->Slot[SlotNum]; + CopyMem (Slot, &gEmmcHcSlotTemplate, sizeof (EMMC_PEIM_HC_SLOT)); + Slot->Private = Private; + Slot->EmmcHcBase = MmioBase[Index]; + CopyMem (&Slot->Capability, &Capability, sizeof (Capability)); + + Status = EmmcPeimIdentification (Slot); + if (EFI_ERROR (Status)) { + continue; + } + + ExtCsd = &Slot->ExtCsd; + if (ExtCsd->ExtCsdRev < 5) { + DEBUG ((DEBUG_ERROR, "The EMMC device version is too low, we don't support!!!\n")); + Status = EFI_UNSUPPORTED; + continue; + } + + if ((ExtCsd->PartitioningSupport & BIT0) != BIT0) { + DEBUG ((DEBUG_ERROR, "The EMMC device doesn't support Partition Feature!!!\n")); + Status = EFI_UNSUPPORTED; + continue; + } + + for (PartitionIndex = 0; PartitionIndex < EMMC_PEIM_MAX_PARTITIONS; PartitionIndex++) { + switch (PartitionIndex) { + 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 = (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 = (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 = (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 = (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); + continue; + } + + MediaNum = Slot->MediaNum; + if (Capacity != 0) { + Slot->Media[MediaNum].LastBlock = DivU64x32 (Capacity, Slot->Media[MediaNum].BlockSize) - 1; + Slot->PartitionType[MediaNum] = PartitionIndex; + Private->TotalBlkIoDevices++; + Slot->MediaNum++; + } + } + + Private->SlotNum++; + } + + Controller++; + + if (!EFI_ERROR (Status)) { + PeiServicesInstallPpi (&Private->BlkIoPpiList); + PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList); + } else { + if (Private->Pool->Head != NULL) { + EmmcPeimFreeMemPool (Private->Pool); + } + } + } + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.h b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.h index f8108c3082..23119a8f29 100644 --- a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.h +++ b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.h @@ -1,514 +1,514 @@ -/** @file
-
- Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _EMMC_BLOCK_IO_PEI_H_
-#define _EMMC_BLOCK_IO_PEI_H_
-
-#include <PiPei.h>
-
-#include <Ppi/SdMmcHostController.h>
-#include <Ppi/BlockIo.h>
-#include <Ppi/BlockIo2.h>
-#include <Ppi/IoMmu.h>
-#include <Ppi/EndOfPeiPhase.h>
-
-#include <Library/DebugLib.h>
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/IoLib.h>
-#include <Library/TimerLib.h>
-#include <Library/PeiServicesLib.h>
-
-#include <IndustryStandard/Emmc.h>
-
-typedef struct _EMMC_PEIM_HC_PRIVATE_DATA EMMC_PEIM_HC_PRIVATE_DATA;
-typedef struct _EMMC_PEIM_HC_SLOT EMMC_PEIM_HC_SLOT;
-typedef struct _EMMC_TRB EMMC_TRB;
-
-#include "EmmcHci.h"
-#include "EmmcHcMem.h"
-
-#define EMMC_PEIM_SIG SIGNATURE_32 ('E', 'M', 'C', 'P')
-#define EMMC_PEIM_SLOT_SIG SIGNATURE_32 ('E', 'M', 'C', 'S')
-
-#define EMMC_PEIM_MAX_SLOTS 6
-#define EMMC_PEIM_MAX_PARTITIONS 8
-
-struct _EMMC_PEIM_HC_SLOT {
- UINT32 Signature;
- EFI_PEI_BLOCK_IO2_MEDIA Media[EMMC_PEIM_MAX_PARTITIONS];
- UINT8 MediaNum;
- EMMC_PARTITION_TYPE PartitionType[EMMC_PEIM_MAX_PARTITIONS];
-
- UINTN EmmcHcBase;
- EMMC_HC_SLOT_CAP Capability;
- EMMC_CSD Csd;
- EMMC_EXT_CSD ExtCsd;
- BOOLEAN SectorAddressing;
- EMMC_PEIM_HC_PRIVATE_DATA *Private;
-};
-
-struct _EMMC_PEIM_HC_PRIVATE_DATA {
- UINT32 Signature;
- EMMC_PEIM_MEM_POOL *Pool;
- EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi;
- EFI_PEI_RECOVERY_BLOCK_IO2_PPI BlkIo2Ppi;
- EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList;
- EFI_PEI_PPI_DESCRIPTOR BlkIo2PpiList;
-
- //
- // EndOfPei callback is used to do the cleanups before exit of PEI phase.
- //
- EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList;
-
- EMMC_PEIM_HC_SLOT Slot[EMMC_PEIM_MAX_SLOTS];
- UINT8 SlotNum;
- UINT8 TotalBlkIoDevices;
-};
-
-#define EMMC_TIMEOUT MultU64x32((UINT64)(3), 1000000)
-#define GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS(a) CR (a, EMMC_PEIM_HC_PRIVATE_DATA, BlkIoPpi, EMMC_PEIM_SIG)
-#define GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2(a) CR (a, EMMC_PEIM_HC_PRIVATE_DATA, BlkIo2Ppi, EMMC_PEIM_SIG)
-#define GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY(a) CR (a, EMMC_PEIM_HC_PRIVATE_DATA, EndOfPeiNotifyList, EMMC_PEIM_SIG)
-
-struct _EMMC_TRB {
- EMMC_PEIM_HC_SLOT *Slot;
- UINT16 BlockSize;
-
- EMMC_COMMAND_PACKET *Packet;
- VOID *Data;
- UINT32 DataLen;
- BOOLEAN Read;
- EFI_PHYSICAL_ADDRESS DataPhy;
- VOID *DataMap;
- EMMC_HC_TRANSFER_MODE Mode;
-
- UINT64 Timeout;
-
- EMMC_HC_ADMA_DESC_LINE *AdmaDesc;
- UINTN AdmaDescSize;
-};
-
-/**
- Gets the count of block I/O devices that one specific block driver detects.
-
- This function is used for getting the count of block I/O devices that one
- specific block driver detects. To the PEI ATAPI driver, it returns the number
- of all the detected ATAPI devices it detects during the enumeration process.
- To the PEI legacy floppy driver, it returns the number of all the legacy
- devices it finds during its enumeration process. If no device is detected,
- then the function will return zero.
-
- @param[in] PeiServices General-purpose services that are available
- to every PEIM.
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
- instance.
- @param[out] NumberBlockDevices The number of block I/O devices discovered.
-
- @retval EFI_SUCCESS The operation performed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcBlockIoPeimGetDeviceNo (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
- OUT UINTN *NumberBlockDevices
- );
-
-/**
- Gets a block device's media information.
-
- This function will provide the caller with the specified block device's media
- information. If the media changes, calling this function will update the media
- information accordingly.
-
- @param[in] PeiServices General-purpose services that are available to every
- PEIM
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
- @param[in] DeviceIndex Specifies the block device to which the function wants
- to talk. Because the driver that implements Block I/O
- PPIs will manage multiple block devices, the PPIs that
- want to talk to a single device must specify the
- device index that was assigned during the enumeration
- process. This index is a number from one to
- NumberBlockDevices.
- @param[out] MediaInfo The media information of the specified block media.
- The caller is responsible for the ownership of this
- data structure.
-
- @par Note:
- The MediaInfo structure describes an enumeration of possible block device
- types. This enumeration exists because no device paths are actually passed
- across interfaces that describe the type or class of hardware that is publishing
- the block I/O interface. This enumeration will allow for policy decisions
- in the Recovery PEIM, such as "Try to recover from legacy floppy first,
- LS-120 second, CD-ROM third." If there are multiple partitions abstracted
- by a given device type, they should be reported in ascending order; this
- order also applies to nested partitions, such as legacy MBR, where the
- outermost partitions would have precedence in the reporting order. The
- same logic applies to systems such as IDE that have precedence relationships
- like "Master/Slave" or "Primary/Secondary". The master device should be
- reported first, the slave second.
-
- @retval EFI_SUCCESS Media information about the specified block device
- was obtained successfully.
- @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
- error.
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcBlockIoPeimGetMediaInfo (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
- IN UINTN DeviceIndex,
- OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
- );
-
-/**
- Reads the requested number of blocks from the specified block device.
-
- The function reads the requested number of blocks from the device. All the
- blocks are read, or an error is returned. If there is no media in the device,
- the function returns EFI_NO_MEDIA.
-
- @param[in] PeiServices General-purpose services that are available to
- every PEIM.
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
- @param[in] DeviceIndex Specifies the block device to which the function wants
- to talk. Because the driver that implements Block I/O
- PPIs will manage multiple block devices, PPIs that
- want to talk to a single device must specify the device
- index that was assigned during the enumeration process.
- This index is a number from one to NumberBlockDevices.
- @param[in] StartLBA The starting logical block address (LBA) to read from
- on the device
- @param[in] BufferSize The size of the Buffer in bytes. This number must be
- a multiple of the intrinsic block size of the device.
- @param[out] Buffer A pointer to the destination buffer for the data.
- The caller is responsible for the 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 attempting
- to perform the read operation.
- @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
- valid, or the buffer is not properly aligned.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
- the intrinsic block size of the device.
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcBlockIoPeimReadBlocks (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
- IN UINTN DeviceIndex,
- IN EFI_PEI_LBA StartLBA,
- IN UINTN BufferSize,
- OUT VOID *Buffer
- );
-
-/**
- Gets the count of block I/O devices that one specific block driver detects.
-
- This function is used for getting the count of block I/O devices that one
- specific block driver detects. To the PEI ATAPI driver, it returns the number
- of all the detected ATAPI devices it detects during the enumeration process.
- To the PEI legacy floppy driver, it returns the number of all the legacy
- devices it finds during its enumeration process. If no device is detected,
- then the function will return zero.
-
- @param[in] PeiServices General-purpose services that are available
- to every PEIM.
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
- instance.
- @param[out] NumberBlockDevices The number of block I/O devices discovered.
-
- @retval EFI_SUCCESS The operation performed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcBlockIoPeimGetDeviceNo2 (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
- OUT UINTN *NumberBlockDevices
- );
-
-/**
- Gets a block device's media information.
-
- This function will provide the caller with the specified block device's media
- information. If the media changes, calling this function will update the media
- information accordingly.
-
- @param[in] PeiServices General-purpose services that are available to every
- PEIM
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
- @param[in] DeviceIndex Specifies the block device to which the function wants
- to talk. Because the driver that implements Block I/O
- PPIs will manage multiple block devices, the PPIs that
- want to talk to a single device must specify the
- device index that was assigned during the enumeration
- process. This index is a number from one to
- NumberBlockDevices.
- @param[out] MediaInfo The media information of the specified block media.
- The caller is responsible for the ownership of this
- data structure.
-
- @par Note:
- The MediaInfo structure describes an enumeration of possible block device
- types. This enumeration exists because no device paths are actually passed
- across interfaces that describe the type or class of hardware that is publishing
- the block I/O interface. This enumeration will allow for policy decisions
- in the Recovery PEIM, such as "Try to recover from legacy floppy first,
- LS-120 second, CD-ROM third." If there are multiple partitions abstracted
- by a given device type, they should be reported in ascending order; this
- order also applies to nested partitions, such as legacy MBR, where the
- outermost partitions would have precedence in the reporting order. The
- same logic applies to systems such as IDE that have precedence relationships
- like "Master/Slave" or "Primary/Secondary". The master device should be
- reported first, the slave second.
-
- @retval EFI_SUCCESS Media information about the specified block device
- was obtained successfully.
- @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
- error.
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcBlockIoPeimGetMediaInfo2 (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
- IN UINTN DeviceIndex,
- OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
- );
-
-/**
- Reads the requested number of blocks from the specified block device.
-
- The function reads the requested number of blocks from the device. All the
- blocks are read, or an error is returned. If there is no media in the device,
- the function returns EFI_NO_MEDIA.
-
- @param[in] PeiServices General-purpose services that are available to
- every PEIM.
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
- @param[in] DeviceIndex Specifies the block device to which the function wants
- to talk. Because the driver that implements Block I/O
- PPIs will manage multiple block devices, PPIs that
- want to talk to a single device must specify the device
- index that was assigned during the enumeration process.
- This index is a number from one to NumberBlockDevices.
- @param[in] StartLBA The starting logical block address (LBA) to read from
- on the device
- @param[in] BufferSize The size of the Buffer in bytes. This number must be
- a multiple of the intrinsic block size of the device.
- @param[out] Buffer A pointer to the destination buffer for the data.
- The caller is responsible for the 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 attempting
- to perform the read operation.
- @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
- valid, or the buffer is not properly aligned.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
- the intrinsic block size of the device.
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcBlockIoPeimReadBlocks2 (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
- IN UINTN DeviceIndex,
- IN EFI_PEI_LBA StartLBA,
- IN UINTN BufferSize,
- OUT VOID *Buffer
- );
-
-/**
- Initialize the memory management pool for the host controller.
-
- @param Private The Emmc Peim driver private data.
-
- @retval EFI_SUCCESS The memory pool is initialized.
- @retval Others Fail to init the memory pool.
-
-**/
-EFI_STATUS
-EmmcPeimInitMemPool (
- IN EMMC_PEIM_HC_PRIVATE_DATA *Private
- );
-
-/**
- Release the memory management pool.
-
- @param Pool The memory pool to free.
-
- @retval EFI_DEVICE_ERROR Fail to free the memory pool.
- @retval EFI_SUCCESS The memory pool is freed.
-
-**/
-EFI_STATUS
-EmmcPeimFreeMemPool (
- IN EMMC_PEIM_MEM_POOL *Pool
- );
-
-/**
- Allocate some memory from the host controller's memory pool
- which can be used to communicate with host controller.
-
- @param Pool The host controller's memory pool.
- @param Size Size of the memory to allocate.
-
- @return The allocated memory or NULL.
-
-**/
-VOID *
-EmmcPeimAllocateMem (
- IN EMMC_PEIM_MEM_POOL *Pool,
- IN UINTN Size
- );
-
-/**
- Free the allocated memory back to the memory pool.
-
- @param Pool The memory pool of the host controller.
- @param Mem The memory to free.
- @param Size The size of the memory to free.
-
-**/
-VOID
-EmmcPeimFreeMem (
- IN EMMC_PEIM_MEM_POOL *Pool,
- IN VOID *Mem,
- IN UINTN Size
- );
-
-/**
- Initialize IOMMU.
-**/
-VOID
-IoMmuInit (
- VOID
- );
-
-/**
- Provides the controller-specific addresses required to access system memory from a
- DMA bus master.
-
- @param Operation Indicates if the bus master is going to read or write to system memory.
- @param HostAddress The system memory address to map to the PCI controller.
- @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
- that were mapped.
- @param DeviceAddress The resulting map address for the bus master PCI controller to use to
- access the hosts HostAddress.
- @param Mapping A resulting value to pass to Unmap().
-
- @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
- @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
- @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
- @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
-
-**/
-EFI_STATUS
-IoMmuMap (
- IN EDKII_IOMMU_OPERATION Operation,
- IN VOID *HostAddress,
- IN OUT UINTN *NumberOfBytes,
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
- OUT VOID **Mapping
- );
-
-/**
- Completes the Map() operation and releases any corresponding resources.
-
- @param Mapping The mapping value returned from Map().
-
- @retval EFI_SUCCESS The range was unmapped.
- @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
- @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
-**/
-EFI_STATUS
-IoMmuUnmap (
- IN VOID *Mapping
- );
-
-/**
- Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
- OperationBusMasterCommonBuffer64 mapping.
-
- @param Pages The number of pages to allocate.
- @param HostAddress A pointer to store the base system memory address of the
- allocated range.
- @param DeviceAddress The resulting map address for the bus master PCI controller to use to
- access the hosts HostAddress.
- @param Mapping A resulting value to pass to Unmap().
-
- @retval EFI_SUCCESS The requested memory pages were allocated.
- @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
- MEMORY_WRITE_COMBINE and MEMORY_CACHED.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
- @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
-
-**/
-EFI_STATUS
-IoMmuAllocateBuffer (
- IN UINTN Pages,
- OUT VOID **HostAddress,
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
- OUT VOID **Mapping
- );
-
-/**
- Frees memory that was allocated with AllocateBuffer().
-
- @param Pages The number of pages to free.
- @param HostAddress The base system memory address of the allocated range.
- @param Mapping The mapping value returned from Map().
-
- @retval EFI_SUCCESS The requested memory pages were freed.
- @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
- was not allocated with AllocateBuffer().
-
-**/
-EFI_STATUS
-IoMmuFreeBuffer (
- IN UINTN Pages,
- IN VOID *HostAddress,
- IN VOID *Mapping
- );
-
-/**
- One notified function to cleanup the allocated DMA buffers at the end of PEI.
-
- @param[in] PeiServices Pointer to PEI Services Table.
- @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
- event that caused this function to execute.
- @param[in] Ppi Pointer to the PPI data associated with this function.
-
- @retval EFI_SUCCESS The function completes successfully
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcBlockIoPeimEndOfPei (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
- IN VOID *Ppi
- );
-
-#endif
+/** @file + + Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EMMC_BLOCK_IO_PEI_H_ +#define _EMMC_BLOCK_IO_PEI_H_ + +#include <PiPei.h> + +#include <Ppi/SdMmcHostController.h> +#include <Ppi/BlockIo.h> +#include <Ppi/BlockIo2.h> +#include <Ppi/IoMmu.h> +#include <Ppi/EndOfPeiPhase.h> + +#include <Library/DebugLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/IoLib.h> +#include <Library/TimerLib.h> +#include <Library/PeiServicesLib.h> + +#include <IndustryStandard/Emmc.h> + +typedef struct _EMMC_PEIM_HC_PRIVATE_DATA EMMC_PEIM_HC_PRIVATE_DATA; +typedef struct _EMMC_PEIM_HC_SLOT EMMC_PEIM_HC_SLOT; +typedef struct _EMMC_TRB EMMC_TRB; + +#include "EmmcHci.h" +#include "EmmcHcMem.h" + +#define EMMC_PEIM_SIG SIGNATURE_32 ('E', 'M', 'C', 'P') +#define EMMC_PEIM_SLOT_SIG SIGNATURE_32 ('E', 'M', 'C', 'S') + +#define EMMC_PEIM_MAX_SLOTS 6 +#define EMMC_PEIM_MAX_PARTITIONS 8 + +struct _EMMC_PEIM_HC_SLOT { + UINT32 Signature; + EFI_PEI_BLOCK_IO2_MEDIA Media[EMMC_PEIM_MAX_PARTITIONS]; + UINT8 MediaNum; + EMMC_PARTITION_TYPE PartitionType[EMMC_PEIM_MAX_PARTITIONS]; + + UINTN EmmcHcBase; + EMMC_HC_SLOT_CAP Capability; + EMMC_CSD Csd; + EMMC_EXT_CSD ExtCsd; + BOOLEAN SectorAddressing; + EMMC_PEIM_HC_PRIVATE_DATA *Private; +}; + +struct _EMMC_PEIM_HC_PRIVATE_DATA { + UINT32 Signature; + EMMC_PEIM_MEM_POOL *Pool; + EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi; + EFI_PEI_RECOVERY_BLOCK_IO2_PPI BlkIo2Ppi; + EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList; + EFI_PEI_PPI_DESCRIPTOR BlkIo2PpiList; + + // + // EndOfPei callback is used to do the cleanups before exit of PEI phase. + // + EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList; + + EMMC_PEIM_HC_SLOT Slot[EMMC_PEIM_MAX_SLOTS]; + UINT8 SlotNum; + UINT8 TotalBlkIoDevices; +}; + +#define EMMC_TIMEOUT MultU64x32((UINT64)(3), 1000000) +#define GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS(a) CR (a, EMMC_PEIM_HC_PRIVATE_DATA, BlkIoPpi, EMMC_PEIM_SIG) +#define GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2(a) CR (a, EMMC_PEIM_HC_PRIVATE_DATA, BlkIo2Ppi, EMMC_PEIM_SIG) +#define GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY(a) CR (a, EMMC_PEIM_HC_PRIVATE_DATA, EndOfPeiNotifyList, EMMC_PEIM_SIG) + +struct _EMMC_TRB { + EMMC_PEIM_HC_SLOT *Slot; + UINT16 BlockSize; + + EMMC_COMMAND_PACKET *Packet; + VOID *Data; + UINT32 DataLen; + BOOLEAN Read; + EFI_PHYSICAL_ADDRESS DataPhy; + VOID *DataMap; + EMMC_HC_TRANSFER_MODE Mode; + + UINT64 Timeout; + + EMMC_HC_ADMA_DESC_LINE *AdmaDesc; + UINTN AdmaDescSize; +}; + +/** + Gets the count of block I/O devices that one specific block driver detects. + + This function is used for getting the count of block I/O devices that one + specific block driver detects. To the PEI ATAPI driver, it returns the number + of all the detected ATAPI devices it detects during the enumeration process. + To the PEI legacy floppy driver, it returns the number of all the legacy + devices it finds during its enumeration process. If no device is detected, + then the function will return zero. + + @param[in] PeiServices General-purpose services that are available + to every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI + instance. + @param[out] NumberBlockDevices The number of block I/O devices discovered. + + @retval EFI_SUCCESS The operation performed successfully. + +**/ +EFI_STATUS +EFIAPI +EmmcBlockIoPeimGetDeviceNo ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + OUT UINTN *NumberBlockDevices + ); + +/** + Gets a block device's media information. + + This function will provide the caller with the specified block device's media + information. If the media changes, calling this function will update the media + information accordingly. + + @param[in] PeiServices General-purpose services that are available to every + PEIM + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, the PPIs that + want to talk to a single device must specify the + device index that was assigned during the enumeration + process. This index is a number from one to + NumberBlockDevices. + @param[out] MediaInfo The media information of the specified block media. + The caller is responsible for the ownership of this + data structure. + + @par Note: + The MediaInfo structure describes an enumeration of possible block device + types. This enumeration exists because no device paths are actually passed + across interfaces that describe the type or class of hardware that is publishing + the block I/O interface. This enumeration will allow for policy decisions + in the Recovery PEIM, such as "Try to recover from legacy floppy first, + LS-120 second, CD-ROM third." If there are multiple partitions abstracted + by a given device type, they should be reported in ascending order; this + order also applies to nested partitions, such as legacy MBR, where the + outermost partitions would have precedence in the reporting order. The + same logic applies to systems such as IDE that have precedence relationships + like "Master/Slave" or "Primary/Secondary". The master device should be + reported first, the slave second. + + @retval EFI_SUCCESS Media information about the specified block device + was obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware + error. + +**/ +EFI_STATUS +EFIAPI +EmmcBlockIoPeimGetMediaInfo ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + IN UINTN DeviceIndex, + OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo + ); + +/** + Reads the requested number of blocks from the specified block device. + + The function reads the requested number of blocks from the device. All the + blocks are read, or an error is returned. If there is no media in the device, + the function returns EFI_NO_MEDIA. + + @param[in] PeiServices General-purpose services that are available to + every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, PPIs that + want to talk to a single device must specify the device + index that was assigned during the enumeration process. + This index is a number from one to NumberBlockDevices. + @param[in] StartLBA The starting logical block address (LBA) to read from + on the device + @param[in] BufferSize The size of the Buffer in bytes. This number must be + a multiple of the intrinsic block size of the device. + @param[out] Buffer A pointer to the destination buffer for the data. + The caller is responsible for the 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 attempting + to perform the read operation. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not + valid, or the buffer is not properly aligned. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of + the intrinsic block size of the device. + +**/ +EFI_STATUS +EFIAPI +EmmcBlockIoPeimReadBlocks ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + IN UINTN DeviceIndex, + IN EFI_PEI_LBA StartLBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +/** + Gets the count of block I/O devices that one specific block driver detects. + + This function is used for getting the count of block I/O devices that one + specific block driver detects. To the PEI ATAPI driver, it returns the number + of all the detected ATAPI devices it detects during the enumeration process. + To the PEI legacy floppy driver, it returns the number of all the legacy + devices it finds during its enumeration process. If no device is detected, + then the function will return zero. + + @param[in] PeiServices General-purpose services that are available + to every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI + instance. + @param[out] NumberBlockDevices The number of block I/O devices discovered. + + @retval EFI_SUCCESS The operation performed successfully. + +**/ +EFI_STATUS +EFIAPI +EmmcBlockIoPeimGetDeviceNo2 ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, + OUT UINTN *NumberBlockDevices + ); + +/** + Gets a block device's media information. + + This function will provide the caller with the specified block device's media + information. If the media changes, calling this function will update the media + information accordingly. + + @param[in] PeiServices General-purpose services that are available to every + PEIM + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, the PPIs that + want to talk to a single device must specify the + device index that was assigned during the enumeration + process. This index is a number from one to + NumberBlockDevices. + @param[out] MediaInfo The media information of the specified block media. + The caller is responsible for the ownership of this + data structure. + + @par Note: + The MediaInfo structure describes an enumeration of possible block device + types. This enumeration exists because no device paths are actually passed + across interfaces that describe the type or class of hardware that is publishing + the block I/O interface. This enumeration will allow for policy decisions + in the Recovery PEIM, such as "Try to recover from legacy floppy first, + LS-120 second, CD-ROM third." If there are multiple partitions abstracted + by a given device type, they should be reported in ascending order; this + order also applies to nested partitions, such as legacy MBR, where the + outermost partitions would have precedence in the reporting order. The + same logic applies to systems such as IDE that have precedence relationships + like "Master/Slave" or "Primary/Secondary". The master device should be + reported first, the slave second. + + @retval EFI_SUCCESS Media information about the specified block device + was obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware + error. + +**/ +EFI_STATUS +EFIAPI +EmmcBlockIoPeimGetMediaInfo2 ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, + IN UINTN DeviceIndex, + OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo + ); + +/** + Reads the requested number of blocks from the specified block device. + + The function reads the requested number of blocks from the device. All the + blocks are read, or an error is returned. If there is no media in the device, + the function returns EFI_NO_MEDIA. + + @param[in] PeiServices General-purpose services that are available to + every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, PPIs that + want to talk to a single device must specify the device + index that was assigned during the enumeration process. + This index is a number from one to NumberBlockDevices. + @param[in] StartLBA The starting logical block address (LBA) to read from + on the device + @param[in] BufferSize The size of the Buffer in bytes. This number must be + a multiple of the intrinsic block size of the device. + @param[out] Buffer A pointer to the destination buffer for the data. + The caller is responsible for the 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 attempting + to perform the read operation. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not + valid, or the buffer is not properly aligned. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of + the intrinsic block size of the device. + +**/ +EFI_STATUS +EFIAPI +EmmcBlockIoPeimReadBlocks2 ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, + IN UINTN DeviceIndex, + IN EFI_PEI_LBA StartLBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +/** + Initialize the memory management pool for the host controller. + + @param Private The Emmc Peim driver private data. + + @retval EFI_SUCCESS The memory pool is initialized. + @retval Others Fail to init the memory pool. + +**/ +EFI_STATUS +EmmcPeimInitMemPool ( + IN EMMC_PEIM_HC_PRIVATE_DATA *Private + ); + +/** + Release the memory management pool. + + @param Pool The memory pool to free. + + @retval EFI_DEVICE_ERROR Fail to free the memory pool. + @retval EFI_SUCCESS The memory pool is freed. + +**/ +EFI_STATUS +EmmcPeimFreeMemPool ( + IN EMMC_PEIM_MEM_POOL *Pool + ); + +/** + Allocate some memory from the host controller's memory pool + which can be used to communicate with host controller. + + @param Pool The host controller's memory pool. + @param Size Size of the memory to allocate. + + @return The allocated memory or NULL. + +**/ +VOID * +EmmcPeimAllocateMem ( + IN EMMC_PEIM_MEM_POOL *Pool, + IN UINTN Size + ); + +/** + Free the allocated memory back to the memory pool. + + @param Pool The memory pool of the host controller. + @param Mem The memory to free. + @param Size The size of the memory to free. + +**/ +VOID +EmmcPeimFreeMem ( + IN EMMC_PEIM_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ); + +/** + Initialize IOMMU. +**/ +VOID +IoMmuInit ( + VOID + ); + +/** + Provides the controller-specific addresses required to access system memory from a + DMA bus master. + + @param Operation Indicates if the bus master is going to read or write to system memory. + @param HostAddress The system memory address to map to the PCI controller. + @param NumberOfBytes On input the number of bytes to map. On output the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + +**/ +EFI_STATUS +IoMmuMap ( + IN EDKII_IOMMU_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +/** + Completes the Map() operation and releases any corresponding resources. + + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map(). + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. +**/ +EFI_STATUS +IoMmuUnmap ( + IN VOID *Mapping + ); + +/** + Allocates pages that are suitable for an OperationBusMasterCommonBuffer or + OperationBusMasterCommonBuffer64 mapping. + + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +IoMmuAllocateBuffer ( + IN UINTN Pages, + OUT VOID **HostAddress, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +/** + Frees memory that was allocated with AllocateBuffer(). + + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages + was not allocated with AllocateBuffer(). + +**/ +EFI_STATUS +IoMmuFreeBuffer ( + IN UINTN Pages, + IN VOID *HostAddress, + IN VOID *Mapping + ); + +/** + One notified function to cleanup the allocated DMA buffers at the end of PEI. + + @param[in] PeiServices Pointer to PEI Services Table. + @param[in] NotifyDescriptor Pointer to the descriptor for the Notification + event that caused this function to execute. + @param[in] Ppi Pointer to the PPI data associated with this function. + + @retval EFI_SUCCESS The function completes successfully + +**/ +EFI_STATUS +EFIAPI +EmmcBlockIoPeimEndOfPei ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +#endif diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.inf b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.inf index 8ab632eb35..de5280178c 100644 --- a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.inf +++ b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.inf @@ -1,60 +1,60 @@ -## @file
-# Description file for the Embedded MMC (eMMC) Peim driver.
-#
-# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = EmmcBlockIoPei
- MODULE_UNI_FILE = EmmcBlockIoPei.uni
- FILE_GUID = 7F06A90F-AE0D-4887-82C0-FEC7F4F68B29
- MODULE_TYPE = PEIM
- VERSION_STRING = 1.0
-
- ENTRY_POINT = InitializeEmmcBlockIoPeim
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64 EBC
-#
-
-[Sources]
- EmmcBlockIoPei.c
- EmmcBlockIoPei.h
- EmmcHci.c
- EmmcHci.h
- EmmcHcMem.c
- EmmcHcMem.h
- DmaMem.c
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
-
-[LibraryClasses]
- IoLib
- TimerLib
- BaseMemoryLib
- PeimEntryPoint
- PeiServicesLib
- DebugLib
-
-[Ppis]
- gEfiPeiVirtualBlockIoPpiGuid ## PRODUCES
- gEfiPeiVirtualBlockIo2PpiGuid ## PRODUCES
- gEdkiiPeiSdMmcHostControllerPpiGuid ## CONSUMES
- gEdkiiIoMmuPpiGuid ## CONSUMES
- gEfiEndOfPeiSignalPpiGuid ## CONSUMES
-
-[Depex]
- gEfiPeiMemoryDiscoveredPpiGuid AND gEdkiiPeiSdMmcHostControllerPpiGuid
-
-[UserExtensions.TianoCore."ExtraFiles"]
- EmmcBlockIoPeiExtra.uni
-
+## @file +# Description file for the Embedded MMC (eMMC) Peim driver. +# +# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = EmmcBlockIoPei + MODULE_UNI_FILE = EmmcBlockIoPei.uni + FILE_GUID = 7F06A90F-AE0D-4887-82C0-FEC7F4F68B29 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeEmmcBlockIoPeim + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + EmmcBlockIoPei.c + EmmcBlockIoPei.h + EmmcHci.c + EmmcHci.h + EmmcHcMem.c + EmmcHcMem.h + DmaMem.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + IoLib + TimerLib + BaseMemoryLib + PeimEntryPoint + PeiServicesLib + DebugLib + +[Ppis] + gEfiPeiVirtualBlockIoPpiGuid ## PRODUCES + gEfiPeiVirtualBlockIo2PpiGuid ## PRODUCES + gEdkiiPeiSdMmcHostControllerPpiGuid ## CONSUMES + gEdkiiIoMmuPpiGuid ## CONSUMES + gEfiEndOfPeiSignalPpiGuid ## CONSUMES + +[Depex] + gEfiPeiMemoryDiscoveredPpiGuid AND gEdkiiPeiSdMmcHostControllerPpiGuid + +[UserExtensions.TianoCore."ExtraFiles"] + EmmcBlockIoPeiExtra.uni + diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.uni b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.uni index 8c4c79c1ac..81c67ae0a0 100644 --- a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.uni +++ b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.uni @@ -1,14 +1,14 @@ -// /** @file
-// The EmmcBlockIoPei driver is used to support recovery from EMMC device.
-//
-// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Support recovery from EMMC devices"
-
-#string STR_MODULE_DESCRIPTION #language en-US "The EmmcBlockIoPei driver is used to support recovery from EMMC device."
-
+// /** @file +// The EmmcBlockIoPei driver is used to support recovery from EMMC device. +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Support recovery from EMMC devices" + +#string STR_MODULE_DESCRIPTION #language en-US "The EmmcBlockIoPei driver is used to support recovery from EMMC device." + diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPeiExtra.uni b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPeiExtra.uni index feeb1b34fe..1d680e9791 100644 --- a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPeiExtra.uni +++ b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPeiExtra.uni @@ -1,14 +1,14 @@ -// /** @file
-// EmmcBlockIoPei 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 BlockIo Peim for Recovery"
-
-
+// /** @file +// EmmcBlockIoPei 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 BlockIo Peim for Recovery" + + diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.c b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.c index 6778254b61..0ed533a76d 100644 --- a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.c +++ b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.c @@ -1,425 +1,425 @@ -/** @file
-
-Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
-
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "EmmcBlockIoPei.h"
-
-/**
- Allocate a block of memory to be used by the buffer pool.
-
- @param Pages How many pages to allocate.
-
- @return The allocated memory block or NULL if failed.
-
-**/
-EMMC_PEIM_MEM_BLOCK *
-EmmcPeimAllocMemBlock (
- IN UINTN Pages
- )
-{
- EMMC_PEIM_MEM_BLOCK *Block;
- VOID *BufHost;
- VOID *Mapping;
- EFI_PHYSICAL_ADDRESS MappedAddr;
- EFI_STATUS Status;
- VOID *TempPtr;
-
- TempPtr = NULL;
- Block = NULL;
-
- Status = PeiServicesAllocatePool (sizeof (EMMC_PEIM_MEM_BLOCK), &TempPtr);
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- ZeroMem ((VOID *)(UINTN)TempPtr, sizeof (EMMC_PEIM_MEM_BLOCK));
-
- //
- // each bit in the bit array represents EMMC_PEIM_MEM_UNIT
- // bytes of memory in the memory block.
- //
- ASSERT (EMMC_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
-
- Block = (EMMC_PEIM_MEM_BLOCK *)(UINTN)TempPtr;
- Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
- Block->BitsLen = Block->BufLen / (EMMC_PEIM_MEM_UNIT * 8);
-
- Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr);
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- ZeroMem ((VOID *)(UINTN)TempPtr, Block->BitsLen);
-
- Block->Bits = (UINT8 *)(UINTN)TempPtr;
-
- Status = IoMmuAllocateBuffer (
- Pages,
- &BufHost,
- &MappedAddr,
- &Mapping
- );
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- ZeroMem ((VOID *)(UINTN)BufHost, EFI_PAGES_TO_SIZE (Pages));
-
- Block->BufHost = (UINT8 *)(UINTN)BufHost;
- Block->Buf = (UINT8 *)(UINTN)MappedAddr;
- Block->Mapping = Mapping;
- Block->Next = NULL;
-
- return Block;
-}
-
-/**
- Free the memory block from the memory pool.
-
- @param Pool The memory pool to free the block from.
- @param Block The memory block to free.
-
-**/
-VOID
-EmmcPeimFreeMemBlock (
- IN EMMC_PEIM_MEM_POOL *Pool,
- IN EMMC_PEIM_MEM_BLOCK *Block
- )
-{
- ASSERT ((Pool != NULL) && (Block != NULL));
-
- IoMmuFreeBuffer (EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost, Block->Mapping);
-}
-
-/**
- Alloc some memory from the block.
-
- @param Block The memory block to allocate memory from.
- @param Units Number of memory units to allocate.
-
- @return The pointer to the allocated memory. If couldn't allocate the needed memory,
- the return value is NULL.
-
-**/
-VOID *
-EmmcPeimAllocMemFromBlock (
- IN EMMC_PEIM_MEM_BLOCK *Block,
- IN UINTN Units
- )
-{
- UINTN Byte;
- UINT8 Bit;
- UINTN StartByte;
- UINT8 StartBit;
- UINTN Available;
- UINTN Count;
-
- ASSERT ((Block != 0) && (Units != 0));
-
- StartByte = 0;
- StartBit = 0;
- Available = 0;
-
- for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
- //
- // If current bit is zero, the corresponding memory unit is
- // available, otherwise we need to restart our searching.
- // Available counts the consecutive number of zero bit.
- //
- if (!EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)) {
- Available++;
-
- if (Available >= Units) {
- break;
- }
-
- EMMC_PEIM_NEXT_BIT (Byte, Bit);
- } else {
- EMMC_PEIM_NEXT_BIT (Byte, Bit);
-
- Available = 0;
- StartByte = Byte;
- StartBit = Bit;
- }
- }
-
- if (Available < Units) {
- return NULL;
- }
-
- //
- // Mark the memory as allocated
- //
- Byte = StartByte;
- Bit = StartBit;
-
- for (Count = 0; Count < Units; Count++) {
- ASSERT (!EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));
-
- Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] | (UINT8)EMMC_PEIM_MEM_BIT (Bit));
- EMMC_PEIM_NEXT_BIT (Byte, Bit);
- }
-
- return Block->Buf + (StartByte * 8 + StartBit) * EMMC_PEIM_MEM_UNIT;
-}
-
-/**
- Insert the memory block to the pool's list of the blocks.
-
- @param Head The head of the memory pool's block list.
- @param Block The memory block to insert.
-
-**/
-VOID
-EmmcPeimInsertMemBlockToPool (
- IN EMMC_PEIM_MEM_BLOCK *Head,
- IN EMMC_PEIM_MEM_BLOCK *Block
- )
-{
- ASSERT ((Head != NULL) && (Block != NULL));
- Block->Next = Head->Next;
- Head->Next = Block;
-}
-
-/**
- Is the memory block empty?
-
- @param Block The memory block to check.
-
- @retval TRUE The memory block is empty.
- @retval FALSE The memory block isn't empty.
-
-**/
-BOOLEAN
-EmmcPeimIsMemBlockEmpty (
- IN EMMC_PEIM_MEM_BLOCK *Block
- )
-{
- UINTN Index;
-
- for (Index = 0; Index < Block->BitsLen; Index++) {
- if (Block->Bits[Index] != 0) {
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-/**
- Initialize the memory management pool for the host controller.
-
- @param Private The Emmc Peim driver private data.
-
- @retval EFI_SUCCESS The memory pool is initialized.
- @retval Others Fail to init the memory pool.
-
-**/
-EFI_STATUS
-EmmcPeimInitMemPool (
- IN EMMC_PEIM_HC_PRIVATE_DATA *Private
- )
-{
- EMMC_PEIM_MEM_POOL *Pool;
- EFI_STATUS Status;
- VOID *TempPtr;
-
- TempPtr = NULL;
- Pool = NULL;
-
- Status = PeiServicesAllocatePool (sizeof (EMMC_PEIM_MEM_POOL), &TempPtr);
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- ZeroMem ((VOID *)(UINTN)TempPtr, sizeof (EMMC_PEIM_MEM_POOL));
-
- Pool = (EMMC_PEIM_MEM_POOL *)((UINTN)TempPtr);
-
- Pool->Head = EmmcPeimAllocMemBlock (EMMC_PEIM_MEM_DEFAULT_PAGES);
-
- if (Pool->Head == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Private->Pool = Pool;
- return EFI_SUCCESS;
-}
-
-/**
- Release the memory management pool.
-
- @param Pool The memory pool to free.
-
- @retval EFI_DEVICE_ERROR Fail to free the memory pool.
- @retval EFI_SUCCESS The memory pool is freed.
-
-**/
-EFI_STATUS
-EmmcPeimFreeMemPool (
- IN EMMC_PEIM_MEM_POOL *Pool
- )
-{
- EMMC_PEIM_MEM_BLOCK *Block;
-
- ASSERT (Pool->Head != NULL);
-
- //
- // Unlink all the memory blocks from the pool, then free them.
- //
- for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
- EmmcPeimFreeMemBlock (Pool, Block);
- }
-
- EmmcPeimFreeMemBlock (Pool, Pool->Head);
-
- return EFI_SUCCESS;
-}
-
-/**
- Allocate some memory from the host controller's memory pool
- which can be used to communicate with host controller.
-
- @param Pool The host controller's memory pool.
- @param Size Size of the memory to allocate.
-
- @return The allocated memory or NULL.
-
-**/
-VOID *
-EmmcPeimAllocateMem (
- IN EMMC_PEIM_MEM_POOL *Pool,
- IN UINTN Size
- )
-{
- EMMC_PEIM_MEM_BLOCK *Head;
- EMMC_PEIM_MEM_BLOCK *Block;
- EMMC_PEIM_MEM_BLOCK *NewBlock;
- VOID *Mem;
- UINTN AllocSize;
- UINTN Pages;
-
- Mem = NULL;
- AllocSize = EMMC_PEIM_MEM_ROUND (Size);
- Head = Pool->Head;
- ASSERT (Head != NULL);
-
- //
- // First check whether current memory blocks can satisfy the allocation.
- //
- for (Block = Head; Block != NULL; Block = Block->Next) {
- Mem = EmmcPeimAllocMemFromBlock (Block, AllocSize / EMMC_PEIM_MEM_UNIT);
-
- if (Mem != NULL) {
- ZeroMem (Mem, Size);
- break;
- }
- }
-
- if (Mem != NULL) {
- return Mem;
- }
-
- //
- // Create a new memory block if there is not enough memory
- // in the pool. If the allocation size is larger than the
- // default page number, just allocate a large enough memory
- // block. Otherwise allocate default pages.
- //
- if (AllocSize > EFI_PAGES_TO_SIZE (EMMC_PEIM_MEM_DEFAULT_PAGES)) {
- Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
- } else {
- Pages = EMMC_PEIM_MEM_DEFAULT_PAGES;
- }
-
- NewBlock = EmmcPeimAllocMemBlock (Pages);
- if (NewBlock == NULL) {
- return NULL;
- }
-
- //
- // Add the new memory block to the pool, then allocate memory from it
- //
- EmmcPeimInsertMemBlockToPool (Head, NewBlock);
- Mem = EmmcPeimAllocMemFromBlock (NewBlock, AllocSize / EMMC_PEIM_MEM_UNIT);
-
- if (Mem != NULL) {
- ZeroMem (Mem, Size);
- }
-
- return Mem;
-}
-
-/**
- Free the allocated memory back to the memory pool.
-
- @param Pool The memory pool of the host controller.
- @param Mem The memory to free.
- @param Size The size of the memory to free.
-
-**/
-VOID
-EmmcPeimFreeMem (
- IN EMMC_PEIM_MEM_POOL *Pool,
- IN VOID *Mem,
- IN UINTN Size
- )
-{
- EMMC_PEIM_MEM_BLOCK *Head;
- EMMC_PEIM_MEM_BLOCK *Block;
- UINT8 *ToFree;
- UINTN AllocSize;
- UINTN Byte;
- UINTN Bit;
- UINTN Count;
-
- Head = Pool->Head;
- AllocSize = EMMC_PEIM_MEM_ROUND (Size);
- ToFree = (UINT8 *)Mem;
-
- for (Block = Head; Block != NULL; Block = Block->Next) {
- //
- // scan the memory block list for the memory block that
- // completely contains the memory to free.
- //
- if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {
- //
- // compute the start byte and bit in the bit array
- //
- Byte = ((ToFree - Block->Buf) / EMMC_PEIM_MEM_UNIT) / 8;
- Bit = ((ToFree - Block->Buf) / EMMC_PEIM_MEM_UNIT) % 8;
-
- //
- // reset associated bits in bit array
- //
- for (Count = 0; Count < (AllocSize / EMMC_PEIM_MEM_UNIT); Count++) {
- ASSERT (EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));
-
- Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] ^ EMMC_PEIM_MEM_BIT (Bit));
- EMMC_PEIM_NEXT_BIT (Byte, Bit);
- }
-
- break;
- }
- }
-
- //
- // If Block == NULL, it means that the current memory isn't
- // in the host controller's pool. This is critical because
- // the caller has passed in a wrong memory point
- //
- ASSERT (Block != NULL);
-
- //
- // Release the current memory block if it is empty and not the head
- //
- if ((Block != Head) && EmmcPeimIsMemBlockEmpty (Block)) {
- EmmcPeimFreeMemBlock (Pool, Block);
- }
-
- return;
-}
+/** @file + +Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "EmmcBlockIoPei.h" + +/** + Allocate a block of memory to be used by the buffer pool. + + @param Pages How many pages to allocate. + + @return The allocated memory block or NULL if failed. + +**/ +EMMC_PEIM_MEM_BLOCK * +EmmcPeimAllocMemBlock ( + IN UINTN Pages + ) +{ + EMMC_PEIM_MEM_BLOCK *Block; + VOID *BufHost; + VOID *Mapping; + EFI_PHYSICAL_ADDRESS MappedAddr; + EFI_STATUS Status; + VOID *TempPtr; + + TempPtr = NULL; + Block = NULL; + + Status = PeiServicesAllocatePool (sizeof (EMMC_PEIM_MEM_BLOCK), &TempPtr); + if (EFI_ERROR (Status)) { + return NULL; + } + + ZeroMem ((VOID *)(UINTN)TempPtr, sizeof (EMMC_PEIM_MEM_BLOCK)); + + // + // each bit in the bit array represents EMMC_PEIM_MEM_UNIT + // bytes of memory in the memory block. + // + ASSERT (EMMC_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE); + + Block = (EMMC_PEIM_MEM_BLOCK *)(UINTN)TempPtr; + Block->BufLen = EFI_PAGES_TO_SIZE (Pages); + Block->BitsLen = Block->BufLen / (EMMC_PEIM_MEM_UNIT * 8); + + Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr); + if (EFI_ERROR (Status)) { + return NULL; + } + + ZeroMem ((VOID *)(UINTN)TempPtr, Block->BitsLen); + + Block->Bits = (UINT8 *)(UINTN)TempPtr; + + Status = IoMmuAllocateBuffer ( + Pages, + &BufHost, + &MappedAddr, + &Mapping + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + ZeroMem ((VOID *)(UINTN)BufHost, EFI_PAGES_TO_SIZE (Pages)); + + Block->BufHost = (UINT8 *)(UINTN)BufHost; + Block->Buf = (UINT8 *)(UINTN)MappedAddr; + Block->Mapping = Mapping; + Block->Next = NULL; + + return Block; +} + +/** + Free the memory block from the memory pool. + + @param Pool The memory pool to free the block from. + @param Block The memory block to free. + +**/ +VOID +EmmcPeimFreeMemBlock ( + IN EMMC_PEIM_MEM_POOL *Pool, + IN EMMC_PEIM_MEM_BLOCK *Block + ) +{ + ASSERT ((Pool != NULL) && (Block != NULL)); + + IoMmuFreeBuffer (EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost, Block->Mapping); +} + +/** + Alloc some memory from the block. + + @param Block The memory block to allocate memory from. + @param Units Number of memory units to allocate. + + @return The pointer to the allocated memory. If couldn't allocate the needed memory, + the return value is NULL. + +**/ +VOID * +EmmcPeimAllocMemFromBlock ( + IN EMMC_PEIM_MEM_BLOCK *Block, + IN UINTN Units + ) +{ + UINTN Byte; + UINT8 Bit; + UINTN StartByte; + UINT8 StartBit; + UINTN Available; + UINTN Count; + + ASSERT ((Block != 0) && (Units != 0)); + + StartByte = 0; + StartBit = 0; + Available = 0; + + for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) { + // + // If current bit is zero, the corresponding memory unit is + // available, otherwise we need to restart our searching. + // Available counts the consecutive number of zero bit. + // + if (!EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)) { + Available++; + + if (Available >= Units) { + break; + } + + EMMC_PEIM_NEXT_BIT (Byte, Bit); + } else { + EMMC_PEIM_NEXT_BIT (Byte, Bit); + + Available = 0; + StartByte = Byte; + StartBit = Bit; + } + } + + if (Available < Units) { + return NULL; + } + + // + // Mark the memory as allocated + // + Byte = StartByte; + Bit = StartBit; + + for (Count = 0; Count < Units; Count++) { + ASSERT (!EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)); + + Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] | (UINT8)EMMC_PEIM_MEM_BIT (Bit)); + EMMC_PEIM_NEXT_BIT (Byte, Bit); + } + + return Block->Buf + (StartByte * 8 + StartBit) * EMMC_PEIM_MEM_UNIT; +} + +/** + Insert the memory block to the pool's list of the blocks. + + @param Head The head of the memory pool's block list. + @param Block The memory block to insert. + +**/ +VOID +EmmcPeimInsertMemBlockToPool ( + IN EMMC_PEIM_MEM_BLOCK *Head, + IN EMMC_PEIM_MEM_BLOCK *Block + ) +{ + ASSERT ((Head != NULL) && (Block != NULL)); + Block->Next = Head->Next; + Head->Next = Block; +} + +/** + Is the memory block empty? + + @param Block The memory block to check. + + @retval TRUE The memory block is empty. + @retval FALSE The memory block isn't empty. + +**/ +BOOLEAN +EmmcPeimIsMemBlockEmpty ( + IN EMMC_PEIM_MEM_BLOCK *Block + ) +{ + UINTN Index; + + for (Index = 0; Index < Block->BitsLen; Index++) { + if (Block->Bits[Index] != 0) { + return FALSE; + } + } + + return TRUE; +} + +/** + Initialize the memory management pool for the host controller. + + @param Private The Emmc Peim driver private data. + + @retval EFI_SUCCESS The memory pool is initialized. + @retval Others Fail to init the memory pool. + +**/ +EFI_STATUS +EmmcPeimInitMemPool ( + IN EMMC_PEIM_HC_PRIVATE_DATA *Private + ) +{ + EMMC_PEIM_MEM_POOL *Pool; + EFI_STATUS Status; + VOID *TempPtr; + + TempPtr = NULL; + Pool = NULL; + + Status = PeiServicesAllocatePool (sizeof (EMMC_PEIM_MEM_POOL), &TempPtr); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + ZeroMem ((VOID *)(UINTN)TempPtr, sizeof (EMMC_PEIM_MEM_POOL)); + + Pool = (EMMC_PEIM_MEM_POOL *)((UINTN)TempPtr); + + Pool->Head = EmmcPeimAllocMemBlock (EMMC_PEIM_MEM_DEFAULT_PAGES); + + if (Pool->Head == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Private->Pool = Pool; + return EFI_SUCCESS; +} + +/** + Release the memory management pool. + + @param Pool The memory pool to free. + + @retval EFI_DEVICE_ERROR Fail to free the memory pool. + @retval EFI_SUCCESS The memory pool is freed. + +**/ +EFI_STATUS +EmmcPeimFreeMemPool ( + IN EMMC_PEIM_MEM_POOL *Pool + ) +{ + EMMC_PEIM_MEM_BLOCK *Block; + + ASSERT (Pool->Head != NULL); + + // + // Unlink all the memory blocks from the pool, then free them. + // + for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) { + EmmcPeimFreeMemBlock (Pool, Block); + } + + EmmcPeimFreeMemBlock (Pool, Pool->Head); + + return EFI_SUCCESS; +} + +/** + Allocate some memory from the host controller's memory pool + which can be used to communicate with host controller. + + @param Pool The host controller's memory pool. + @param Size Size of the memory to allocate. + + @return The allocated memory or NULL. + +**/ +VOID * +EmmcPeimAllocateMem ( + IN EMMC_PEIM_MEM_POOL *Pool, + IN UINTN Size + ) +{ + EMMC_PEIM_MEM_BLOCK *Head; + EMMC_PEIM_MEM_BLOCK *Block; + EMMC_PEIM_MEM_BLOCK *NewBlock; + VOID *Mem; + UINTN AllocSize; + UINTN Pages; + + Mem = NULL; + AllocSize = EMMC_PEIM_MEM_ROUND (Size); + Head = Pool->Head; + ASSERT (Head != NULL); + + // + // First check whether current memory blocks can satisfy the allocation. + // + for (Block = Head; Block != NULL; Block = Block->Next) { + Mem = EmmcPeimAllocMemFromBlock (Block, AllocSize / EMMC_PEIM_MEM_UNIT); + + if (Mem != NULL) { + ZeroMem (Mem, Size); + break; + } + } + + if (Mem != NULL) { + return Mem; + } + + // + // Create a new memory block if there is not enough memory + // in the pool. If the allocation size is larger than the + // default page number, just allocate a large enough memory + // block. Otherwise allocate default pages. + // + if (AllocSize > EFI_PAGES_TO_SIZE (EMMC_PEIM_MEM_DEFAULT_PAGES)) { + Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1; + } else { + Pages = EMMC_PEIM_MEM_DEFAULT_PAGES; + } + + NewBlock = EmmcPeimAllocMemBlock (Pages); + if (NewBlock == NULL) { + return NULL; + } + + // + // Add the new memory block to the pool, then allocate memory from it + // + EmmcPeimInsertMemBlockToPool (Head, NewBlock); + Mem = EmmcPeimAllocMemFromBlock (NewBlock, AllocSize / EMMC_PEIM_MEM_UNIT); + + if (Mem != NULL) { + ZeroMem (Mem, Size); + } + + return Mem; +} + +/** + Free the allocated memory back to the memory pool. + + @param Pool The memory pool of the host controller. + @param Mem The memory to free. + @param Size The size of the memory to free. + +**/ +VOID +EmmcPeimFreeMem ( + IN EMMC_PEIM_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ) +{ + EMMC_PEIM_MEM_BLOCK *Head; + EMMC_PEIM_MEM_BLOCK *Block; + UINT8 *ToFree; + UINTN AllocSize; + UINTN Byte; + UINTN Bit; + UINTN Count; + + Head = Pool->Head; + AllocSize = EMMC_PEIM_MEM_ROUND (Size); + ToFree = (UINT8 *)Mem; + + for (Block = Head; Block != NULL; Block = Block->Next) { + // + // scan the memory block list for the memory block that + // completely contains the memory to free. + // + if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) { + // + // compute the start byte and bit in the bit array + // + Byte = ((ToFree - Block->Buf) / EMMC_PEIM_MEM_UNIT) / 8; + Bit = ((ToFree - Block->Buf) / EMMC_PEIM_MEM_UNIT) % 8; + + // + // reset associated bits in bit array + // + for (Count = 0; Count < (AllocSize / EMMC_PEIM_MEM_UNIT); Count++) { + ASSERT (EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)); + + Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] ^ EMMC_PEIM_MEM_BIT (Bit)); + EMMC_PEIM_NEXT_BIT (Byte, Bit); + } + + break; + } + } + + // + // If Block == NULL, it means that the current memory isn't + // in the host controller's pool. This is critical because + // the caller has passed in a wrong memory point + // + ASSERT (Block != NULL); + + // + // Release the current memory block if it is empty and not the head + // + if ((Block != Head) && EmmcPeimIsMemBlockEmpty (Block)) { + EmmcPeimFreeMemBlock (Pool, Block); + } + + return; +} diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.h b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.h index d3b6ec545a..15ee6593f8 100644 --- a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.h +++ b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.h @@ -1,55 +1,55 @@ -/** @file
-
-Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
-
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _EMMC_PEIM_MEM_H_
-#define _EMMC_PEIM_MEM_H_
-
-#define EMMC_PEIM_MEM_BIT(a) ((UINTN)(1 << (a)))
-
-#define EMMC_PEIM_MEM_BIT_IS_SET(Data, Bit) \
- ((BOOLEAN)(((Data) & EMMC_PEIM_MEM_BIT(Bit)) == EMMC_PEIM_MEM_BIT(Bit)))
-
-typedef struct _EMMC_PEIM_MEM_BLOCK EMMC_PEIM_MEM_BLOCK;
-
-struct _EMMC_PEIM_MEM_BLOCK {
- UINT8 *Bits; // Bit array to record which unit is allocated
- UINTN BitsLen;
- UINT8 *Buf;
- UINT8 *BufHost;
- UINTN BufLen; // Memory size in bytes
- VOID *Mapping;
- EMMC_PEIM_MEM_BLOCK *Next;
-};
-
-typedef struct _EMMC_PEIM_MEM_POOL {
- EMMC_PEIM_MEM_BLOCK *Head;
-} EMMC_PEIM_MEM_POOL;
-
-//
-// Memory allocation unit, note that the value must meet EMMC spec alignment requirement.
-//
-#define EMMC_PEIM_MEM_UNIT 128
-
-#define EMMC_PEIM_MEM_UNIT_MASK (EMMC_PEIM_MEM_UNIT - 1)
-#define EMMC_PEIM_MEM_DEFAULT_PAGES 16
-
-#define EMMC_PEIM_MEM_ROUND(Len) (((Len) + EMMC_PEIM_MEM_UNIT_MASK) & (~EMMC_PEIM_MEM_UNIT_MASK))
-
-//
-// Advance the byte and bit to the next bit, adjust byte accordingly.
-//
-#define EMMC_PEIM_NEXT_BIT(Byte, Bit) \
- do { \
- (Bit)++; \
- if ((Bit) > 7) { \
- (Byte)++; \
- (Bit) = 0; \
- } \
- } while (0)
-
-#endif
+/** @file + +Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EMMC_PEIM_MEM_H_ +#define _EMMC_PEIM_MEM_H_ + +#define EMMC_PEIM_MEM_BIT(a) ((UINTN)(1 << (a))) + +#define EMMC_PEIM_MEM_BIT_IS_SET(Data, Bit) \ + ((BOOLEAN)(((Data) & EMMC_PEIM_MEM_BIT(Bit)) == EMMC_PEIM_MEM_BIT(Bit))) + +typedef struct _EMMC_PEIM_MEM_BLOCK EMMC_PEIM_MEM_BLOCK; + +struct _EMMC_PEIM_MEM_BLOCK { + UINT8 *Bits; // Bit array to record which unit is allocated + UINTN BitsLen; + UINT8 *Buf; + UINT8 *BufHost; + UINTN BufLen; // Memory size in bytes + VOID *Mapping; + EMMC_PEIM_MEM_BLOCK *Next; +}; + +typedef struct _EMMC_PEIM_MEM_POOL { + EMMC_PEIM_MEM_BLOCK *Head; +} EMMC_PEIM_MEM_POOL; + +// +// Memory allocation unit, note that the value must meet EMMC spec alignment requirement. +// +#define EMMC_PEIM_MEM_UNIT 128 + +#define EMMC_PEIM_MEM_UNIT_MASK (EMMC_PEIM_MEM_UNIT - 1) +#define EMMC_PEIM_MEM_DEFAULT_PAGES 16 + +#define EMMC_PEIM_MEM_ROUND(Len) (((Len) + EMMC_PEIM_MEM_UNIT_MASK) & (~EMMC_PEIM_MEM_UNIT_MASK)) + +// +// Advance the byte and bit to the next bit, adjust byte accordingly. +// +#define EMMC_PEIM_NEXT_BIT(Byte, Bit) \ + do { \ + (Bit)++; \ + if ((Bit) > 7) { \ + (Byte)++; \ + (Bit) = 0; \ + } \ + } while (0) + +#endif diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.c b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.c index bafd71e9b5..757eb3bb38 100644 --- a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.c +++ b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.c @@ -1,2951 +1,2951 @@ -/** @file
-
- Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "EmmcBlockIoPei.h"
-
-/**
- Read/Write specified EMMC host controller mmio register.
-
- @param[in] Address The address of the mmio register to be read/written.
- @param[in] Read A boolean to indicate it's read or write operation.
- @param[in] Count The width of the mmio register in bytes.
- Must be 1, 2 , 4 or 8 bytes.
- @param[in, out] Data For read operations, the destination buffer to store
- the results. For write operations, the source buffer
- to write data from. The caller is responsible for
- having ownership of the data buffer and ensuring its
- size not less than Count bytes.
-
- @retval EFI_INVALID_PARAMETER The Address or the Data or the Count is not valid.
- @retval EFI_SUCCESS The read/write operation succeeds.
- @retval Others The read/write operation fails.
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcPeimHcRwMmio (
- IN UINTN Address,
- IN BOOLEAN Read,
- IN UINT8 Count,
- IN OUT VOID *Data
- )
-{
- if ((Address == 0) || (Data == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) {
- return EFI_INVALID_PARAMETER;
- }
-
- switch (Count) {
- case 1:
- if (Read) {
- *(UINT8 *)Data = MmioRead8 (Address);
- } else {
- MmioWrite8 (Address, *(UINT8 *)Data);
- }
-
- break;
- case 2:
- if (Read) {
- *(UINT16 *)Data = MmioRead16 (Address);
- } else {
- MmioWrite16 (Address, *(UINT16 *)Data);
- }
-
- break;
- case 4:
- if (Read) {
- *(UINT32 *)Data = MmioRead32 (Address);
- } else {
- MmioWrite32 (Address, *(UINT32 *)Data);
- }
-
- break;
- case 8:
- if (Read) {
- *(UINT64 *)Data = MmioRead64 (Address);
- } else {
- MmioWrite64 (Address, *(UINT64 *)Data);
- }
-
- break;
- default:
- ASSERT (FALSE);
- return EFI_INVALID_PARAMETER;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Do OR operation with the value of the specified EMMC host controller mmio register.
-
- @param[in] Address The address of the mmio register to be read/written.
- @param[in] Count The width of the mmio register in bytes.
- Must be 1, 2 , 4 or 8 bytes.
- @param[in] OrData The pointer to the data used to do OR operation.
- The caller is responsible for having ownership of
- the data buffer and ensuring its size not less than
- Count bytes.
-
- @retval EFI_INVALID_PARAMETER The Address or the OrData or the Count is not valid.
- @retval EFI_SUCCESS The OR operation succeeds.
- @retval Others The OR operation fails.
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcPeimHcOrMmio (
- IN UINTN Address,
- IN UINT8 Count,
- IN VOID *OrData
- )
-{
- EFI_STATUS Status;
- UINT64 Data;
- UINT64 Or;
-
- Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Data);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Count == 1) {
- Or = *(UINT8 *)OrData;
- } else if (Count == 2) {
- Or = *(UINT16 *)OrData;
- } else if (Count == 4) {
- Or = *(UINT32 *)OrData;
- } else if (Count == 8) {
- Or = *(UINT64 *)OrData;
- } else {
- return EFI_INVALID_PARAMETER;
- }
-
- Data |= Or;
- Status = EmmcPeimHcRwMmio (Address, FALSE, Count, &Data);
-
- return Status;
-}
-
-/**
- Do AND operation with the value of the specified EMMC host controller mmio register.
-
- @param[in] Address The address of the mmio register to be read/written.
- @param[in] Count The width of the mmio register in bytes.
- Must be 1, 2 , 4 or 8 bytes.
- @param[in] AndData The pointer to the data used to do AND operation.
- The caller is responsible for having ownership of
- the data buffer and ensuring its size not less than
- Count bytes.
-
- @retval EFI_INVALID_PARAMETER The Address or the AndData or the Count is not valid.
- @retval EFI_SUCCESS The AND operation succeeds.
- @retval Others The AND operation fails.
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcPeimHcAndMmio (
- IN UINTN Address,
- IN UINT8 Count,
- IN VOID *AndData
- )
-{
- EFI_STATUS Status;
- UINT64 Data;
- UINT64 And;
-
- Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Data);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Count == 1) {
- And = *(UINT8 *)AndData;
- } else if (Count == 2) {
- And = *(UINT16 *)AndData;
- } else if (Count == 4) {
- And = *(UINT32 *)AndData;
- } else if (Count == 8) {
- And = *(UINT64 *)AndData;
- } else {
- return EFI_INVALID_PARAMETER;
- }
-
- Data &= And;
- Status = EmmcPeimHcRwMmio (Address, FALSE, Count, &Data);
-
- return Status;
-}
-
-/**
- Wait for the value of the specified MMIO register set to the test value.
-
- @param[in] Address The address of the mmio register to be checked.
- @param[in] Count The width of the mmio register in bytes.
- Must be 1, 2, 4 or 8 bytes.
- @param[in] MaskValue The mask value of memory.
- @param[in] TestValue The test value of memory.
-
- @retval EFI_NOT_READY The MMIO register hasn't set to the expected value.
- @retval EFI_SUCCESS The MMIO register has expected value.
- @retval Others The MMIO operation fails.
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcPeimHcCheckMmioSet (
- IN UINTN Address,
- IN UINT8 Count,
- IN UINT64 MaskValue,
- IN UINT64 TestValue
- )
-{
- EFI_STATUS Status;
- UINT64 Value;
-
- //
- // Access PCI MMIO space to see if the value is the tested one.
- //
- Value = 0;
- Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Value);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Value &= MaskValue;
-
- if (Value == TestValue) {
- return EFI_SUCCESS;
- }
-
- return EFI_NOT_READY;
-}
-
-/**
- Wait for the value of the specified MMIO register set to the test value.
-
- @param[in] Address The address of the mmio register to wait.
- @param[in] Count The width of the mmio register in bytes.
- Must be 1, 2, 4 or 8 bytes.
- @param[in] MaskValue The mask value of memory.
- @param[in] TestValue The test value of memory.
- @param[in] Timeout The time out value for wait memory set, uses 1
- microsecond as a unit.
-
- @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout
- range.
- @retval EFI_SUCCESS The MMIO register has expected value.
- @retval Others The MMIO operation fails.
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcPeimHcWaitMmioSet (
- IN UINTN Address,
- IN UINT8 Count,
- IN UINT64 MaskValue,
- IN UINT64 TestValue,
- IN UINT64 Timeout
- )
-{
- EFI_STATUS Status;
- BOOLEAN InfiniteWait;
-
- if (Timeout == 0) {
- InfiniteWait = TRUE;
- } else {
- InfiniteWait = FALSE;
- }
-
- while (InfiniteWait || (Timeout > 0)) {
- Status = EmmcPeimHcCheckMmioSet (
- Address,
- Count,
- MaskValue,
- TestValue
- );
- if (Status != EFI_NOT_READY) {
- return Status;
- }
-
- //
- // Stall for 1 microsecond.
- //
- MicroSecondDelay (1);
-
- Timeout--;
- }
-
- return EFI_TIMEOUT;
-}
-
-/**
- Software reset the specified EMMC host controller and enable all interrupts.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The software reset executes successfully.
- @retval Others The software reset fails.
-
-**/
-EFI_STATUS
-EmmcPeimHcReset (
- IN UINTN Bar
- )
-{
- EFI_STATUS Status;
- UINT8 SwReset;
-
- SwReset = 0xFF;
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset);
-
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "EmmcPeimHcReset: write full 1 fails: %r\n", Status));
- return Status;
- }
-
- Status = EmmcPeimHcWaitMmioSet (
- Bar + EMMC_HC_SW_RST,
- sizeof (SwReset),
- 0xFF,
- 0x00,
- EMMC_TIMEOUT
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_INFO, "EmmcPeimHcReset: reset done with %r\n", Status));
- return Status;
- }
-
- //
- // Enable all interrupt after reset all.
- //
- Status = EmmcPeimHcEnableInterrupt (Bar);
-
- return Status;
-}
-
-/**
- Set all interrupt status bits in Normal and Error Interrupt Status Enable
- register.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The operation executes successfully.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimHcEnableInterrupt (
- IN UINTN Bar
- )
-{
- EFI_STATUS Status;
- UINT16 IntStatus;
-
- //
- // Enable all bits in Error Interrupt Status Enable Register
- //
- IntStatus = 0xFFFF;
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ERR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Enable all bits in Normal Interrupt Status Enable Register
- //
- IntStatus = 0xFFFF;
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);
-
- return Status;
-}
-
-/**
- Get the capability data from the specified slot.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[out] Capability The buffer to store the capability data.
-
- @retval EFI_SUCCESS The operation executes successfully.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimHcGetCapability (
- IN UINTN Bar,
- OUT EMMC_HC_SLOT_CAP *Capability
- )
-{
- EFI_STATUS Status;
- UINT64 Cap;
-
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CAP, TRUE, sizeof (Cap), &Cap);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- CopyMem (Capability, &Cap, sizeof (Cap));
-
- return EFI_SUCCESS;
-}
-
-/**
- Detect whether there is a EMMC card attached at the specified EMMC host controller
- slot.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS There is a EMMC card attached.
- @retval EFI_NO_MEDIA There is not a EMMC card attached.
- @retval Others The detection fails.
-
-**/
-EFI_STATUS
-EmmcPeimHcCardDetect (
- IN UINTN Bar
- )
-{
- EFI_STATUS Status;
- UINT16 Data;
- UINT32 PresentState;
-
- //
- // Check Normal Interrupt Status Register
- //
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, TRUE, sizeof (Data), &Data);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if ((Data & (BIT6 | BIT7)) != 0) {
- //
- // Clear BIT6 and BIT7 by writing 1 to these two bits if set.
- //
- Data &= BIT6 | BIT7;
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, FALSE, sizeof (Data), &Data);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- //
- // Check Present State Register to see if there is a card presented.
- //
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if ((PresentState & BIT16) != 0) {
- return EFI_SUCCESS;
- } else {
- return EFI_NO_MEDIA;
- }
-}
-
-/**
- Stop EMMC card clock.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS Succeed to stop EMMC clock.
- @retval Others Fail to stop EMMC clock.
-
-**/
-EFI_STATUS
-EmmcPeimHcStopClock (
- IN UINTN Bar
- )
-{
- EFI_STATUS Status;
- UINT32 PresentState;
- UINT16 ClockCtrl;
-
- //
- // Ensure no SD transactions are occurring on the SD Bus by
- // waiting for Command Inhibit (DAT) and Command Inhibit (CMD)
- // in the Present State register to be 0.
- //
- Status = EmmcPeimHcWaitMmioSet (
- Bar + EMMC_HC_PRESENT_STATE,
- sizeof (PresentState),
- BIT0 | BIT1,
- 0,
- EMMC_TIMEOUT
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Set SD Clock Enable in the Clock Control register to 0
- //
- ClockCtrl = (UINT16) ~BIT2;
- Status = EmmcPeimHcAndMmio (Bar + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
-
- return Status;
-}
-
-/**
- EMMC card clock supply.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
-
- @retval EFI_SUCCESS The clock is supplied successfully.
- @retval Others The clock isn't supplied successfully.
-
-**/
-EFI_STATUS
-EmmcPeimHcClockSupply (
- IN UINTN Bar,
- IN UINT64 ClockFreq
- )
-{
- EFI_STATUS Status;
- EMMC_HC_SLOT_CAP Capability;
- UINT32 BaseClkFreq;
- UINT32 SettingFreq;
- UINT32 Divisor;
- UINT32 Remainder;
- UINT16 ControllerVer;
- UINT16 ClockCtrl;
-
- //
- // Calculate a divisor for SD clock frequency
- //
- Status = EmmcPeimHcGetCapability (Bar, &Capability);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- ASSERT (Capability.BaseClkFreq != 0);
-
- BaseClkFreq = Capability.BaseClkFreq;
-
- if (ClockFreq == 0) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (ClockFreq > (BaseClkFreq * 1000)) {
- ClockFreq = BaseClkFreq * 1000;
- }
-
- //
- // Calculate the divisor of base frequency.
- //
- Divisor = 0;
- SettingFreq = BaseClkFreq * 1000;
- while (ClockFreq < SettingFreq) {
- Divisor++;
-
- SettingFreq = (BaseClkFreq * 1000) / (2 * Divisor);
- Remainder = (BaseClkFreq * 1000) % (2 * Divisor);
- if ((ClockFreq == SettingFreq) && (Remainder == 0)) {
- break;
- }
-
- if ((ClockFreq == SettingFreq) && (Remainder != 0)) {
- SettingFreq++;
- }
- }
-
- DEBUG ((DEBUG_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq));
-
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register.
- //
- if ((ControllerVer & 0xFF) == 2) {
- ASSERT (Divisor <= 0x3FF);
- ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2);
- } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {
- //
- // Only the most significant bit can be used as divisor.
- //
- if (((Divisor - 1) & Divisor) != 0) {
- Divisor = 1 << (HighBitSet32 (Divisor) + 1);
- }
-
- ASSERT (Divisor <= 0x80);
- ClockCtrl = (Divisor & 0xFF) << 8;
- } else {
- DEBUG ((DEBUG_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer));
- return EFI_UNSUPPORTED;
- }
-
- //
- // Stop bus clock at first
- //
- Status = EmmcPeimHcStopClock (Bar);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Supply clock frequency with specified divisor
- //
- ClockCtrl |= BIT0;
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n"));
- return Status;
- }
-
- //
- // Wait Internal Clock Stable in the Clock Control register to be 1
- //
- Status = EmmcPeimHcWaitMmioSet (
- Bar + EMMC_HC_CLOCK_CTRL,
- sizeof (ClockCtrl),
- BIT1,
- BIT1,
- EMMC_TIMEOUT
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Set SD Clock Enable in the Clock Control register to 1
- //
- ClockCtrl = BIT2;
- Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
-
- return Status;
-}
-
-/**
- EMMC bus power control.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] PowerCtrl The value setting to the power control register.
-
- @retval TRUE There is a EMMC card attached.
- @retval FALSE There is no a EMMC card attached.
-
-**/
-EFI_STATUS
-EmmcPeimHcPowerControl (
- IN UINTN Bar,
- IN UINT8 PowerCtrl
- )
-{
- EFI_STATUS Status;
-
- //
- // Clr SD Bus Power
- //
- PowerCtrl &= (UINT8) ~BIT0;
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register
- //
- PowerCtrl |= BIT0;
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);
-
- return Status;
-}
-
-/**
- Set the EMMC bus width.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] BusWidth The bus width used by the EMMC device, it must be 1, 4 or 8.
-
- @retval EFI_SUCCESS The bus width is set successfully.
- @retval Others The bus width isn't set successfully.
-
-**/
-EFI_STATUS
-EmmcPeimHcSetBusWidth (
- IN UINTN Bar,
- IN UINT16 BusWidth
- )
-{
- EFI_STATUS Status;
- UINT8 HostCtrl1;
-
- if (BusWidth == 1) {
- HostCtrl1 = (UINT8) ~(BIT5 | BIT1);
- Status = EmmcPeimHcAndMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
- } else if (BusWidth == 4) {
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- HostCtrl1 |= BIT1;
- HostCtrl1 &= (UINT8) ~BIT5;
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);
- } else if (BusWidth == 8) {
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- HostCtrl1 &= (UINT8) ~BIT1;
- HostCtrl1 |= BIT5;
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);
- } else {
- ASSERT (FALSE);
- return EFI_INVALID_PARAMETER;
- }
-
- return Status;
-}
-
-/**
- Supply EMMC card with lowest clock frequency at initialization.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The clock is supplied successfully.
- @retval Others The clock isn't supplied successfully.
-
-**/
-EFI_STATUS
-EmmcPeimHcInitClockFreq (
- IN UINTN Bar
- )
-{
- EFI_STATUS Status;
- EMMC_HC_SLOT_CAP Capability;
- UINT32 InitFreq;
-
- //
- // Calculate a divisor for SD clock frequency
- //
- Status = EmmcPeimHcGetCapability (Bar, &Capability);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Capability.BaseClkFreq == 0) {
- //
- // Don't support get Base Clock Frequency information via another method
- //
- return EFI_UNSUPPORTED;
- }
-
- //
- // Supply 400KHz clock frequency at initialization phase.
- //
- InitFreq = 400;
- Status = EmmcPeimHcClockSupply (Bar, InitFreq);
- return Status;
-}
-
-/**
- Supply EMMC card with maximum voltage at initialization.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The voltage is supplied successfully.
- @retval Others The voltage isn't supplied successfully.
-
-**/
-EFI_STATUS
-EmmcPeimHcInitPowerVoltage (
- IN UINTN Bar
- )
-{
- EFI_STATUS Status;
- EMMC_HC_SLOT_CAP Capability;
- UINT8 MaxVoltage;
- UINT8 HostCtrl2;
-
- //
- // Get the support voltage of the Host Controller
- //
- Status = EmmcPeimHcGetCapability (Bar, &Capability);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Calculate supported maximum voltage according to SD Bus Voltage Select
- //
- if (Capability.Voltage33 != 0) {
- //
- // Support 3.3V
- //
- MaxVoltage = 0x0E;
- } else if (Capability.Voltage30 != 0) {
- //
- // Support 3.0V
- //
- MaxVoltage = 0x0C;
- } else if (Capability.Voltage18 != 0) {
- //
- // Support 1.8V
- //
- MaxVoltage = 0x0A;
- HostCtrl2 = BIT3;
- Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- MicroSecondDelay (5000);
- } else {
- ASSERT (FALSE);
- return EFI_DEVICE_ERROR;
- }
-
- //
- // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register
- //
- Status = EmmcPeimHcPowerControl (Bar, MaxVoltage);
-
- return Status;
-}
-
-/**
- Initialize the Timeout Control register with most conservative value at initialization.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The timeout control register is configured successfully.
- @retval Others The timeout control register isn't configured successfully.
-
-**/
-EFI_STATUS
-EmmcPeimHcInitTimeoutCtrl (
- IN UINTN Bar
- )
-{
- EFI_STATUS Status;
- UINT8 Timeout;
-
- Timeout = 0x0E;
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_TIMEOUT_CTRL, FALSE, sizeof (Timeout), &Timeout);
-
- return Status;
-}
-
-/**
- Initial EMMC host controller with lowest clock frequency, max power and max timeout value
- at initialization.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The host controller is initialized successfully.
- @retval Others The host controller isn't initialized successfully.
-
-**/
-EFI_STATUS
-EmmcPeimHcInitHost (
- IN UINTN Bar
- )
-{
- EFI_STATUS Status;
-
- Status = EmmcPeimHcInitClockFreq (Bar);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = EmmcPeimHcInitPowerVoltage (Bar);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = EmmcPeimHcInitTimeoutCtrl (Bar);
- return Status;
-}
-
-/**
- Turn on/off LED.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] On The boolean to turn on/off LED.
-
- @retval EFI_SUCCESS The LED is turned on/off successfully.
- @retval Others The LED isn't turned on/off successfully.
-
-**/
-EFI_STATUS
-EmmcPeimHcLedOnOff (
- IN UINTN Bar,
- IN BOOLEAN On
- )
-{
- EFI_STATUS Status;
- UINT8 HostCtrl1;
-
- if (On) {
- HostCtrl1 = BIT0;
- Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
- } else {
- HostCtrl1 = (UINT8) ~BIT0;
- Status = EmmcPeimHcAndMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
- }
-
- return Status;
-}
-
-/**
- Build ADMA descriptor table for transfer.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details.
-
- @param[in] Trb The pointer to the EMMC_TRB instance.
-
- @retval EFI_SUCCESS The ADMA descriptor table is created successfully.
- @retval Others The ADMA descriptor table isn't created successfully.
-
-**/
-EFI_STATUS
-BuildAdmaDescTable (
- IN EMMC_TRB *Trb
- )
-{
- EFI_PHYSICAL_ADDRESS Data;
- UINT64 DataLen;
- UINT64 Entries;
- UINT32 Index;
- UINT64 Remaining;
- UINT32 Address;
-
- Data = Trb->DataPhy;
- DataLen = Trb->DataLen;
- //
- // Only support 32bit ADMA Descriptor Table
- //
- if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)
- // for 32-bit address descriptor table.
- //
- if ((Data & (BIT0 | BIT1)) != 0) {
- DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));
- }
-
- Entries = DivU64x32 ((DataLen + ADMA_MAX_DATA_PER_LINE - 1), ADMA_MAX_DATA_PER_LINE);
-
- Trb->AdmaDescSize = (UINTN)MultU64x32 (Entries, sizeof (EMMC_HC_ADMA_DESC_LINE));
- Trb->AdmaDesc = EmmcPeimAllocateMem (Trb->Slot->Private->Pool, Trb->AdmaDescSize);
- if (Trb->AdmaDesc == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Remaining = DataLen;
- Address = (UINT32)Data;
- for (Index = 0; Index < Entries; Index++) {
- if (Remaining <= ADMA_MAX_DATA_PER_LINE) {
- Trb->AdmaDesc[Index].Valid = 1;
- Trb->AdmaDesc[Index].Act = 2;
- Trb->AdmaDesc[Index].Length = (UINT16)Remaining;
- Trb->AdmaDesc[Index].Address = Address;
- break;
- } else {
- Trb->AdmaDesc[Index].Valid = 1;
- Trb->AdmaDesc[Index].Act = 2;
- Trb->AdmaDesc[Index].Length = 0;
- Trb->AdmaDesc[Index].Address = Address;
- }
-
- Remaining -= ADMA_MAX_DATA_PER_LINE;
- Address += ADMA_MAX_DATA_PER_LINE;
- }
-
- //
- // Set the last descriptor line as end of descriptor table
- //
- Trb->AdmaDesc[Index].End = 1;
- return EFI_SUCCESS;
-}
-
-/**
- Create a new TRB for the EMMC cmd request.
-
- @param[in] Slot The slot number of the EMMC card to send the command to.
- @param[in] Packet A pointer to the SD command data structure.
-
- @return Created Trb or NULL.
-
-**/
-EMMC_TRB *
-EmmcPeimCreateTrb (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN EMMC_COMMAND_PACKET *Packet
- )
-{
- EMMC_TRB *Trb;
- EFI_STATUS Status;
- EMMC_HC_SLOT_CAP Capability;
- EDKII_IOMMU_OPERATION MapOp;
- UINTN MapLength;
-
- //
- // Calculate a divisor for SD clock frequency
- //
- Status = EmmcPeimHcGetCapability (Slot->EmmcHcBase, &Capability);
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- Trb = AllocateZeroPool (sizeof (EMMC_TRB));
- if (Trb == NULL) {
- return NULL;
- }
-
- Trb->Slot = Slot;
- Trb->BlockSize = 0x200;
- Trb->Packet = Packet;
- Trb->Timeout = Packet->Timeout;
-
- if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {
- Trb->Data = Packet->InDataBuffer;
- Trb->DataLen = Packet->InTransferLength;
- Trb->Read = TRUE;
- } else if ((Packet->OutTransferLength != 0) && (Packet->OutDataBuffer != NULL)) {
- Trb->Data = Packet->OutDataBuffer;
- Trb->DataLen = Packet->OutTransferLength;
- Trb->Read = FALSE;
- } else if ((Packet->InTransferLength == 0) && (Packet->OutTransferLength == 0)) {
- Trb->Data = NULL;
- Trb->DataLen = 0;
- } else {
- goto Error;
- }
-
- if ((Trb->DataLen != 0) && (Trb->DataLen < Trb->BlockSize)) {
- Trb->BlockSize = (UINT16)Trb->DataLen;
- }
-
- if (Packet->EmmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK) {
- Trb->Mode = EmmcPioMode;
- } else {
- if (Trb->Read) {
- MapOp = EdkiiIoMmuOperationBusMasterWrite;
- } else {
- MapOp = EdkiiIoMmuOperationBusMasterRead;
- }
-
- if (Trb->DataLen != 0) {
- MapLength = Trb->DataLen;
- Status = IoMmuMap (MapOp, Trb->Data, &MapLength, &Trb->DataPhy, &Trb->DataMap);
-
- if (EFI_ERROR (Status) || (MapLength != Trb->DataLen)) {
- DEBUG ((DEBUG_ERROR, "EmmcPeimCreateTrb: Fail to map data buffer.\n"));
- goto Error;
- }
- }
-
- if (Trb->DataLen == 0) {
- Trb->Mode = EmmcNoData;
- } else if (Capability.Adma2 != 0) {
- Trb->Mode = EmmcAdmaMode;
- Status = BuildAdmaDescTable (Trb);
- if (EFI_ERROR (Status)) {
- goto Error;
- }
- } else if (Capability.Sdma != 0) {
- Trb->Mode = EmmcSdmaMode;
- } else {
- Trb->Mode = EmmcPioMode;
- }
- }
-
- return Trb;
-
-Error:
- EmmcPeimFreeTrb (Trb);
- return NULL;
-}
-
-/**
- Free the resource used by the TRB.
-
- @param[in] Trb The pointer to the EMMC_TRB instance.
-
-**/
-VOID
-EmmcPeimFreeTrb (
- IN EMMC_TRB *Trb
- )
-{
- if ((Trb != NULL) && (Trb->DataMap != NULL)) {
- IoMmuUnmap (Trb->DataMap);
- }
-
- if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) {
- EmmcPeimFreeMem (Trb->Slot->Private->Pool, Trb->AdmaDesc, Trb->AdmaDescSize);
- }
-
- if (Trb != NULL) {
- FreePool (Trb);
- }
-
- return;
-}
-
-/**
- Check if the env is ready for execute specified TRB.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] Trb The pointer to the EMMC_TRB instance.
-
- @retval EFI_SUCCESS The env is ready for TRB execution.
- @retval EFI_NOT_READY The env is not ready for TRB execution.
- @retval Others Some erros happen.
-
-**/
-EFI_STATUS
-EmmcPeimCheckTrbEnv (
- IN UINTN Bar,
- IN EMMC_TRB *Trb
- )
-{
- EFI_STATUS Status;
- EMMC_COMMAND_PACKET *Packet;
- UINT32 PresentState;
-
- Packet = Trb->Packet;
-
- if ((Packet->EmmcCmdBlk->CommandType == EmmcCommandTypeAdtc) ||
- (Packet->EmmcCmdBlk->ResponseType == EmmcResponceTypeR1b) ||
- (Packet->EmmcCmdBlk->ResponseType == EmmcResponceTypeR5b))
- {
- //
- // Wait Command Inhibit (CMD) and Command Inhibit (DAT) in
- // the Present State register to be 0
- //
- PresentState = BIT0 | BIT1;
- } else {
- //
- // Wait Command Inhibit (CMD) in the Present State register
- // to be 0
- //
- PresentState = BIT0;
- }
-
- Status = EmmcPeimHcCheckMmioSet (
- Bar + EMMC_HC_PRESENT_STATE,
- sizeof (PresentState),
- PresentState,
- 0
- );
-
- return Status;
-}
-
-/**
- Wait for the env to be ready for execute specified TRB.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] Trb The pointer to the EMMC_TRB instance.
-
- @retval EFI_SUCCESS The env is ready for TRB execution.
- @retval EFI_TIMEOUT The env is not ready for TRB execution in time.
- @retval Others Some erros happen.
-
-**/
-EFI_STATUS
-EmmcPeimWaitTrbEnv (
- IN UINTN Bar,
- IN EMMC_TRB *Trb
- )
-{
- EFI_STATUS Status;
- EMMC_COMMAND_PACKET *Packet;
- UINT64 Timeout;
- BOOLEAN InfiniteWait;
-
- //
- // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register
- //
- Packet = Trb->Packet;
- Timeout = Packet->Timeout;
- if (Timeout == 0) {
- InfiniteWait = TRUE;
- } else {
- InfiniteWait = FALSE;
- }
-
- while (InfiniteWait || (Timeout > 0)) {
- //
- // Check Trb execution result by reading Normal Interrupt Status register.
- //
- Status = EmmcPeimCheckTrbEnv (Bar, Trb);
- if (Status != EFI_NOT_READY) {
- return Status;
- }
-
- //
- // Stall for 1 microsecond.
- //
- MicroSecondDelay (1);
-
- Timeout--;
- }
-
- return EFI_TIMEOUT;
-}
-
-/**
- Execute the specified TRB.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] Trb The pointer to the EMMC_TRB instance.
-
- @retval EFI_SUCCESS The TRB is sent to host controller successfully.
- @retval Others Some erros happen when sending this request to the host controller.
-
-**/
-EFI_STATUS
-EmmcPeimExecTrb (
- IN UINTN Bar,
- IN EMMC_TRB *Trb
- )
-{
- EFI_STATUS Status;
- EMMC_COMMAND_PACKET *Packet;
- UINT16 Cmd;
- UINT16 IntStatus;
- UINT32 Argument;
- UINT16 BlkCount;
- UINT16 BlkSize;
- UINT16 TransMode;
- UINT8 HostCtrl1;
- UINT32 SdmaAddr;
- UINT64 AdmaAddr;
-
- Packet = Trb->Packet;
- //
- // Clear all bits in Error Interrupt Status Register
- //
- IntStatus = 0xFFFF;
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ERR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Clear all bits in Normal Interrupt Status Register
- //
- IntStatus = 0xFFFF;
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Set Host Control 1 register DMA Select field
- //
- if (Trb->Mode == EmmcAdmaMode) {
- HostCtrl1 = BIT4;
- Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- EmmcPeimHcLedOnOff (Bar, TRUE);
-
- if (Trb->Mode == EmmcSdmaMode) {
- if ((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul) {
- return EFI_INVALID_PARAMETER;
- }
-
- SdmaAddr = (UINT32)(UINTN)Trb->DataPhy;
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- } else if (Trb->Mode == EmmcAdmaMode) {
- AdmaAddr = (UINT64)(UINTN)Trb->AdmaDesc;
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- BlkSize = Trb->BlockSize;
- if (Trb->Mode == EmmcSdmaMode) {
- //
- // Set SDMA boundary to be 512K bytes.
- //
- BlkSize |= 0x7000;
- }
-
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_BLK_SIZE, FALSE, sizeof (BlkSize), &BlkSize);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- BlkCount = 0;
- if (Trb->Mode != EmmcNoData) {
- //
- // Calculate Block Count.
- //
- BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);
- }
-
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Argument = Packet->EmmcCmdBlk->CommandArgument;
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ARG1, FALSE, sizeof (Argument), &Argument);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- TransMode = 0;
- if (Trb->Mode != EmmcNoData) {
- if (Trb->Mode != EmmcPioMode) {
- TransMode |= BIT0;
- }
-
- if (Trb->Read) {
- TransMode |= BIT4;
- }
-
- if (BlkCount > 1) {
- TransMode |= BIT5 | BIT1;
- }
- }
-
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_TRANS_MOD, FALSE, sizeof (TransMode), &TransMode);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Cmd = (UINT16)LShiftU64 (Packet->EmmcCmdBlk->CommandIndex, 8);
- if (Packet->EmmcCmdBlk->CommandType == EmmcCommandTypeAdtc) {
- Cmd |= BIT5;
- }
-
- //
- // Convert ResponseType to value
- //
- if (Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeBc) {
- switch (Packet->EmmcCmdBlk->ResponseType) {
- case EmmcResponceTypeR1:
- case EmmcResponceTypeR5:
- case EmmcResponceTypeR6:
- case EmmcResponceTypeR7:
- Cmd |= (BIT1 | BIT3 | BIT4);
- break;
- case EmmcResponceTypeR2:
- Cmd |= (BIT0 | BIT3);
- break;
- case EmmcResponceTypeR3:
- case EmmcResponceTypeR4:
- Cmd |= BIT1;
- break;
- case EmmcResponceTypeR1b:
- case EmmcResponceTypeR5b:
- Cmd |= (BIT0 | BIT1 | BIT3 | BIT4);
- break;
- default:
- ASSERT (FALSE);
- break;
- }
- }
-
- //
- // Execute cmd
- //
- Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd);
- return Status;
-}
-
-/**
- Check the TRB execution result.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] Trb The pointer to the EMMC_TRB instance.
-
- @retval EFI_SUCCESS The TRB is executed successfully.
- @retval EFI_NOT_READY The TRB is not completed for execution.
- @retval Others Some erros happen when executing this request.
-
-**/
-EFI_STATUS
-EmmcPeimCheckTrbResult (
- IN UINTN Bar,
- IN EMMC_TRB *Trb
- )
-{
- EFI_STATUS Status;
- EMMC_COMMAND_PACKET *Packet;
- UINT16 IntStatus;
- UINT32 Response[4];
- UINT32 SdmaAddr;
- UINT8 Index;
- UINT8 SwReset;
- UINT32 PioLength;
-
- SwReset = 0;
- Packet = Trb->Packet;
- //
- // Check Trb execution result by reading Normal Interrupt Status register.
- //
- Status = EmmcPeimHcRwMmio (
- Bar + EMMC_HC_NOR_INT_STS,
- TRUE,
- sizeof (IntStatus),
- &IntStatus
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Check Transfer Complete bit is set or not.
- //
- if ((IntStatus & BIT1) == BIT1) {
- if ((IntStatus & BIT15) == BIT15) {
- //
- // Read Error Interrupt Status register to check if the error is
- // Data Timeout Error.
- // If yes, treat it as success as Transfer Complete has higher
- // priority than Data Timeout Error.
- //
- Status = EmmcPeimHcRwMmio (
- Bar + EMMC_HC_ERR_INT_STS,
- TRUE,
- sizeof (IntStatus),
- &IntStatus
- );
- if (!EFI_ERROR (Status)) {
- if ((IntStatus & BIT4) == BIT4) {
- Status = EFI_SUCCESS;
- } else {
- Status = EFI_DEVICE_ERROR;
- }
- }
- }
-
- goto Done;
- }
-
- //
- // Check if there is a error happened during cmd execution.
- // If yes, then do error recovery procedure to follow SD Host Controller
- // Simplified Spec 3.0 section 3.10.1.
- //
- if ((IntStatus & BIT15) == BIT15) {
- Status = EmmcPeimHcRwMmio (
- Bar + EMMC_HC_ERR_INT_STS,
- TRUE,
- sizeof (IntStatus),
- &IntStatus
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- if ((IntStatus & 0x0F) != 0) {
- SwReset |= BIT1;
- }
-
- if ((IntStatus & 0xF0) != 0) {
- SwReset |= BIT2;
- }
-
- Status = EmmcPeimHcRwMmio (
- Bar + EMMC_HC_SW_RST,
- FALSE,
- sizeof (SwReset),
- &SwReset
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = EmmcPeimHcWaitMmioSet (
- Bar + EMMC_HC_SW_RST,
- sizeof (SwReset),
- 0xFF,
- 0,
- EMMC_TIMEOUT
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
-
- //
- // Check if DMA interrupt is signalled for the SDMA transfer.
- //
- if ((Trb->Mode == EmmcSdmaMode) && ((IntStatus & BIT3) == BIT3)) {
- //
- // Clear DMA interrupt bit.
- //
- IntStatus = BIT3;
- Status = EmmcPeimHcRwMmio (
- Bar + EMMC_HC_NOR_INT_STS,
- FALSE,
- sizeof (IntStatus),
- &IntStatus
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Update SDMA Address register.
- //
- SdmaAddr = EMMC_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->DataPhy, EMMC_SDMA_BOUNDARY);
- Status = EmmcPeimHcRwMmio (
- Bar + EMMC_HC_SDMA_ADDR,
- FALSE,
- sizeof (UINT32),
- &SdmaAddr
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Trb->DataPhy = (UINT32)(UINTN)SdmaAddr;
- }
-
- if ((Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeAdtc) &&
- (Packet->EmmcCmdBlk->ResponseType != EmmcResponceTypeR1b) &&
- (Packet->EmmcCmdBlk->ResponseType != EmmcResponceTypeR5b))
- {
- if ((IntStatus & BIT0) == BIT0) {
- Status = EFI_SUCCESS;
- goto Done;
- }
- }
-
- if (Packet->EmmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK) {
- //
- // When performing tuning procedure (Execute Tuning is set to 1) through PIO mode,
- // wait Buffer Read Ready bit of Normal Interrupt Status Register to be 1.
- // Refer to SD Host Controller Simplified Specification 3.0 figure 2-29 for details.
- //
- if ((IntStatus & BIT5) == BIT5) {
- //
- // Clear Buffer Read Ready interrupt at first.
- //
- IntStatus = BIT5;
- EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
- //
- // Read data out from Buffer Port register
- //
- for (PioLength = 0; PioLength < Trb->DataLen; PioLength += 4) {
- EmmcPeimHcRwMmio (Bar + EMMC_HC_BUF_DAT_PORT, TRUE, 4, (UINT8 *)Trb->Data + PioLength);
- }
-
- Status = EFI_SUCCESS;
- goto Done;
- }
- }
-
- Status = EFI_NOT_READY;
-Done:
- //
- // Get response data when the cmd is executed successfully.
- //
- if (!EFI_ERROR (Status)) {
- if (Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeBc) {
- for (Index = 0; Index < 4; Index++) {
- Status = EmmcPeimHcRwMmio (
- Bar + EMMC_HC_RESPONSE + Index * 4,
- TRUE,
- sizeof (UINT32),
- &Response[Index]
- );
- if (EFI_ERROR (Status)) {
- EmmcPeimHcLedOnOff (Bar, FALSE);
- return Status;
- }
- }
-
- CopyMem (Packet->EmmcStatusBlk, Response, sizeof (Response));
- }
- }
-
- if (Status != EFI_NOT_READY) {
- EmmcPeimHcLedOnOff (Bar, FALSE);
- }
-
- return Status;
-}
-
-/**
- Wait for the TRB execution result.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] Trb The pointer to the EMMC_TRB instance.
-
- @retval EFI_SUCCESS The TRB is executed successfully.
- @retval Others Some erros happen when executing this request.
-
-**/
-EFI_STATUS
-EmmcPeimWaitTrbResult (
- IN UINTN Bar,
- IN EMMC_TRB *Trb
- )
-{
- EFI_STATUS Status;
- EMMC_COMMAND_PACKET *Packet;
- UINT64 Timeout;
- BOOLEAN InfiniteWait;
-
- Packet = Trb->Packet;
- //
- // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register
- //
- Timeout = Packet->Timeout;
- if (Timeout == 0) {
- InfiniteWait = TRUE;
- } else {
- InfiniteWait = FALSE;
- }
-
- while (InfiniteWait || (Timeout > 0)) {
- //
- // Check Trb execution result by reading Normal Interrupt Status register.
- //
- Status = EmmcPeimCheckTrbResult (Bar, Trb);
- if (Status != EFI_NOT_READY) {
- return Status;
- }
-
- //
- // Stall for 1 microsecond.
- //
- MicroSecondDelay (1);
-
- Timeout--;
- }
-
- return EFI_TIMEOUT;
-}
-
-/**
- Sends EMMC command to an EMMC card that is attached to the EMMC controller.
-
- If Packet is successfully sent to the EMMC card, then EFI_SUCCESS is returned.
-
- If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.
-
- If Slot is not in a valid range for the EMMC controller, then EFI_INVALID_PARAMETER
- is returned.
-
- If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,
- EFI_INVALID_PARAMETER is returned.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in,out] Packet A pointer to the EMMC command data structure.
-
- @retval EFI_SUCCESS The EMMC Command Packet was sent by the host.
- @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD
- command Packet.
- @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.
- @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and
- OutDataBuffer are NULL.
- @retval EFI_NO_MEDIA SD Device not present in the Slot.
- @retval EFI_UNSUPPORTED The command described by the EMMC Command Packet is not
- supported by the host controller.
- @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the
- limit supported by EMMC card ( i.e. if the number of bytes
- exceed the Last LBA).
-
-**/
-EFI_STATUS
-EFIAPI
-EmmcPeimExecCmd (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN OUT EMMC_COMMAND_PACKET *Packet
- )
-{
- EFI_STATUS Status;
- EMMC_TRB *Trb;
-
- if (Packet == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if ((Packet->EmmcCmdBlk == NULL) || (Packet->EmmcStatusBlk == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Trb = EmmcPeimCreateTrb (Slot, Packet);
- if (Trb == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Status = EmmcPeimWaitTrbEnv (Slot->EmmcHcBase, Trb);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = EmmcPeimExecTrb (Slot->EmmcHcBase, Trb);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = EmmcPeimWaitTrbResult (Slot->EmmcHcBase, Trb);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
-Done:
- EmmcPeimFreeTrb (Trb);
-
- return Status;
-}
-
-/**
- Send command GO_IDLE_STATE (CMD0 with argument of 0x00000000) to the device to
- make it go to Idle State.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
-
- @retval EFI_SUCCESS The EMMC device is reset correctly.
- @retval Others The device reset fails.
-
-**/
-EFI_STATUS
-EmmcPeimReset (
- IN EMMC_PEIM_HC_SLOT *Slot
- )
-{
- EMMC_COMMAND_BLOCK EmmcCmdBlk;
- EMMC_STATUS_BLOCK EmmcStatusBlk;
- EMMC_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
- ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.EmmcCmdBlk = &EmmcCmdBlk;
- Packet.EmmcStatusBlk = &EmmcStatusBlk;
- Packet.Timeout = EMMC_TIMEOUT;
-
- EmmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE;
- EmmcCmdBlk.CommandType = EmmcCommandTypeBc;
- EmmcCmdBlk.ResponseType = 0;
- EmmcCmdBlk.CommandArgument = 0;
-
- Status = EmmcPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Send command SEND_OP_COND to the EMMC device to get the data of the OCR register.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in, out] Argument On input, the argument of SEND_OP_COND is to send to the device.
- On output, the argument is the value of OCR register.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimGetOcr (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN OUT UINT32 *Argument
- )
-{
- EMMC_COMMAND_BLOCK EmmcCmdBlk;
- EMMC_STATUS_BLOCK EmmcStatusBlk;
- EMMC_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
- ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.EmmcCmdBlk = &EmmcCmdBlk;
- Packet.EmmcStatusBlk = &EmmcStatusBlk;
- Packet.Timeout = EMMC_TIMEOUT;
-
- EmmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND;
- EmmcCmdBlk.CommandType = EmmcCommandTypeBcr;
- EmmcCmdBlk.ResponseType = EmmcResponceTypeR3;
- EmmcCmdBlk.CommandArgument = *Argument;
-
- Status = EmmcPeimExecCmd (Slot, &Packet);
- if (!EFI_ERROR (Status)) {
- //
- // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
- //
- *Argument = EmmcStatusBlk.Resp0;
- }
-
- return Status;
-}
-
-/**
- Broadcast command ALL_SEND_CID to the bus to ask all the EMMC devices to send the
- data of their CID registers.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimGetAllCid (
- IN EMMC_PEIM_HC_SLOT *Slot
- )
-{
- EMMC_COMMAND_BLOCK EmmcCmdBlk;
- EMMC_STATUS_BLOCK EmmcStatusBlk;
- EMMC_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
- ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.EmmcCmdBlk = &EmmcCmdBlk;
- Packet.EmmcStatusBlk = &EmmcStatusBlk;
- Packet.Timeout = EMMC_TIMEOUT;
-
- EmmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID;
- EmmcCmdBlk.CommandType = EmmcCommandTypeBcr;
- EmmcCmdBlk.ResponseType = EmmcResponceTypeR2;
- EmmcCmdBlk.CommandArgument = 0;
-
- Status = EmmcPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Send command SET_RELATIVE_ADDR to the EMMC device to assign a Relative device
- Address (RCA).
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] Rca The relative device address to be assigned.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimSetRca (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN UINT32 Rca
- )
-{
- EMMC_COMMAND_BLOCK EmmcCmdBlk;
- EMMC_STATUS_BLOCK EmmcStatusBlk;
- EMMC_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
- ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.EmmcCmdBlk = &EmmcCmdBlk;
- Packet.EmmcStatusBlk = &EmmcStatusBlk;
- Packet.Timeout = EMMC_TIMEOUT;
-
- EmmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR;
- EmmcCmdBlk.CommandType = EmmcCommandTypeAc;
- EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;
- EmmcCmdBlk.CommandArgument = Rca << 16;
-
- Status = EmmcPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Send command SEND_CSD to the EMMC device to get the data of the CSD register.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] Rca The relative device address of selected device.
- @param[out] Csd The buffer to store the content of the CSD register.
- Note the caller should ignore the lowest byte of this
- buffer as the content of this byte is meaningless even
- if the operation succeeds.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimGetCsd (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN UINT32 Rca,
- OUT EMMC_CSD *Csd
- )
-{
- EMMC_COMMAND_BLOCK EmmcCmdBlk;
- EMMC_STATUS_BLOCK EmmcStatusBlk;
- EMMC_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
- ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.EmmcCmdBlk = &EmmcCmdBlk;
- Packet.EmmcStatusBlk = &EmmcStatusBlk;
- Packet.Timeout = EMMC_TIMEOUT;
-
- EmmcCmdBlk.CommandIndex = EMMC_SEND_CSD;
- EmmcCmdBlk.CommandType = EmmcCommandTypeAc;
- EmmcCmdBlk.ResponseType = EmmcResponceTypeR2;
- EmmcCmdBlk.CommandArgument = Rca << 16;
-
- Status = EmmcPeimExecCmd (Slot, &Packet);
- if (!EFI_ERROR (Status)) {
- //
- // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
- //
- CopyMem (((UINT8 *)Csd) + 1, &EmmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);
- }
-
- return Status;
-}
-
-/**
- Send command SELECT_DESELECT_CARD to the EMMC device to select/deselect it.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] Rca The relative device address of selected device.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimSelect (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN UINT32 Rca
- )
-{
- EMMC_COMMAND_BLOCK EmmcCmdBlk;
- EMMC_STATUS_BLOCK EmmcStatusBlk;
- EMMC_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
- ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.EmmcCmdBlk = &EmmcCmdBlk;
- Packet.EmmcStatusBlk = &EmmcStatusBlk;
- Packet.Timeout = EMMC_TIMEOUT;
-
- EmmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;
- EmmcCmdBlk.CommandType = EmmcCommandTypeAc;
- EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;
- EmmcCmdBlk.CommandArgument = Rca << 16;
-
- Status = EmmcPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Send command SEND_EXT_CSD to the EMMC device to get the data of the EXT_CSD register.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[out] ExtCsd The buffer to store the content of the EXT_CSD register.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimGetExtCsd (
- IN EMMC_PEIM_HC_SLOT *Slot,
- OUT EMMC_EXT_CSD *ExtCsd
- )
-{
- EMMC_COMMAND_BLOCK EmmcCmdBlk;
- EMMC_STATUS_BLOCK EmmcStatusBlk;
- EMMC_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
- ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.EmmcCmdBlk = &EmmcCmdBlk;
- Packet.EmmcStatusBlk = &EmmcStatusBlk;
- Packet.Timeout = EMMC_TIMEOUT;
-
- EmmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;
- EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc;
- EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;
- EmmcCmdBlk.CommandArgument = 0x00000000;
-
- Packet.InDataBuffer = ExtCsd;
- Packet.InTransferLength = sizeof (EMMC_EXT_CSD);
-
- Status = EmmcPeimExecCmd (Slot, &Packet);
- return Status;
-}
-
-/**
- Send command SWITCH to the EMMC device to switch the mode of operation of the
- selected Device or modifies the EXT_CSD registers.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] Access The access mode of SWITCH command.
- @param[in] Index The offset of the field to be access.
- @param[in] Value The value to be set to the specified field of EXT_CSD register.
- @param[in] CmdSet The value of CmdSet field of EXT_CSD register.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimSwitch (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN UINT8 Access,
- IN UINT8 Index,
- IN UINT8 Value,
- IN UINT8 CmdSet
- )
-{
- EMMC_COMMAND_BLOCK EmmcCmdBlk;
- EMMC_STATUS_BLOCK EmmcStatusBlk;
- EMMC_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
- ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.EmmcCmdBlk = &EmmcCmdBlk;
- Packet.EmmcStatusBlk = &EmmcStatusBlk;
- Packet.Timeout = EMMC_TIMEOUT;
-
- EmmcCmdBlk.CommandIndex = EMMC_SWITCH;
- EmmcCmdBlk.CommandType = EmmcCommandTypeAc;
- EmmcCmdBlk.ResponseType = EmmcResponceTypeR1b;
- EmmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | (Value << 8) | CmdSet;
-
- Status = EmmcPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Send command SEND_STATUS to the addressed EMMC device to get its status register.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] Rca The relative device address of addressed device.
- @param[out] DevStatus The returned device status.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimSendStatus (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN UINT32 Rca,
- OUT UINT32 *DevStatus
- )
-{
- EMMC_COMMAND_BLOCK EmmcCmdBlk;
- EMMC_STATUS_BLOCK EmmcStatusBlk;
- EMMC_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
- ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.EmmcCmdBlk = &EmmcCmdBlk;
- Packet.EmmcStatusBlk = &EmmcStatusBlk;
- Packet.Timeout = EMMC_TIMEOUT;
-
- EmmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;
- EmmcCmdBlk.CommandType = EmmcCommandTypeAc;
- EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;
- EmmcCmdBlk.CommandArgument = Rca << 16;
-
- Status = EmmcPeimExecCmd (Slot, &Packet);
- if (!EFI_ERROR (Status)) {
- *DevStatus = EmmcStatusBlk.Resp0;
- }
-
- return Status;
-}
-
-/**
- Send command SET_BLOCK_COUNT to the addressed EMMC device to set the number of
- blocks for the following block read/write cmd.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] BlockCount The number of the logical block to access.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimSetBlkCount (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN UINT16 BlockCount
- )
-{
- EMMC_COMMAND_BLOCK EmmcCmdBlk;
- EMMC_STATUS_BLOCK EmmcStatusBlk;
- EMMC_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
- ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.EmmcCmdBlk = &EmmcCmdBlk;
- Packet.EmmcStatusBlk = &EmmcStatusBlk;
- Packet.Timeout = EMMC_TIMEOUT;
-
- EmmcCmdBlk.CommandIndex = EMMC_SET_BLOCK_COUNT;
- EmmcCmdBlk.CommandType = EmmcCommandTypeAc;
- EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;
- EmmcCmdBlk.CommandArgument = BlockCount;
-
- Status = EmmcPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed EMMC device
- to read/write the specified number of blocks.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] Lba The logical block address of starting access.
- @param[in] BlockSize The block size of specified EMMC device partition.
- @param[in] Buffer The pointer to the transfer buffer.
- @param[in] BufferSize The size of transfer buffer.
- @param[in] IsRead Boolean to show the operation direction.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimRwMultiBlocks (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN EFI_LBA Lba,
- IN UINT32 BlockSize,
- IN VOID *Buffer,
- IN UINTN BufferSize,
- IN BOOLEAN IsRead
- )
-{
- EMMC_COMMAND_BLOCK EmmcCmdBlk;
- EMMC_STATUS_BLOCK EmmcStatusBlk;
- EMMC_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
- ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.EmmcCmdBlk = &EmmcCmdBlk;
- Packet.EmmcStatusBlk = &EmmcStatusBlk;
- //
- // 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.
- //
- Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
-
- if (IsRead) {
- Packet.InDataBuffer = Buffer;
- Packet.InTransferLength = (UINT32)BufferSize;
-
- EmmcCmdBlk.CommandIndex = EMMC_READ_MULTIPLE_BLOCK;
- EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc;
- EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;
- } else {
- Packet.OutDataBuffer = Buffer;
- Packet.OutTransferLength = (UINT32)BufferSize;
-
- EmmcCmdBlk.CommandIndex = EMMC_WRITE_MULTIPLE_BLOCK;
- EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc;
- EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;
- }
-
- if (Slot->SectorAddressing) {
- EmmcCmdBlk.CommandArgument = (UINT32)Lba;
- } else {
- EmmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, BlockSize);
- }
-
- Status = EmmcPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Send command SEND_TUNING_BLOCK to the EMMC device for HS200 optimal sampling point
- detection.
-
- It may be sent up to 40 times until the host finishes the tuning procedure.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] BusWidth The bus width to work.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimSendTuningBlk (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN UINT8 BusWidth
- )
-{
- EMMC_COMMAND_BLOCK EmmcCmdBlk;
- EMMC_STATUS_BLOCK EmmcStatusBlk;
- EMMC_COMMAND_PACKET Packet;
- EFI_STATUS Status;
- UINT8 TuningBlock[128];
-
- ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));
- ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.EmmcCmdBlk = &EmmcCmdBlk;
- Packet.EmmcStatusBlk = &EmmcStatusBlk;
- Packet.Timeout = EMMC_TIMEOUT;
-
- EmmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK;
- EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc;
- EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;
- EmmcCmdBlk.CommandArgument = 0;
-
- Packet.InDataBuffer = TuningBlock;
- if (BusWidth == 8) {
- Packet.InTransferLength = sizeof (TuningBlock);
- } else {
- Packet.InTransferLength = 64;
- }
-
- Status = EmmcPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Tuning the clock to get HS200 optimal sampling point.
-
- Command SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the
- tuning procedure.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
- Simplified Spec 3.0 section Figure 2-29 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] BusWidth The bus width to work.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimTuningClkForHs200 (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN UINT8 BusWidth
- )
-{
- EFI_STATUS Status;
- UINT8 HostCtrl2;
- UINT8 Retry;
-
- //
- // Notify the host that the sampling clock tuning procedure starts.
- //
- HostCtrl2 = BIT6;
- Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.
- //
- Retry = 0;
- do {
- Status = EmmcPeimSendTuningBlk (Slot, BusWidth);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = EmmcPeimHcRwMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if ((HostCtrl2 & (BIT6 | BIT7)) == 0) {
- break;
- }
-
- if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {
- return EFI_SUCCESS;
- }
- } while (++Retry < 40);
-
- DEBUG ((DEBUG_ERROR, "EmmcPeimTuningClkForHs200: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2));
- //
- // Abort the tuning procedure and reset the tuning circuit.
- //
- HostCtrl2 = (UINT8) ~(BIT6 | BIT7);
- Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- return EFI_DEVICE_ERROR;
-}
-
-/**
- Switch the bus width to specified width.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9 and SD Host Controller
- Simplified Spec 3.0 section Figure 3-7 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] Rca The relative device address to be assigned.
- @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise
- use single data rate data simpling method.
- @param[in] BusWidth The bus width to be set, it could be 4 or 8.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimSwitchBusWidth (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN UINT32 Rca,
- IN BOOLEAN IsDdr,
- IN UINT8 BusWidth
- )
-{
- EFI_STATUS Status;
- UINT8 Access;
- UINT8 Index;
- UINT8 Value;
- UINT8 CmdSet;
- UINT32 DevStatus;
-
- //
- // Write Byte, the Value field is written into the byte pointed by Index.
- //
- Access = 0x03;
- Index = OFFSET_OF (EMMC_EXT_CSD, BusWidth);
- if (BusWidth == 4) {
- Value = 1;
- } else if (BusWidth == 8) {
- Value = 2;
- } else {
- return EFI_INVALID_PARAMETER;
- }
-
- if (IsDdr) {
- Value += 4;
- }
-
- CmdSet = 0;
- Status = EmmcPeimSwitch (Slot, Access, Index, Value, CmdSet);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = EmmcPeimSendStatus (Slot, Rca, &DevStatus);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Check the switch operation is really successful or not.
- //
- if ((DevStatus & BIT7) != 0) {
- return EFI_DEVICE_ERROR;
- }
-
- Status = EmmcPeimHcSetBusWidth (Slot->EmmcHcBase, BusWidth);
-
- return Status;
-}
-
-/**
- Switch the clock frequency to the specified value.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.6 and SD Host Controller
- Simplified Spec 3.0 section Figure 3-3 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] Rca The relative device address to be assigned.
- @param[in] HsTiming The value to be written to HS_TIMING field of EXT_CSD register.
- @param[in] ClockFreq The max clock frequency to be set, the unit is MHz.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimSwitchClockFreq (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN UINT32 Rca,
- IN UINT8 HsTiming,
- IN UINT32 ClockFreq
- )
-{
- EFI_STATUS Status;
- UINT8 Access;
- UINT8 Index;
- UINT8 Value;
- UINT8 CmdSet;
- UINT32 DevStatus;
-
- //
- // Write Byte, the Value field is written into the byte pointed by Index.
- //
- Access = 0x03;
- Index = OFFSET_OF (EMMC_EXT_CSD, HsTiming);
- Value = HsTiming;
- CmdSet = 0;
-
- Status = EmmcPeimSwitch (Slot, Access, Index, Value, CmdSet);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = EmmcPeimSendStatus (Slot, Rca, &DevStatus);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Check the switch operation is really successful or not.
- //
- if ((DevStatus & BIT7) != 0) {
- return EFI_DEVICE_ERROR;
- }
-
- //
- // Convert the clock freq unit from MHz to KHz.
- //
- Status = EmmcPeimHcClockSupply (Slot->EmmcHcBase, ClockFreq * 1000);
-
- return Status;
-}
-
-/**
- Switch to the High Speed timing according to request.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
- Simplified Spec 3.0 section Figure 2-29 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] Rca The relative device address to be assigned.
- @param[in] ClockFreq The max clock frequency to be set.
- @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise
- use single data rate data simpling method.
- @param[in] BusWidth The bus width to be set, it could be 4 or 8.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimSwitchToHighSpeed (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN UINT32 Rca,
- IN UINT32 ClockFreq,
- IN BOOLEAN IsDdr,
- IN UINT8 BusWidth
- )
-{
- EFI_STATUS Status;
- UINT8 HsTiming;
- UINT8 HostCtrl1;
- UINT8 HostCtrl2;
-
- Status = EmmcPeimSwitchBusWidth (Slot, Rca, IsDdr, BusWidth);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Set to High Speed timing
- //
- HostCtrl1 = BIT2;
- Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- HostCtrl2 = (UINT8) ~0x7;
- Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (IsDdr) {
- HostCtrl2 = BIT2;
- } else if (ClockFreq == 52) {
- HostCtrl2 = BIT0;
- } else {
- HostCtrl2 = 0;
- }
-
- Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- HsTiming = 1;
- Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq);
-
- return Status;
-}
-
-/**
- Switch to the HS200 timing according to request.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
- Simplified Spec 3.0 section Figure 2-29 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] Rca The relative device address to be assigned.
- @param[in] ClockFreq The max clock frequency to be set.
- @param[in] BusWidth The bus width to be set, it could be 4 or 8.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimSwitchToHS200 (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN UINT32 Rca,
- IN UINT32 ClockFreq,
- IN UINT8 BusWidth
- )
-{
- EFI_STATUS Status;
- UINT8 HsTiming;
- UINT8 HostCtrl2;
- UINT16 ClockCtrl;
-
- if ((BusWidth != 4) && (BusWidth != 8)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Status = EmmcPeimSwitchBusWidth (Slot, Rca, FALSE, BusWidth);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Set to HS200/SDR104 timing
- //
- //
- // Stop bus clock at first
- //
- Status = EmmcPeimHcStopClock (Slot->EmmcHcBase);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- HostCtrl2 = (UINT8) ~0x7;
- Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- HostCtrl2 = BIT0 | BIT1;
- Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Wait Internal Clock Stable in the Clock Control register to be 1 before set SD Clock Enable bit
- //
- Status = EmmcPeimHcWaitMmioSet (
- Slot->EmmcHcBase + EMMC_HC_CLOCK_CTRL,
- sizeof (ClockCtrl),
- BIT1,
- BIT1,
- EMMC_TIMEOUT
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Set SD Clock Enable in the Clock Control register to 1
- //
- ClockCtrl = BIT2;
- Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
-
- HsTiming = 2;
- Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = EmmcPeimTuningClkForHs200 (Slot, BusWidth);
-
- return Status;
-}
-
-/**
- Switch to the HS400 timing according to request.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
- Simplified Spec 3.0 section Figure 2-29 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] Rca The relative device address to be assigned.
- @param[in] ClockFreq The max clock frequency to be set.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimSwitchToHS400 (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN UINT32 Rca,
- IN UINT32 ClockFreq
- )
-{
- EFI_STATUS Status;
- UINT8 HsTiming;
- UINT8 HostCtrl2;
-
- Status = EmmcPeimSwitchToHS200 (Slot, Rca, ClockFreq, 8);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Set to High Speed timing and set the clock frequency to a value less than 52MHz.
- //
- HsTiming = 1;
- Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, 52);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // HS400 mode must use 8 data lines.
- //
- Status = EmmcPeimSwitchBusWidth (Slot, Rca, TRUE, 8);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Set to HS400 timing
- //
- HostCtrl2 = (UINT8) ~0x7;
- Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- HostCtrl2 = BIT0 | BIT2;
- Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- HsTiming = 3;
- Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq);
-
- return Status;
-}
-
-/**
- Switch the high speed timing according to request.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller
- Simplified Spec 3.0 section Figure 2-29 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] Rca The relative device address to be assigned.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimSetBusMode (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN UINT32 Rca
- )
-{
- EFI_STATUS Status;
- EMMC_HC_SLOT_CAP Capability;
- UINT8 HsTiming;
- BOOLEAN IsDdr;
- UINT32 ClockFreq;
- UINT8 BusWidth;
-
- Status = EmmcPeimGetCsd (Slot, Rca, &Slot->Csd);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "EmmcPeimSetBusMode: EmmcPeimGetCsd fails with %r\n", Status));
- return Status;
- }
-
- if ((Slot->Csd.CSizeLow | Slot->Csd.CSizeHigh << 2) == 0xFFF) {
- Slot->SectorAddressing = TRUE;
- } else {
- Slot->SectorAddressing = FALSE;
- }
-
- Status = EmmcPeimSelect (Slot, Rca);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "EmmcPeimSetBusMode: EmmcPeimSelect fails with %r\n", Status));
- return Status;
- }
-
- Status = EmmcPeimHcGetCapability (Slot->EmmcHcBase, &Capability);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "EmmcPeimSetBusMode: EmmcPeimHcGetCapability fails with %r\n", Status));
- return Status;
- }
-
- ASSERT (Capability.BaseClkFreq != 0);
- //
- // Check if the Host Controller support 8bits bus width.
- //
- if (Capability.BusWidth8 != 0) {
- BusWidth = 8;
- } else {
- BusWidth = 4;
- }
-
- //
- // Get Device_Type from EXT_CSD register.
- //
- Status = EmmcPeimGetExtCsd (Slot, &Slot->ExtCsd);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "EmmcPeimSetBusMode: EmmcPeimGetExtCsd fails with %r\n", Status));
- return Status;
- }
-
- //
- // Calculate supported bus speed/bus width/clock frequency.
- //
- HsTiming = 0;
- IsDdr = FALSE;
- ClockFreq = 0;
- if (((Slot->ExtCsd.DeviceType & (BIT4 | BIT5)) != 0) && (Capability.Sdr104 != 0)) {
- HsTiming = 2;
- IsDdr = FALSE;
- ClockFreq = 200;
- } else if (((Slot->ExtCsd.DeviceType & (BIT2 | BIT3)) != 0) && (Capability.Ddr50 != 0)) {
- HsTiming = 1;
- IsDdr = TRUE;
- ClockFreq = 52;
- } else if (((Slot->ExtCsd.DeviceType & BIT1) != 0) && (Capability.HighSpeed != 0)) {
- HsTiming = 1;
- IsDdr = FALSE;
- ClockFreq = 52;
- } else if (((Slot->ExtCsd.DeviceType & BIT0) != 0) && (Capability.HighSpeed != 0)) {
- HsTiming = 1;
- IsDdr = FALSE;
- ClockFreq = 26;
- }
-
- //
- // Check if both of the device and the host controller support HS400 DDR mode.
- //
- if (((Slot->ExtCsd.DeviceType & (BIT6 | BIT7)) != 0) && (Capability.Hs400 != 0)) {
- //
- // The host controller supports 8bits bus.
- //
- ASSERT (BusWidth == 8);
- HsTiming = 3;
- IsDdr = TRUE;
- ClockFreq = 200;
- }
-
- if ((ClockFreq == 0) || (HsTiming == 0)) {
- //
- // Continue using default setting.
- //
- return EFI_SUCCESS;
- }
-
- DEBUG ((DEBUG_INFO, "HsTiming %d ClockFreq %d BusWidth %d Ddr %a\n", HsTiming, ClockFreq, BusWidth, IsDdr ? "TRUE" : "FALSE"));
-
- if (HsTiming == 3) {
- //
- // Execute HS400 timing switch procedure
- //
- Status = EmmcPeimSwitchToHS400 (Slot, Rca, ClockFreq);
- } else if (HsTiming == 2) {
- //
- // Execute HS200 timing switch procedure
- //
- Status = EmmcPeimSwitchToHS200 (Slot, Rca, ClockFreq, BusWidth);
- } else {
- //
- // Execute High Speed timing switch procedure
- //
- Status = EmmcPeimSwitchToHighSpeed (Slot, Rca, ClockFreq, IsDdr, BusWidth);
- }
-
- return Status;
-}
-
-/**
- Execute EMMC device identification procedure.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
-
- @retval EFI_SUCCESS There is a EMMC card.
- @retval Others There is not a EMMC card.
-
-**/
-EFI_STATUS
-EmmcPeimIdentification (
- IN EMMC_PEIM_HC_SLOT *Slot
- )
-{
- EFI_STATUS Status;
- UINT32 Ocr;
- UINT32 Rca;
- UINTN Retry;
-
- Status = EmmcPeimReset (Slot);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "EmmcPeimIdentification: EmmcPeimReset fails with %r\n", Status));
- return Status;
- }
-
- Ocr = 0;
- Retry = 0;
- do {
- Status = EmmcPeimGetOcr (Slot, &Ocr);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "EmmcPeimIdentification: EmmcPeimGetOcr fails with %r\n", Status));
- return Status;
- }
-
- if (Retry++ == 100) {
- DEBUG ((DEBUG_ERROR, "EmmcPeimIdentification: EmmcPeimGetOcr fails too many times\n"));
- return EFI_DEVICE_ERROR;
- }
-
- MicroSecondDelay (10 * 1000);
- } while ((Ocr & BIT31) == 0);
-
- Status = EmmcPeimGetAllCid (Slot);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "EmmcPeimIdentification: EmmcPeimGetAllCid fails with %r\n", Status));
- return Status;
- }
-
- //
- // Don't support multiple devices on the slot, that is
- // shared bus slot feature.
- //
- Rca = 1;
- Status = EmmcPeimSetRca (Slot, Rca);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "EmmcPeimIdentification: EmmcPeimSetRca fails with %r\n", Status));
- return Status;
- }
-
- //
- // Enter Data Tranfer Mode.
- //
- DEBUG ((DEBUG_INFO, "Found a EMMC device at slot [%d], RCA [%d]\n", Slot, Rca));
-
- Status = EmmcPeimSetBusMode (Slot, Rca);
-
- return Status;
-}
+/** @file + + Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "EmmcBlockIoPei.h" + +/** + Read/Write specified EMMC host controller mmio register. + + @param[in] Address The address of the mmio register to be read/written. + @param[in] Read A boolean to indicate it's read or write operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in, out] Data For read operations, the destination buffer to store + the results. For write operations, the source buffer + to write data from. The caller is responsible for + having ownership of the data buffer and ensuring its + size not less than Count bytes. + + @retval EFI_INVALID_PARAMETER The Address or the Data or the Count is not valid. + @retval EFI_SUCCESS The read/write operation succeeds. + @retval Others The read/write operation fails. + +**/ +EFI_STATUS +EFIAPI +EmmcPeimHcRwMmio ( + IN UINTN Address, + IN BOOLEAN Read, + IN UINT8 Count, + IN OUT VOID *Data + ) +{ + if ((Address == 0) || (Data == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) { + return EFI_INVALID_PARAMETER; + } + + switch (Count) { + case 1: + if (Read) { + *(UINT8 *)Data = MmioRead8 (Address); + } else { + MmioWrite8 (Address, *(UINT8 *)Data); + } + + break; + case 2: + if (Read) { + *(UINT16 *)Data = MmioRead16 (Address); + } else { + MmioWrite16 (Address, *(UINT16 *)Data); + } + + break; + case 4: + if (Read) { + *(UINT32 *)Data = MmioRead32 (Address); + } else { + MmioWrite32 (Address, *(UINT32 *)Data); + } + + break; + case 8: + if (Read) { + *(UINT64 *)Data = MmioRead64 (Address); + } else { + MmioWrite64 (Address, *(UINT64 *)Data); + } + + break; + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +/** + Do OR operation with the value of the specified EMMC host controller mmio register. + + @param[in] Address The address of the mmio register to be read/written. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in] OrData The pointer to the data used to do OR operation. + The caller is responsible for having ownership of + the data buffer and ensuring its size not less than + Count bytes. + + @retval EFI_INVALID_PARAMETER The Address or the OrData or the Count is not valid. + @retval EFI_SUCCESS The OR operation succeeds. + @retval Others The OR operation fails. + +**/ +EFI_STATUS +EFIAPI +EmmcPeimHcOrMmio ( + IN UINTN Address, + IN UINT8 Count, + IN VOID *OrData + ) +{ + EFI_STATUS Status; + UINT64 Data; + UINT64 Or; + + Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Data); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Count == 1) { + Or = *(UINT8 *)OrData; + } else if (Count == 2) { + Or = *(UINT16 *)OrData; + } else if (Count == 4) { + Or = *(UINT32 *)OrData; + } else if (Count == 8) { + Or = *(UINT64 *)OrData; + } else { + return EFI_INVALID_PARAMETER; + } + + Data |= Or; + Status = EmmcPeimHcRwMmio (Address, FALSE, Count, &Data); + + return Status; +} + +/** + Do AND operation with the value of the specified EMMC host controller mmio register. + + @param[in] Address The address of the mmio register to be read/written. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in] AndData The pointer to the data used to do AND operation. + The caller is responsible for having ownership of + the data buffer and ensuring its size not less than + Count bytes. + + @retval EFI_INVALID_PARAMETER The Address or the AndData or the Count is not valid. + @retval EFI_SUCCESS The AND operation succeeds. + @retval Others The AND operation fails. + +**/ +EFI_STATUS +EFIAPI +EmmcPeimHcAndMmio ( + IN UINTN Address, + IN UINT8 Count, + IN VOID *AndData + ) +{ + EFI_STATUS Status; + UINT64 Data; + UINT64 And; + + Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Data); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Count == 1) { + And = *(UINT8 *)AndData; + } else if (Count == 2) { + And = *(UINT16 *)AndData; + } else if (Count == 4) { + And = *(UINT32 *)AndData; + } else if (Count == 8) { + And = *(UINT64 *)AndData; + } else { + return EFI_INVALID_PARAMETER; + } + + Data &= And; + Status = EmmcPeimHcRwMmio (Address, FALSE, Count, &Data); + + return Status; +} + +/** + Wait for the value of the specified MMIO register set to the test value. + + @param[in] Address The address of the mmio register to be checked. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2, 4 or 8 bytes. + @param[in] MaskValue The mask value of memory. + @param[in] TestValue The test value of memory. + + @retval EFI_NOT_READY The MMIO register hasn't set to the expected value. + @retval EFI_SUCCESS The MMIO register has expected value. + @retval Others The MMIO operation fails. + +**/ +EFI_STATUS +EFIAPI +EmmcPeimHcCheckMmioSet ( + IN UINTN Address, + IN UINT8 Count, + IN UINT64 MaskValue, + IN UINT64 TestValue + ) +{ + EFI_STATUS Status; + UINT64 Value; + + // + // Access PCI MMIO space to see if the value is the tested one. + // + Value = 0; + Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Value); + if (EFI_ERROR (Status)) { + return Status; + } + + Value &= MaskValue; + + if (Value == TestValue) { + return EFI_SUCCESS; + } + + return EFI_NOT_READY; +} + +/** + Wait for the value of the specified MMIO register set to the test value. + + @param[in] Address The address of the mmio register to wait. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2, 4 or 8 bytes. + @param[in] MaskValue The mask value of memory. + @param[in] TestValue The test value of memory. + @param[in] Timeout The time out value for wait memory set, uses 1 + microsecond as a unit. + + @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout + range. + @retval EFI_SUCCESS The MMIO register has expected value. + @retval Others The MMIO operation fails. + +**/ +EFI_STATUS +EFIAPI +EmmcPeimHcWaitMmioSet ( + IN UINTN Address, + IN UINT8 Count, + IN UINT64 MaskValue, + IN UINT64 TestValue, + IN UINT64 Timeout + ) +{ + EFI_STATUS Status; + BOOLEAN InfiniteWait; + + if (Timeout == 0) { + InfiniteWait = TRUE; + } else { + InfiniteWait = FALSE; + } + + while (InfiniteWait || (Timeout > 0)) { + Status = EmmcPeimHcCheckMmioSet ( + Address, + Count, + MaskValue, + TestValue + ); + if (Status != EFI_NOT_READY) { + return Status; + } + + // + // Stall for 1 microsecond. + // + MicroSecondDelay (1); + + Timeout--; + } + + return EFI_TIMEOUT; +} + +/** + Software reset the specified EMMC host controller and enable all interrupts. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The software reset executes successfully. + @retval Others The software reset fails. + +**/ +EFI_STATUS +EmmcPeimHcReset ( + IN UINTN Bar + ) +{ + EFI_STATUS Status; + UINT8 SwReset; + + SwReset = 0xFF; + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcPeimHcReset: write full 1 fails: %r\n", Status)); + return Status; + } + + Status = EmmcPeimHcWaitMmioSet ( + Bar + EMMC_HC_SW_RST, + sizeof (SwReset), + 0xFF, + 0x00, + EMMC_TIMEOUT + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "EmmcPeimHcReset: reset done with %r\n", Status)); + return Status; + } + + // + // Enable all interrupt after reset all. + // + Status = EmmcPeimHcEnableInterrupt (Bar); + + return Status; +} + +/** + Set all interrupt status bits in Normal and Error Interrupt Status Enable + register. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimHcEnableInterrupt ( + IN UINTN Bar + ) +{ + EFI_STATUS Status; + UINT16 IntStatus; + + // + // Enable all bits in Error Interrupt Status Enable Register + // + IntStatus = 0xFFFF; + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ERR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Enable all bits in Normal Interrupt Status Enable Register + // + IntStatus = 0xFFFF; + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus); + + return Status; +} + +/** + Get the capability data from the specified slot. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[out] Capability The buffer to store the capability data. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimHcGetCapability ( + IN UINTN Bar, + OUT EMMC_HC_SLOT_CAP *Capability + ) +{ + EFI_STATUS Status; + UINT64 Cap; + + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CAP, TRUE, sizeof (Cap), &Cap); + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem (Capability, &Cap, sizeof (Cap)); + + return EFI_SUCCESS; +} + +/** + Detect whether there is a EMMC card attached at the specified EMMC host controller + slot. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS There is a EMMC card attached. + @retval EFI_NO_MEDIA There is not a EMMC card attached. + @retval Others The detection fails. + +**/ +EFI_STATUS +EmmcPeimHcCardDetect ( + IN UINTN Bar + ) +{ + EFI_STATUS Status; + UINT16 Data; + UINT32 PresentState; + + // + // Check Normal Interrupt Status Register + // + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, TRUE, sizeof (Data), &Data); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((Data & (BIT6 | BIT7)) != 0) { + // + // Clear BIT6 and BIT7 by writing 1 to these two bits if set. + // + Data &= BIT6 | BIT7; + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, FALSE, sizeof (Data), &Data); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Check Present State Register to see if there is a card presented. + // + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((PresentState & BIT16) != 0) { + return EFI_SUCCESS; + } else { + return EFI_NO_MEDIA; + } +} + +/** + Stop EMMC card clock. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS Succeed to stop EMMC clock. + @retval Others Fail to stop EMMC clock. + +**/ +EFI_STATUS +EmmcPeimHcStopClock ( + IN UINTN Bar + ) +{ + EFI_STATUS Status; + UINT32 PresentState; + UINT16 ClockCtrl; + + // + // Ensure no SD transactions are occurring on the SD Bus by + // waiting for Command Inhibit (DAT) and Command Inhibit (CMD) + // in the Present State register to be 0. + // + Status = EmmcPeimHcWaitMmioSet ( + Bar + EMMC_HC_PRESENT_STATE, + sizeof (PresentState), + BIT0 | BIT1, + 0, + EMMC_TIMEOUT + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set SD Clock Enable in the Clock Control register to 0 + // + ClockCtrl = (UINT16) ~BIT2; + Status = EmmcPeimHcAndMmio (Bar + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl); + + return Status; +} + +/** + EMMC card clock supply. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] ClockFreq The max clock frequency to be set. The unit is KHz. + + @retval EFI_SUCCESS The clock is supplied successfully. + @retval Others The clock isn't supplied successfully. + +**/ +EFI_STATUS +EmmcPeimHcClockSupply ( + IN UINTN Bar, + IN UINT64 ClockFreq + ) +{ + EFI_STATUS Status; + EMMC_HC_SLOT_CAP Capability; + UINT32 BaseClkFreq; + UINT32 SettingFreq; + UINT32 Divisor; + UINT32 Remainder; + UINT16 ControllerVer; + UINT16 ClockCtrl; + + // + // Calculate a divisor for SD clock frequency + // + Status = EmmcPeimHcGetCapability (Bar, &Capability); + if (EFI_ERROR (Status)) { + return Status; + } + + ASSERT (Capability.BaseClkFreq != 0); + + BaseClkFreq = Capability.BaseClkFreq; + + if (ClockFreq == 0) { + return EFI_INVALID_PARAMETER; + } + + if (ClockFreq > (BaseClkFreq * 1000)) { + ClockFreq = BaseClkFreq * 1000; + } + + // + // Calculate the divisor of base frequency. + // + Divisor = 0; + SettingFreq = BaseClkFreq * 1000; + while (ClockFreq < SettingFreq) { + Divisor++; + + SettingFreq = (BaseClkFreq * 1000) / (2 * Divisor); + Remainder = (BaseClkFreq * 1000) % (2 * Divisor); + if ((ClockFreq == SettingFreq) && (Remainder == 0)) { + break; + } + + if ((ClockFreq == SettingFreq) && (Remainder != 0)) { + SettingFreq++; + } + } + + DEBUG ((DEBUG_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq)); + + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register. + // + if ((ControllerVer & 0xFF) == 2) { + ASSERT (Divisor <= 0x3FF); + ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2); + } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) { + // + // Only the most significant bit can be used as divisor. + // + if (((Divisor - 1) & Divisor) != 0) { + Divisor = 1 << (HighBitSet32 (Divisor) + 1); + } + + ASSERT (Divisor <= 0x80); + ClockCtrl = (Divisor & 0xFF) << 8; + } else { + DEBUG ((DEBUG_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer)); + return EFI_UNSUPPORTED; + } + + // + // Stop bus clock at first + // + Status = EmmcPeimHcStopClock (Bar); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Supply clock frequency with specified divisor + // + ClockCtrl |= BIT0; + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n")); + return Status; + } + + // + // Wait Internal Clock Stable in the Clock Control register to be 1 + // + Status = EmmcPeimHcWaitMmioSet ( + Bar + EMMC_HC_CLOCK_CTRL, + sizeof (ClockCtrl), + BIT1, + BIT1, + EMMC_TIMEOUT + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set SD Clock Enable in the Clock Control register to 1 + // + ClockCtrl = BIT2; + Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl); + + return Status; +} + +/** + EMMC bus power control. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] PowerCtrl The value setting to the power control register. + + @retval TRUE There is a EMMC card attached. + @retval FALSE There is no a EMMC card attached. + +**/ +EFI_STATUS +EmmcPeimHcPowerControl ( + IN UINTN Bar, + IN UINT8 PowerCtrl + ) +{ + EFI_STATUS Status; + + // + // Clr SD Bus Power + // + PowerCtrl &= (UINT8) ~BIT0; + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register + // + PowerCtrl |= BIT0; + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl); + + return Status; +} + +/** + Set the EMMC bus width. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] BusWidth The bus width used by the EMMC device, it must be 1, 4 or 8. + + @retval EFI_SUCCESS The bus width is set successfully. + @retval Others The bus width isn't set successfully. + +**/ +EFI_STATUS +EmmcPeimHcSetBusWidth ( + IN UINTN Bar, + IN UINT16 BusWidth + ) +{ + EFI_STATUS Status; + UINT8 HostCtrl1; + + if (BusWidth == 1) { + HostCtrl1 = (UINT8) ~(BIT5 | BIT1); + Status = EmmcPeimHcAndMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1); + } else if (BusWidth == 4) { + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1); + if (EFI_ERROR (Status)) { + return Status; + } + + HostCtrl1 |= BIT1; + HostCtrl1 &= (UINT8) ~BIT5; + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1); + } else if (BusWidth == 8) { + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1); + if (EFI_ERROR (Status)) { + return Status; + } + + HostCtrl1 &= (UINT8) ~BIT1; + HostCtrl1 |= BIT5; + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1); + } else { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + return Status; +} + +/** + Supply EMMC card with lowest clock frequency at initialization. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The clock is supplied successfully. + @retval Others The clock isn't supplied successfully. + +**/ +EFI_STATUS +EmmcPeimHcInitClockFreq ( + IN UINTN Bar + ) +{ + EFI_STATUS Status; + EMMC_HC_SLOT_CAP Capability; + UINT32 InitFreq; + + // + // Calculate a divisor for SD clock frequency + // + Status = EmmcPeimHcGetCapability (Bar, &Capability); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Capability.BaseClkFreq == 0) { + // + // Don't support get Base Clock Frequency information via another method + // + return EFI_UNSUPPORTED; + } + + // + // Supply 400KHz clock frequency at initialization phase. + // + InitFreq = 400; + Status = EmmcPeimHcClockSupply (Bar, InitFreq); + return Status; +} + +/** + Supply EMMC card with maximum voltage at initialization. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The voltage is supplied successfully. + @retval Others The voltage isn't supplied successfully. + +**/ +EFI_STATUS +EmmcPeimHcInitPowerVoltage ( + IN UINTN Bar + ) +{ + EFI_STATUS Status; + EMMC_HC_SLOT_CAP Capability; + UINT8 MaxVoltage; + UINT8 HostCtrl2; + + // + // Get the support voltage of the Host Controller + // + Status = EmmcPeimHcGetCapability (Bar, &Capability); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Calculate supported maximum voltage according to SD Bus Voltage Select + // + if (Capability.Voltage33 != 0) { + // + // Support 3.3V + // + MaxVoltage = 0x0E; + } else if (Capability.Voltage30 != 0) { + // + // Support 3.0V + // + MaxVoltage = 0x0C; + } else if (Capability.Voltage18 != 0) { + // + // Support 1.8V + // + MaxVoltage = 0x0A; + HostCtrl2 = BIT3; + Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + MicroSecondDelay (5000); + } else { + ASSERT (FALSE); + return EFI_DEVICE_ERROR; + } + + // + // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register + // + Status = EmmcPeimHcPowerControl (Bar, MaxVoltage); + + return Status; +} + +/** + Initialize the Timeout Control register with most conservative value at initialization. + + Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The timeout control register is configured successfully. + @retval Others The timeout control register isn't configured successfully. + +**/ +EFI_STATUS +EmmcPeimHcInitTimeoutCtrl ( + IN UINTN Bar + ) +{ + EFI_STATUS Status; + UINT8 Timeout; + + Timeout = 0x0E; + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_TIMEOUT_CTRL, FALSE, sizeof (Timeout), &Timeout); + + return Status; +} + +/** + Initial EMMC host controller with lowest clock frequency, max power and max timeout value + at initialization. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The host controller is initialized successfully. + @retval Others The host controller isn't initialized successfully. + +**/ +EFI_STATUS +EmmcPeimHcInitHost ( + IN UINTN Bar + ) +{ + EFI_STATUS Status; + + Status = EmmcPeimHcInitClockFreq (Bar); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EmmcPeimHcInitPowerVoltage (Bar); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EmmcPeimHcInitTimeoutCtrl (Bar); + return Status; +} + +/** + Turn on/off LED. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] On The boolean to turn on/off LED. + + @retval EFI_SUCCESS The LED is turned on/off successfully. + @retval Others The LED isn't turned on/off successfully. + +**/ +EFI_STATUS +EmmcPeimHcLedOnOff ( + IN UINTN Bar, + IN BOOLEAN On + ) +{ + EFI_STATUS Status; + UINT8 HostCtrl1; + + if (On) { + HostCtrl1 = BIT0; + Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1); + } else { + HostCtrl1 = (UINT8) ~BIT0; + Status = EmmcPeimHcAndMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1); + } + + return Status; +} + +/** + Build ADMA descriptor table for transfer. + + Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details. + + @param[in] Trb The pointer to the EMMC_TRB instance. + + @retval EFI_SUCCESS The ADMA descriptor table is created successfully. + @retval Others The ADMA descriptor table isn't created successfully. + +**/ +EFI_STATUS +BuildAdmaDescTable ( + IN EMMC_TRB *Trb + ) +{ + EFI_PHYSICAL_ADDRESS Data; + UINT64 DataLen; + UINT64 Entries; + UINT32 Index; + UINT64 Remaining; + UINT32 Address; + + Data = Trb->DataPhy; + DataLen = Trb->DataLen; + // + // Only support 32bit ADMA Descriptor Table + // + if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) { + return EFI_INVALID_PARAMETER; + } + + // + // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0) + // for 32-bit address descriptor table. + // + if ((Data & (BIT0 | BIT1)) != 0) { + DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data)); + } + + Entries = DivU64x32 ((DataLen + ADMA_MAX_DATA_PER_LINE - 1), ADMA_MAX_DATA_PER_LINE); + + Trb->AdmaDescSize = (UINTN)MultU64x32 (Entries, sizeof (EMMC_HC_ADMA_DESC_LINE)); + Trb->AdmaDesc = EmmcPeimAllocateMem (Trb->Slot->Private->Pool, Trb->AdmaDescSize); + if (Trb->AdmaDesc == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Remaining = DataLen; + Address = (UINT32)Data; + for (Index = 0; Index < Entries; Index++) { + if (Remaining <= ADMA_MAX_DATA_PER_LINE) { + Trb->AdmaDesc[Index].Valid = 1; + Trb->AdmaDesc[Index].Act = 2; + Trb->AdmaDesc[Index].Length = (UINT16)Remaining; + Trb->AdmaDesc[Index].Address = Address; + break; + } else { + Trb->AdmaDesc[Index].Valid = 1; + Trb->AdmaDesc[Index].Act = 2; + Trb->AdmaDesc[Index].Length = 0; + Trb->AdmaDesc[Index].Address = Address; + } + + Remaining -= ADMA_MAX_DATA_PER_LINE; + Address += ADMA_MAX_DATA_PER_LINE; + } + + // + // Set the last descriptor line as end of descriptor table + // + Trb->AdmaDesc[Index].End = 1; + return EFI_SUCCESS; +} + +/** + Create a new TRB for the EMMC cmd request. + + @param[in] Slot The slot number of the EMMC card to send the command to. + @param[in] Packet A pointer to the SD command data structure. + + @return Created Trb or NULL. + +**/ +EMMC_TRB * +EmmcPeimCreateTrb ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN EMMC_COMMAND_PACKET *Packet + ) +{ + EMMC_TRB *Trb; + EFI_STATUS Status; + EMMC_HC_SLOT_CAP Capability; + EDKII_IOMMU_OPERATION MapOp; + UINTN MapLength; + + // + // Calculate a divisor for SD clock frequency + // + Status = EmmcPeimHcGetCapability (Slot->EmmcHcBase, &Capability); + if (EFI_ERROR (Status)) { + return NULL; + } + + Trb = AllocateZeroPool (sizeof (EMMC_TRB)); + if (Trb == NULL) { + return NULL; + } + + Trb->Slot = Slot; + Trb->BlockSize = 0x200; + Trb->Packet = Packet; + Trb->Timeout = Packet->Timeout; + + if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) { + Trb->Data = Packet->InDataBuffer; + Trb->DataLen = Packet->InTransferLength; + Trb->Read = TRUE; + } else if ((Packet->OutTransferLength != 0) && (Packet->OutDataBuffer != NULL)) { + Trb->Data = Packet->OutDataBuffer; + Trb->DataLen = Packet->OutTransferLength; + Trb->Read = FALSE; + } else if ((Packet->InTransferLength == 0) && (Packet->OutTransferLength == 0)) { + Trb->Data = NULL; + Trb->DataLen = 0; + } else { + goto Error; + } + + if ((Trb->DataLen != 0) && (Trb->DataLen < Trb->BlockSize)) { + Trb->BlockSize = (UINT16)Trb->DataLen; + } + + if (Packet->EmmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK) { + Trb->Mode = EmmcPioMode; + } else { + if (Trb->Read) { + MapOp = EdkiiIoMmuOperationBusMasterWrite; + } else { + MapOp = EdkiiIoMmuOperationBusMasterRead; + } + + if (Trb->DataLen != 0) { + MapLength = Trb->DataLen; + Status = IoMmuMap (MapOp, Trb->Data, &MapLength, &Trb->DataPhy, &Trb->DataMap); + + if (EFI_ERROR (Status) || (MapLength != Trb->DataLen)) { + DEBUG ((DEBUG_ERROR, "EmmcPeimCreateTrb: Fail to map data buffer.\n")); + goto Error; + } + } + + if (Trb->DataLen == 0) { + Trb->Mode = EmmcNoData; + } else if (Capability.Adma2 != 0) { + Trb->Mode = EmmcAdmaMode; + Status = BuildAdmaDescTable (Trb); + if (EFI_ERROR (Status)) { + goto Error; + } + } else if (Capability.Sdma != 0) { + Trb->Mode = EmmcSdmaMode; + } else { + Trb->Mode = EmmcPioMode; + } + } + + return Trb; + +Error: + EmmcPeimFreeTrb (Trb); + return NULL; +} + +/** + Free the resource used by the TRB. + + @param[in] Trb The pointer to the EMMC_TRB instance. + +**/ +VOID +EmmcPeimFreeTrb ( + IN EMMC_TRB *Trb + ) +{ + if ((Trb != NULL) && (Trb->DataMap != NULL)) { + IoMmuUnmap (Trb->DataMap); + } + + if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) { + EmmcPeimFreeMem (Trb->Slot->Private->Pool, Trb->AdmaDesc, Trb->AdmaDescSize); + } + + if (Trb != NULL) { + FreePool (Trb); + } + + return; +} + +/** + Check if the env is ready for execute specified TRB. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] Trb The pointer to the EMMC_TRB instance. + + @retval EFI_SUCCESS The env is ready for TRB execution. + @retval EFI_NOT_READY The env is not ready for TRB execution. + @retval Others Some erros happen. + +**/ +EFI_STATUS +EmmcPeimCheckTrbEnv ( + IN UINTN Bar, + IN EMMC_TRB *Trb + ) +{ + EFI_STATUS Status; + EMMC_COMMAND_PACKET *Packet; + UINT32 PresentState; + + Packet = Trb->Packet; + + if ((Packet->EmmcCmdBlk->CommandType == EmmcCommandTypeAdtc) || + (Packet->EmmcCmdBlk->ResponseType == EmmcResponceTypeR1b) || + (Packet->EmmcCmdBlk->ResponseType == EmmcResponceTypeR5b)) + { + // + // Wait Command Inhibit (CMD) and Command Inhibit (DAT) in + // the Present State register to be 0 + // + PresentState = BIT0 | BIT1; + } else { + // + // Wait Command Inhibit (CMD) in the Present State register + // to be 0 + // + PresentState = BIT0; + } + + Status = EmmcPeimHcCheckMmioSet ( + Bar + EMMC_HC_PRESENT_STATE, + sizeof (PresentState), + PresentState, + 0 + ); + + return Status; +} + +/** + Wait for the env to be ready for execute specified TRB. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] Trb The pointer to the EMMC_TRB instance. + + @retval EFI_SUCCESS The env is ready for TRB execution. + @retval EFI_TIMEOUT The env is not ready for TRB execution in time. + @retval Others Some erros happen. + +**/ +EFI_STATUS +EmmcPeimWaitTrbEnv ( + IN UINTN Bar, + IN EMMC_TRB *Trb + ) +{ + EFI_STATUS Status; + EMMC_COMMAND_PACKET *Packet; + UINT64 Timeout; + BOOLEAN InfiniteWait; + + // + // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register + // + Packet = Trb->Packet; + Timeout = Packet->Timeout; + if (Timeout == 0) { + InfiniteWait = TRUE; + } else { + InfiniteWait = FALSE; + } + + while (InfiniteWait || (Timeout > 0)) { + // + // Check Trb execution result by reading Normal Interrupt Status register. + // + Status = EmmcPeimCheckTrbEnv (Bar, Trb); + if (Status != EFI_NOT_READY) { + return Status; + } + + // + // Stall for 1 microsecond. + // + MicroSecondDelay (1); + + Timeout--; + } + + return EFI_TIMEOUT; +} + +/** + Execute the specified TRB. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] Trb The pointer to the EMMC_TRB instance. + + @retval EFI_SUCCESS The TRB is sent to host controller successfully. + @retval Others Some erros happen when sending this request to the host controller. + +**/ +EFI_STATUS +EmmcPeimExecTrb ( + IN UINTN Bar, + IN EMMC_TRB *Trb + ) +{ + EFI_STATUS Status; + EMMC_COMMAND_PACKET *Packet; + UINT16 Cmd; + UINT16 IntStatus; + UINT32 Argument; + UINT16 BlkCount; + UINT16 BlkSize; + UINT16 TransMode; + UINT8 HostCtrl1; + UINT32 SdmaAddr; + UINT64 AdmaAddr; + + Packet = Trb->Packet; + // + // Clear all bits in Error Interrupt Status Register + // + IntStatus = 0xFFFF; + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ERR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Clear all bits in Normal Interrupt Status Register + // + IntStatus = 0xFFFF; + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set Host Control 1 register DMA Select field + // + if (Trb->Mode == EmmcAdmaMode) { + HostCtrl1 = BIT4; + Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1); + if (EFI_ERROR (Status)) { + return Status; + } + } + + EmmcPeimHcLedOnOff (Bar, TRUE); + + if (Trb->Mode == EmmcSdmaMode) { + if ((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul) { + return EFI_INVALID_PARAMETER; + } + + SdmaAddr = (UINT32)(UINTN)Trb->DataPhy; + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr); + if (EFI_ERROR (Status)) { + return Status; + } + } else if (Trb->Mode == EmmcAdmaMode) { + AdmaAddr = (UINT64)(UINTN)Trb->AdmaDesc; + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr); + if (EFI_ERROR (Status)) { + return Status; + } + } + + BlkSize = Trb->BlockSize; + if (Trb->Mode == EmmcSdmaMode) { + // + // Set SDMA boundary to be 512K bytes. + // + BlkSize |= 0x7000; + } + + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_BLK_SIZE, FALSE, sizeof (BlkSize), &BlkSize); + if (EFI_ERROR (Status)) { + return Status; + } + + BlkCount = 0; + if (Trb->Mode != EmmcNoData) { + // + // Calculate Block Count. + // + BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize); + } + + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount); + if (EFI_ERROR (Status)) { + return Status; + } + + Argument = Packet->EmmcCmdBlk->CommandArgument; + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ARG1, FALSE, sizeof (Argument), &Argument); + if (EFI_ERROR (Status)) { + return Status; + } + + TransMode = 0; + if (Trb->Mode != EmmcNoData) { + if (Trb->Mode != EmmcPioMode) { + TransMode |= BIT0; + } + + if (Trb->Read) { + TransMode |= BIT4; + } + + if (BlkCount > 1) { + TransMode |= BIT5 | BIT1; + } + } + + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_TRANS_MOD, FALSE, sizeof (TransMode), &TransMode); + if (EFI_ERROR (Status)) { + return Status; + } + + Cmd = (UINT16)LShiftU64 (Packet->EmmcCmdBlk->CommandIndex, 8); + if (Packet->EmmcCmdBlk->CommandType == EmmcCommandTypeAdtc) { + Cmd |= BIT5; + } + + // + // Convert ResponseType to value + // + if (Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeBc) { + switch (Packet->EmmcCmdBlk->ResponseType) { + case EmmcResponceTypeR1: + case EmmcResponceTypeR5: + case EmmcResponceTypeR6: + case EmmcResponceTypeR7: + Cmd |= (BIT1 | BIT3 | BIT4); + break; + case EmmcResponceTypeR2: + Cmd |= (BIT0 | BIT3); + break; + case EmmcResponceTypeR3: + case EmmcResponceTypeR4: + Cmd |= BIT1; + break; + case EmmcResponceTypeR1b: + case EmmcResponceTypeR5b: + Cmd |= (BIT0 | BIT1 | BIT3 | BIT4); + break; + default: + ASSERT (FALSE); + break; + } + } + + // + // Execute cmd + // + Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd); + return Status; +} + +/** + Check the TRB execution result. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] Trb The pointer to the EMMC_TRB instance. + + @retval EFI_SUCCESS The TRB is executed successfully. + @retval EFI_NOT_READY The TRB is not completed for execution. + @retval Others Some erros happen when executing this request. + +**/ +EFI_STATUS +EmmcPeimCheckTrbResult ( + IN UINTN Bar, + IN EMMC_TRB *Trb + ) +{ + EFI_STATUS Status; + EMMC_COMMAND_PACKET *Packet; + UINT16 IntStatus; + UINT32 Response[4]; + UINT32 SdmaAddr; + UINT8 Index; + UINT8 SwReset; + UINT32 PioLength; + + SwReset = 0; + Packet = Trb->Packet; + // + // Check Trb execution result by reading Normal Interrupt Status register. + // + Status = EmmcPeimHcRwMmio ( + Bar + EMMC_HC_NOR_INT_STS, + TRUE, + sizeof (IntStatus), + &IntStatus + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Check Transfer Complete bit is set or not. + // + if ((IntStatus & BIT1) == BIT1) { + if ((IntStatus & BIT15) == BIT15) { + // + // Read Error Interrupt Status register to check if the error is + // Data Timeout Error. + // If yes, treat it as success as Transfer Complete has higher + // priority than Data Timeout Error. + // + Status = EmmcPeimHcRwMmio ( + Bar + EMMC_HC_ERR_INT_STS, + TRUE, + sizeof (IntStatus), + &IntStatus + ); + if (!EFI_ERROR (Status)) { + if ((IntStatus & BIT4) == BIT4) { + Status = EFI_SUCCESS; + } else { + Status = EFI_DEVICE_ERROR; + } + } + } + + goto Done; + } + + // + // Check if there is a error happened during cmd execution. + // If yes, then do error recovery procedure to follow SD Host Controller + // Simplified Spec 3.0 section 3.10.1. + // + if ((IntStatus & BIT15) == BIT15) { + Status = EmmcPeimHcRwMmio ( + Bar + EMMC_HC_ERR_INT_STS, + TRUE, + sizeof (IntStatus), + &IntStatus + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + if ((IntStatus & 0x0F) != 0) { + SwReset |= BIT1; + } + + if ((IntStatus & 0xF0) != 0) { + SwReset |= BIT2; + } + + Status = EmmcPeimHcRwMmio ( + Bar + EMMC_HC_SW_RST, + FALSE, + sizeof (SwReset), + &SwReset + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = EmmcPeimHcWaitMmioSet ( + Bar + EMMC_HC_SW_RST, + sizeof (SwReset), + 0xFF, + 0, + EMMC_TIMEOUT + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = EFI_DEVICE_ERROR; + goto Done; + } + + // + // Check if DMA interrupt is signalled for the SDMA transfer. + // + if ((Trb->Mode == EmmcSdmaMode) && ((IntStatus & BIT3) == BIT3)) { + // + // Clear DMA interrupt bit. + // + IntStatus = BIT3; + Status = EmmcPeimHcRwMmio ( + Bar + EMMC_HC_NOR_INT_STS, + FALSE, + sizeof (IntStatus), + &IntStatus + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Update SDMA Address register. + // + SdmaAddr = EMMC_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->DataPhy, EMMC_SDMA_BOUNDARY); + Status = EmmcPeimHcRwMmio ( + Bar + EMMC_HC_SDMA_ADDR, + FALSE, + sizeof (UINT32), + &SdmaAddr + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Trb->DataPhy = (UINT32)(UINTN)SdmaAddr; + } + + if ((Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeAdtc) && + (Packet->EmmcCmdBlk->ResponseType != EmmcResponceTypeR1b) && + (Packet->EmmcCmdBlk->ResponseType != EmmcResponceTypeR5b)) + { + if ((IntStatus & BIT0) == BIT0) { + Status = EFI_SUCCESS; + goto Done; + } + } + + if (Packet->EmmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK) { + // + // When performing tuning procedure (Execute Tuning is set to 1) through PIO mode, + // wait Buffer Read Ready bit of Normal Interrupt Status Register to be 1. + // Refer to SD Host Controller Simplified Specification 3.0 figure 2-29 for details. + // + if ((IntStatus & BIT5) == BIT5) { + // + // Clear Buffer Read Ready interrupt at first. + // + IntStatus = BIT5; + EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus); + // + // Read data out from Buffer Port register + // + for (PioLength = 0; PioLength < Trb->DataLen; PioLength += 4) { + EmmcPeimHcRwMmio (Bar + EMMC_HC_BUF_DAT_PORT, TRUE, 4, (UINT8 *)Trb->Data + PioLength); + } + + Status = EFI_SUCCESS; + goto Done; + } + } + + Status = EFI_NOT_READY; +Done: + // + // Get response data when the cmd is executed successfully. + // + if (!EFI_ERROR (Status)) { + if (Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeBc) { + for (Index = 0; Index < 4; Index++) { + Status = EmmcPeimHcRwMmio ( + Bar + EMMC_HC_RESPONSE + Index * 4, + TRUE, + sizeof (UINT32), + &Response[Index] + ); + if (EFI_ERROR (Status)) { + EmmcPeimHcLedOnOff (Bar, FALSE); + return Status; + } + } + + CopyMem (Packet->EmmcStatusBlk, Response, sizeof (Response)); + } + } + + if (Status != EFI_NOT_READY) { + EmmcPeimHcLedOnOff (Bar, FALSE); + } + + return Status; +} + +/** + Wait for the TRB execution result. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] Trb The pointer to the EMMC_TRB instance. + + @retval EFI_SUCCESS The TRB is executed successfully. + @retval Others Some erros happen when executing this request. + +**/ +EFI_STATUS +EmmcPeimWaitTrbResult ( + IN UINTN Bar, + IN EMMC_TRB *Trb + ) +{ + EFI_STATUS Status; + EMMC_COMMAND_PACKET *Packet; + UINT64 Timeout; + BOOLEAN InfiniteWait; + + Packet = Trb->Packet; + // + // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register + // + Timeout = Packet->Timeout; + if (Timeout == 0) { + InfiniteWait = TRUE; + } else { + InfiniteWait = FALSE; + } + + while (InfiniteWait || (Timeout > 0)) { + // + // Check Trb execution result by reading Normal Interrupt Status register. + // + Status = EmmcPeimCheckTrbResult (Bar, Trb); + if (Status != EFI_NOT_READY) { + return Status; + } + + // + // Stall for 1 microsecond. + // + MicroSecondDelay (1); + + Timeout--; + } + + return EFI_TIMEOUT; +} + +/** + Sends EMMC command to an EMMC card that is attached to the EMMC controller. + + If Packet is successfully sent to the EMMC card, then EFI_SUCCESS is returned. + + If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned. + + If Slot is not in a valid range for the EMMC controller, then EFI_INVALID_PARAMETER + is returned. + + If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL, + EFI_INVALID_PARAMETER is returned. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in,out] Packet A pointer to the EMMC command data structure. + + @retval EFI_SUCCESS The EMMC Command Packet was sent by the host. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD + command Packet. + @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid. + @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and + OutDataBuffer are NULL. + @retval EFI_NO_MEDIA SD Device not present in the Slot. + @retval EFI_UNSUPPORTED The command described by the EMMC Command Packet is not + supported by the host controller. + @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the + limit supported by EMMC card ( i.e. if the number of bytes + exceed the Last LBA). + +**/ +EFI_STATUS +EFIAPI +EmmcPeimExecCmd ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN OUT EMMC_COMMAND_PACKET *Packet + ) +{ + EFI_STATUS Status; + EMMC_TRB *Trb; + + if (Packet == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((Packet->EmmcCmdBlk == NULL) || (Packet->EmmcStatusBlk == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) { + return EFI_INVALID_PARAMETER; + } + + if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) { + return EFI_INVALID_PARAMETER; + } + + Trb = EmmcPeimCreateTrb (Slot, Packet); + if (Trb == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = EmmcPeimWaitTrbEnv (Slot->EmmcHcBase, Trb); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = EmmcPeimExecTrb (Slot->EmmcHcBase, Trb); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = EmmcPeimWaitTrbResult (Slot->EmmcHcBase, Trb); + if (EFI_ERROR (Status)) { + goto Done; + } + +Done: + EmmcPeimFreeTrb (Trb); + + return Status; +} + +/** + Send command GO_IDLE_STATE (CMD0 with argument of 0x00000000) to the device to + make it go to Idle State. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + + @retval EFI_SUCCESS The EMMC device is reset correctly. + @retval Others The device reset fails. + +**/ +EFI_STATUS +EmmcPeimReset ( + IN EMMC_PEIM_HC_SLOT *Slot + ) +{ + EMMC_COMMAND_BLOCK EmmcCmdBlk; + EMMC_STATUS_BLOCK EmmcStatusBlk; + EMMC_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk)); + ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.EmmcCmdBlk = &EmmcCmdBlk; + Packet.EmmcStatusBlk = &EmmcStatusBlk; + Packet.Timeout = EMMC_TIMEOUT; + + EmmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE; + EmmcCmdBlk.CommandType = EmmcCommandTypeBc; + EmmcCmdBlk.ResponseType = 0; + EmmcCmdBlk.CommandArgument = 0; + + Status = EmmcPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Send command SEND_OP_COND to the EMMC device to get the data of the OCR register. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in, out] Argument On input, the argument of SEND_OP_COND is to send to the device. + On output, the argument is the value of OCR register. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimGetOcr ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN OUT UINT32 *Argument + ) +{ + EMMC_COMMAND_BLOCK EmmcCmdBlk; + EMMC_STATUS_BLOCK EmmcStatusBlk; + EMMC_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk)); + ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.EmmcCmdBlk = &EmmcCmdBlk; + Packet.EmmcStatusBlk = &EmmcStatusBlk; + Packet.Timeout = EMMC_TIMEOUT; + + EmmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND; + EmmcCmdBlk.CommandType = EmmcCommandTypeBcr; + EmmcCmdBlk.ResponseType = EmmcResponceTypeR3; + EmmcCmdBlk.CommandArgument = *Argument; + + Status = EmmcPeimExecCmd (Slot, &Packet); + if (!EFI_ERROR (Status)) { + // + // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12. + // + *Argument = EmmcStatusBlk.Resp0; + } + + return Status; +} + +/** + Broadcast command ALL_SEND_CID to the bus to ask all the EMMC devices to send the + data of their CID registers. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimGetAllCid ( + IN EMMC_PEIM_HC_SLOT *Slot + ) +{ + EMMC_COMMAND_BLOCK EmmcCmdBlk; + EMMC_STATUS_BLOCK EmmcStatusBlk; + EMMC_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk)); + ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.EmmcCmdBlk = &EmmcCmdBlk; + Packet.EmmcStatusBlk = &EmmcStatusBlk; + Packet.Timeout = EMMC_TIMEOUT; + + EmmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID; + EmmcCmdBlk.CommandType = EmmcCommandTypeBcr; + EmmcCmdBlk.ResponseType = EmmcResponceTypeR2; + EmmcCmdBlk.CommandArgument = 0; + + Status = EmmcPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Send command SET_RELATIVE_ADDR to the EMMC device to assign a Relative device + Address (RCA). + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] Rca The relative device address to be assigned. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimSetRca ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN UINT32 Rca + ) +{ + EMMC_COMMAND_BLOCK EmmcCmdBlk; + EMMC_STATUS_BLOCK EmmcStatusBlk; + EMMC_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk)); + ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.EmmcCmdBlk = &EmmcCmdBlk; + Packet.EmmcStatusBlk = &EmmcStatusBlk; + Packet.Timeout = EMMC_TIMEOUT; + + EmmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR; + EmmcCmdBlk.CommandType = EmmcCommandTypeAc; + EmmcCmdBlk.ResponseType = EmmcResponceTypeR1; + EmmcCmdBlk.CommandArgument = Rca << 16; + + Status = EmmcPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Send command SEND_CSD to the EMMC device to get the data of the CSD register. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] Rca The relative device address of selected device. + @param[out] Csd The buffer to store the content of the CSD register. + Note the caller should ignore the lowest byte of this + buffer as the content of this byte is meaningless even + if the operation succeeds. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimGetCsd ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN UINT32 Rca, + OUT EMMC_CSD *Csd + ) +{ + EMMC_COMMAND_BLOCK EmmcCmdBlk; + EMMC_STATUS_BLOCK EmmcStatusBlk; + EMMC_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk)); + ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.EmmcCmdBlk = &EmmcCmdBlk; + Packet.EmmcStatusBlk = &EmmcStatusBlk; + Packet.Timeout = EMMC_TIMEOUT; + + EmmcCmdBlk.CommandIndex = EMMC_SEND_CSD; + EmmcCmdBlk.CommandType = EmmcCommandTypeAc; + EmmcCmdBlk.ResponseType = EmmcResponceTypeR2; + EmmcCmdBlk.CommandArgument = Rca << 16; + + Status = EmmcPeimExecCmd (Slot, &Packet); + if (!EFI_ERROR (Status)) { + // + // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12. + // + CopyMem (((UINT8 *)Csd) + 1, &EmmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1); + } + + return Status; +} + +/** + Send command SELECT_DESELECT_CARD to the EMMC device to select/deselect it. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] Rca The relative device address of selected device. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimSelect ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN UINT32 Rca + ) +{ + EMMC_COMMAND_BLOCK EmmcCmdBlk; + EMMC_STATUS_BLOCK EmmcStatusBlk; + EMMC_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk)); + ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.EmmcCmdBlk = &EmmcCmdBlk; + Packet.EmmcStatusBlk = &EmmcStatusBlk; + Packet.Timeout = EMMC_TIMEOUT; + + EmmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD; + EmmcCmdBlk.CommandType = EmmcCommandTypeAc; + EmmcCmdBlk.ResponseType = EmmcResponceTypeR1; + EmmcCmdBlk.CommandArgument = Rca << 16; + + Status = EmmcPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Send command SEND_EXT_CSD to the EMMC device to get the data of the EXT_CSD register. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[out] ExtCsd The buffer to store the content of the EXT_CSD register. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimGetExtCsd ( + IN EMMC_PEIM_HC_SLOT *Slot, + OUT EMMC_EXT_CSD *ExtCsd + ) +{ + EMMC_COMMAND_BLOCK EmmcCmdBlk; + EMMC_STATUS_BLOCK EmmcStatusBlk; + EMMC_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk)); + ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.EmmcCmdBlk = &EmmcCmdBlk; + Packet.EmmcStatusBlk = &EmmcStatusBlk; + Packet.Timeout = EMMC_TIMEOUT; + + EmmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD; + EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc; + EmmcCmdBlk.ResponseType = EmmcResponceTypeR1; + EmmcCmdBlk.CommandArgument = 0x00000000; + + Packet.InDataBuffer = ExtCsd; + Packet.InTransferLength = sizeof (EMMC_EXT_CSD); + + Status = EmmcPeimExecCmd (Slot, &Packet); + return Status; +} + +/** + Send command SWITCH to the EMMC device to switch the mode of operation of the + selected Device or modifies the EXT_CSD registers. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] Access The access mode of SWITCH command. + @param[in] Index The offset of the field to be access. + @param[in] Value The value to be set to the specified field of EXT_CSD register. + @param[in] CmdSet The value of CmdSet field of EXT_CSD register. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimSwitch ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN UINT8 Access, + IN UINT8 Index, + IN UINT8 Value, + IN UINT8 CmdSet + ) +{ + EMMC_COMMAND_BLOCK EmmcCmdBlk; + EMMC_STATUS_BLOCK EmmcStatusBlk; + EMMC_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk)); + ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.EmmcCmdBlk = &EmmcCmdBlk; + Packet.EmmcStatusBlk = &EmmcStatusBlk; + Packet.Timeout = EMMC_TIMEOUT; + + EmmcCmdBlk.CommandIndex = EMMC_SWITCH; + EmmcCmdBlk.CommandType = EmmcCommandTypeAc; + EmmcCmdBlk.ResponseType = EmmcResponceTypeR1b; + EmmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | (Value << 8) | CmdSet; + + Status = EmmcPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Send command SEND_STATUS to the addressed EMMC device to get its status register. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] Rca The relative device address of addressed device. + @param[out] DevStatus The returned device status. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimSendStatus ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN UINT32 Rca, + OUT UINT32 *DevStatus + ) +{ + EMMC_COMMAND_BLOCK EmmcCmdBlk; + EMMC_STATUS_BLOCK EmmcStatusBlk; + EMMC_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk)); + ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.EmmcCmdBlk = &EmmcCmdBlk; + Packet.EmmcStatusBlk = &EmmcStatusBlk; + Packet.Timeout = EMMC_TIMEOUT; + + EmmcCmdBlk.CommandIndex = EMMC_SEND_STATUS; + EmmcCmdBlk.CommandType = EmmcCommandTypeAc; + EmmcCmdBlk.ResponseType = EmmcResponceTypeR1; + EmmcCmdBlk.CommandArgument = Rca << 16; + + Status = EmmcPeimExecCmd (Slot, &Packet); + if (!EFI_ERROR (Status)) { + *DevStatus = EmmcStatusBlk.Resp0; + } + + return Status; +} + +/** + Send command SET_BLOCK_COUNT to the addressed EMMC device to set the number of + blocks for the following block read/write cmd. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] BlockCount The number of the logical block to access. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimSetBlkCount ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN UINT16 BlockCount + ) +{ + EMMC_COMMAND_BLOCK EmmcCmdBlk; + EMMC_STATUS_BLOCK EmmcStatusBlk; + EMMC_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk)); + ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.EmmcCmdBlk = &EmmcCmdBlk; + Packet.EmmcStatusBlk = &EmmcStatusBlk; + Packet.Timeout = EMMC_TIMEOUT; + + EmmcCmdBlk.CommandIndex = EMMC_SET_BLOCK_COUNT; + EmmcCmdBlk.CommandType = EmmcCommandTypeAc; + EmmcCmdBlk.ResponseType = EmmcResponceTypeR1; + EmmcCmdBlk.CommandArgument = BlockCount; + + Status = EmmcPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed EMMC device + to read/write the specified number of blocks. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] Lba The logical block address of starting access. + @param[in] BlockSize The block size of specified EMMC device partition. + @param[in] Buffer The pointer to the transfer buffer. + @param[in] BufferSize The size of transfer buffer. + @param[in] IsRead Boolean to show the operation direction. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimRwMultiBlocks ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN EFI_LBA Lba, + IN UINT32 BlockSize, + IN VOID *Buffer, + IN UINTN BufferSize, + IN BOOLEAN IsRead + ) +{ + EMMC_COMMAND_BLOCK EmmcCmdBlk; + EMMC_STATUS_BLOCK EmmcStatusBlk; + EMMC_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk)); + ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.EmmcCmdBlk = &EmmcCmdBlk; + Packet.EmmcStatusBlk = &EmmcStatusBlk; + // + // 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. + // + Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000; + + if (IsRead) { + Packet.InDataBuffer = Buffer; + Packet.InTransferLength = (UINT32)BufferSize; + + EmmcCmdBlk.CommandIndex = EMMC_READ_MULTIPLE_BLOCK; + EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc; + EmmcCmdBlk.ResponseType = EmmcResponceTypeR1; + } else { + Packet.OutDataBuffer = Buffer; + Packet.OutTransferLength = (UINT32)BufferSize; + + EmmcCmdBlk.CommandIndex = EMMC_WRITE_MULTIPLE_BLOCK; + EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc; + EmmcCmdBlk.ResponseType = EmmcResponceTypeR1; + } + + if (Slot->SectorAddressing) { + EmmcCmdBlk.CommandArgument = (UINT32)Lba; + } else { + EmmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, BlockSize); + } + + Status = EmmcPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Send command SEND_TUNING_BLOCK to the EMMC device for HS200 optimal sampling point + detection. + + It may be sent up to 40 times until the host finishes the tuning procedure. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] BusWidth The bus width to work. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimSendTuningBlk ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN UINT8 BusWidth + ) +{ + EMMC_COMMAND_BLOCK EmmcCmdBlk; + EMMC_STATUS_BLOCK EmmcStatusBlk; + EMMC_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT8 TuningBlock[128]; + + ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk)); + ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.EmmcCmdBlk = &EmmcCmdBlk; + Packet.EmmcStatusBlk = &EmmcStatusBlk; + Packet.Timeout = EMMC_TIMEOUT; + + EmmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK; + EmmcCmdBlk.CommandType = EmmcCommandTypeAdtc; + EmmcCmdBlk.ResponseType = EmmcResponceTypeR1; + EmmcCmdBlk.CommandArgument = 0; + + Packet.InDataBuffer = TuningBlock; + if (BusWidth == 8) { + Packet.InTransferLength = sizeof (TuningBlock); + } else { + Packet.InTransferLength = 64; + } + + Status = EmmcPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Tuning the clock to get HS200 optimal sampling point. + + Command SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the + tuning procedure. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller + Simplified Spec 3.0 section Figure 2-29 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] BusWidth The bus width to work. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimTuningClkForHs200 ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN UINT8 BusWidth + ) +{ + EFI_STATUS Status; + UINT8 HostCtrl2; + UINT8 Retry; + + // + // Notify the host that the sampling clock tuning procedure starts. + // + HostCtrl2 = BIT6; + Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Ask the device to send a sequence of tuning blocks till the tuning procedure is done. + // + Retry = 0; + do { + Status = EmmcPeimSendTuningBlk (Slot, BusWidth); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EmmcPeimHcRwMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((HostCtrl2 & (BIT6 | BIT7)) == 0) { + break; + } + + if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) { + return EFI_SUCCESS; + } + } while (++Retry < 40); + + DEBUG ((DEBUG_ERROR, "EmmcPeimTuningClkForHs200: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2)); + // + // Abort the tuning procedure and reset the tuning circuit. + // + HostCtrl2 = (UINT8) ~(BIT6 | BIT7); + Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_DEVICE_ERROR; +} + +/** + Switch the bus width to specified width. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9 and SD Host Controller + Simplified Spec 3.0 section Figure 3-7 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] Rca The relative device address to be assigned. + @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise + use single data rate data simpling method. + @param[in] BusWidth The bus width to be set, it could be 4 or 8. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimSwitchBusWidth ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN UINT32 Rca, + IN BOOLEAN IsDdr, + IN UINT8 BusWidth + ) +{ + EFI_STATUS Status; + UINT8 Access; + UINT8 Index; + UINT8 Value; + UINT8 CmdSet; + UINT32 DevStatus; + + // + // Write Byte, the Value field is written into the byte pointed by Index. + // + Access = 0x03; + Index = OFFSET_OF (EMMC_EXT_CSD, BusWidth); + if (BusWidth == 4) { + Value = 1; + } else if (BusWidth == 8) { + Value = 2; + } else { + return EFI_INVALID_PARAMETER; + } + + if (IsDdr) { + Value += 4; + } + + CmdSet = 0; + Status = EmmcPeimSwitch (Slot, Access, Index, Value, CmdSet); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EmmcPeimSendStatus (Slot, Rca, &DevStatus); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check the switch operation is really successful or not. + // + if ((DevStatus & BIT7) != 0) { + return EFI_DEVICE_ERROR; + } + + Status = EmmcPeimHcSetBusWidth (Slot->EmmcHcBase, BusWidth); + + return Status; +} + +/** + Switch the clock frequency to the specified value. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6 and SD Host Controller + Simplified Spec 3.0 section Figure 3-3 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] Rca The relative device address to be assigned. + @param[in] HsTiming The value to be written to HS_TIMING field of EXT_CSD register. + @param[in] ClockFreq The max clock frequency to be set, the unit is MHz. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimSwitchClockFreq ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN UINT32 Rca, + IN UINT8 HsTiming, + IN UINT32 ClockFreq + ) +{ + EFI_STATUS Status; + UINT8 Access; + UINT8 Index; + UINT8 Value; + UINT8 CmdSet; + UINT32 DevStatus; + + // + // Write Byte, the Value field is written into the byte pointed by Index. + // + Access = 0x03; + Index = OFFSET_OF (EMMC_EXT_CSD, HsTiming); + Value = HsTiming; + CmdSet = 0; + + Status = EmmcPeimSwitch (Slot, Access, Index, Value, CmdSet); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EmmcPeimSendStatus (Slot, Rca, &DevStatus); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check the switch operation is really successful or not. + // + if ((DevStatus & BIT7) != 0) { + return EFI_DEVICE_ERROR; + } + + // + // Convert the clock freq unit from MHz to KHz. + // + Status = EmmcPeimHcClockSupply (Slot->EmmcHcBase, ClockFreq * 1000); + + return Status; +} + +/** + Switch to the High Speed timing according to request. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller + Simplified Spec 3.0 section Figure 2-29 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] Rca The relative device address to be assigned. + @param[in] ClockFreq The max clock frequency to be set. + @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise + use single data rate data simpling method. + @param[in] BusWidth The bus width to be set, it could be 4 or 8. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimSwitchToHighSpeed ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN UINT32 Rca, + IN UINT32 ClockFreq, + IN BOOLEAN IsDdr, + IN UINT8 BusWidth + ) +{ + EFI_STATUS Status; + UINT8 HsTiming; + UINT8 HostCtrl1; + UINT8 HostCtrl2; + + Status = EmmcPeimSwitchBusWidth (Slot, Rca, IsDdr, BusWidth); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set to High Speed timing + // + HostCtrl1 = BIT2; + Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1); + if (EFI_ERROR (Status)) { + return Status; + } + + HostCtrl2 = (UINT8) ~0x7; + Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + if (IsDdr) { + HostCtrl2 = BIT2; + } else if (ClockFreq == 52) { + HostCtrl2 = BIT0; + } else { + HostCtrl2 = 0; + } + + Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + HsTiming = 1; + Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq); + + return Status; +} + +/** + Switch to the HS200 timing according to request. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller + Simplified Spec 3.0 section Figure 2-29 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] Rca The relative device address to be assigned. + @param[in] ClockFreq The max clock frequency to be set. + @param[in] BusWidth The bus width to be set, it could be 4 or 8. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimSwitchToHS200 ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN UINT32 Rca, + IN UINT32 ClockFreq, + IN UINT8 BusWidth + ) +{ + EFI_STATUS Status; + UINT8 HsTiming; + UINT8 HostCtrl2; + UINT16 ClockCtrl; + + if ((BusWidth != 4) && (BusWidth != 8)) { + return EFI_INVALID_PARAMETER; + } + + Status = EmmcPeimSwitchBusWidth (Slot, Rca, FALSE, BusWidth); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set to HS200/SDR104 timing + // + // + // Stop bus clock at first + // + Status = EmmcPeimHcStopClock (Slot->EmmcHcBase); + if (EFI_ERROR (Status)) { + return Status; + } + + HostCtrl2 = (UINT8) ~0x7; + Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + HostCtrl2 = BIT0 | BIT1; + Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Wait Internal Clock Stable in the Clock Control register to be 1 before set SD Clock Enable bit + // + Status = EmmcPeimHcWaitMmioSet ( + Slot->EmmcHcBase + EMMC_HC_CLOCK_CTRL, + sizeof (ClockCtrl), + BIT1, + BIT1, + EMMC_TIMEOUT + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set SD Clock Enable in the Clock Control register to 1 + // + ClockCtrl = BIT2; + Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl); + + HsTiming = 2; + Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EmmcPeimTuningClkForHs200 (Slot, BusWidth); + + return Status; +} + +/** + Switch to the HS400 timing according to request. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller + Simplified Spec 3.0 section Figure 2-29 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] Rca The relative device address to be assigned. + @param[in] ClockFreq The max clock frequency to be set. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimSwitchToHS400 ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN UINT32 Rca, + IN UINT32 ClockFreq + ) +{ + EFI_STATUS Status; + UINT8 HsTiming; + UINT8 HostCtrl2; + + Status = EmmcPeimSwitchToHS200 (Slot, Rca, ClockFreq, 8); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set to High Speed timing and set the clock frequency to a value less than 52MHz. + // + HsTiming = 1; + Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, 52); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // HS400 mode must use 8 data lines. + // + Status = EmmcPeimSwitchBusWidth (Slot, Rca, TRUE, 8); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set to HS400 timing + // + HostCtrl2 = (UINT8) ~0x7; + Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + HostCtrl2 = BIT0 | BIT2; + Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + HsTiming = 3; + Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq); + + return Status; +} + +/** + Switch the high speed timing according to request. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller + Simplified Spec 3.0 section Figure 2-29 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] Rca The relative device address to be assigned. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimSetBusMode ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN UINT32 Rca + ) +{ + EFI_STATUS Status; + EMMC_HC_SLOT_CAP Capability; + UINT8 HsTiming; + BOOLEAN IsDdr; + UINT32 ClockFreq; + UINT8 BusWidth; + + Status = EmmcPeimGetCsd (Slot, Rca, &Slot->Csd); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcPeimSetBusMode: EmmcPeimGetCsd fails with %r\n", Status)); + return Status; + } + + if ((Slot->Csd.CSizeLow | Slot->Csd.CSizeHigh << 2) == 0xFFF) { + Slot->SectorAddressing = TRUE; + } else { + Slot->SectorAddressing = FALSE; + } + + Status = EmmcPeimSelect (Slot, Rca); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcPeimSetBusMode: EmmcPeimSelect fails with %r\n", Status)); + return Status; + } + + Status = EmmcPeimHcGetCapability (Slot->EmmcHcBase, &Capability); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcPeimSetBusMode: EmmcPeimHcGetCapability fails with %r\n", Status)); + return Status; + } + + ASSERT (Capability.BaseClkFreq != 0); + // + // Check if the Host Controller support 8bits bus width. + // + if (Capability.BusWidth8 != 0) { + BusWidth = 8; + } else { + BusWidth = 4; + } + + // + // Get Device_Type from EXT_CSD register. + // + Status = EmmcPeimGetExtCsd (Slot, &Slot->ExtCsd); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcPeimSetBusMode: EmmcPeimGetExtCsd fails with %r\n", Status)); + return Status; + } + + // + // Calculate supported bus speed/bus width/clock frequency. + // + HsTiming = 0; + IsDdr = FALSE; + ClockFreq = 0; + if (((Slot->ExtCsd.DeviceType & (BIT4 | BIT5)) != 0) && (Capability.Sdr104 != 0)) { + HsTiming = 2; + IsDdr = FALSE; + ClockFreq = 200; + } else if (((Slot->ExtCsd.DeviceType & (BIT2 | BIT3)) != 0) && (Capability.Ddr50 != 0)) { + HsTiming = 1; + IsDdr = TRUE; + ClockFreq = 52; + } else if (((Slot->ExtCsd.DeviceType & BIT1) != 0) && (Capability.HighSpeed != 0)) { + HsTiming = 1; + IsDdr = FALSE; + ClockFreq = 52; + } else if (((Slot->ExtCsd.DeviceType & BIT0) != 0) && (Capability.HighSpeed != 0)) { + HsTiming = 1; + IsDdr = FALSE; + ClockFreq = 26; + } + + // + // Check if both of the device and the host controller support HS400 DDR mode. + // + if (((Slot->ExtCsd.DeviceType & (BIT6 | BIT7)) != 0) && (Capability.Hs400 != 0)) { + // + // The host controller supports 8bits bus. + // + ASSERT (BusWidth == 8); + HsTiming = 3; + IsDdr = TRUE; + ClockFreq = 200; + } + + if ((ClockFreq == 0) || (HsTiming == 0)) { + // + // Continue using default setting. + // + return EFI_SUCCESS; + } + + DEBUG ((DEBUG_INFO, "HsTiming %d ClockFreq %d BusWidth %d Ddr %a\n", HsTiming, ClockFreq, BusWidth, IsDdr ? "TRUE" : "FALSE")); + + if (HsTiming == 3) { + // + // Execute HS400 timing switch procedure + // + Status = EmmcPeimSwitchToHS400 (Slot, Rca, ClockFreq); + } else if (HsTiming == 2) { + // + // Execute HS200 timing switch procedure + // + Status = EmmcPeimSwitchToHS200 (Slot, Rca, ClockFreq, BusWidth); + } else { + // + // Execute High Speed timing switch procedure + // + Status = EmmcPeimSwitchToHighSpeed (Slot, Rca, ClockFreq, IsDdr, BusWidth); + } + + return Status; +} + +/** + Execute EMMC device identification procedure. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + + @retval EFI_SUCCESS There is a EMMC card. + @retval Others There is not a EMMC card. + +**/ +EFI_STATUS +EmmcPeimIdentification ( + IN EMMC_PEIM_HC_SLOT *Slot + ) +{ + EFI_STATUS Status; + UINT32 Ocr; + UINT32 Rca; + UINTN Retry; + + Status = EmmcPeimReset (Slot); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcPeimIdentification: EmmcPeimReset fails with %r\n", Status)); + return Status; + } + + Ocr = 0; + Retry = 0; + do { + Status = EmmcPeimGetOcr (Slot, &Ocr); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcPeimIdentification: EmmcPeimGetOcr fails with %r\n", Status)); + return Status; + } + + if (Retry++ == 100) { + DEBUG ((DEBUG_ERROR, "EmmcPeimIdentification: EmmcPeimGetOcr fails too many times\n")); + return EFI_DEVICE_ERROR; + } + + MicroSecondDelay (10 * 1000); + } while ((Ocr & BIT31) == 0); + + Status = EmmcPeimGetAllCid (Slot); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcPeimIdentification: EmmcPeimGetAllCid fails with %r\n", Status)); + return Status; + } + + // + // Don't support multiple devices on the slot, that is + // shared bus slot feature. + // + Rca = 1; + Status = EmmcPeimSetRca (Slot, Rca); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "EmmcPeimIdentification: EmmcPeimSetRca fails with %r\n", Status)); + return Status; + } + + // + // Enter Data Tranfer Mode. + // + DEBUG ((DEBUG_INFO, "Found a EMMC device at slot [%d], RCA [%d]\n", Slot, Rca)); + + Status = EmmcPeimSetBusMode (Slot, Rca); + + return Status; +} diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.h b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.h index 6c6108b028..82585c9530 100644 --- a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.h +++ b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.h @@ -1,338 +1,338 @@ -/** @file
-
- Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _EMMC_HCI_H_
-#define _EMMC_HCI_H_
-
-//
-// EMMC Host Controller MMIO Register Offset
-//
-#define EMMC_HC_SDMA_ADDR 0x00
-#define EMMC_HC_ARG2 0x00
-#define EMMC_HC_BLK_SIZE 0x04
-#define EMMC_HC_BLK_COUNT 0x06
-#define EMMC_HC_ARG1 0x08
-#define EMMC_HC_TRANS_MOD 0x0C
-#define EMMC_HC_COMMAND 0x0E
-#define EMMC_HC_RESPONSE 0x10
-#define EMMC_HC_BUF_DAT_PORT 0x20
-#define EMMC_HC_PRESENT_STATE 0x24
-#define EMMC_HC_HOST_CTRL1 0x28
-#define EMMC_HC_POWER_CTRL 0x29
-#define EMMC_HC_BLK_GAP_CTRL 0x2A
-#define EMMC_HC_WAKEUP_CTRL 0x2B
-#define EMMC_HC_CLOCK_CTRL 0x2C
-#define EMMC_HC_TIMEOUT_CTRL 0x2E
-#define EMMC_HC_SW_RST 0x2F
-#define EMMC_HC_NOR_INT_STS 0x30
-#define EMMC_HC_ERR_INT_STS 0x32
-#define EMMC_HC_NOR_INT_STS_EN 0x34
-#define EMMC_HC_ERR_INT_STS_EN 0x36
-#define EMMC_HC_NOR_INT_SIG_EN 0x38
-#define EMMC_HC_ERR_INT_SIG_EN 0x3A
-#define EMMC_HC_AUTO_CMD_ERR_STS 0x3C
-#define EMMC_HC_HOST_CTRL2 0x3E
-#define EMMC_HC_CAP 0x40
-#define EMMC_HC_MAX_CURRENT_CAP 0x48
-#define EMMC_HC_FORCE_EVT_AUTO_CMD 0x50
-#define EMMC_HC_FORCE_EVT_ERR_INT 0x52
-#define EMMC_HC_ADMA_ERR_STS 0x54
-#define EMMC_HC_ADMA_SYS_ADDR 0x58
-#define EMMC_HC_PRESET_VAL 0x60
-#define EMMC_HC_SHARED_BUS_CTRL 0xE0
-#define EMMC_HC_SLOT_INT_STS 0xFC
-#define EMMC_HC_CTRL_VER 0xFE
-
-//
-// The transfer modes supported by SD Host Controller
-// Simplified Spec 3.0 Table 1-2
-//
-typedef enum {
- EmmcNoData,
- EmmcPioMode,
- EmmcSdmaMode,
- EmmcAdmaMode
-} EMMC_HC_TRANSFER_MODE;
-
-//
-// The maximum data length of each descriptor line
-//
-#define ADMA_MAX_DATA_PER_LINE 0x10000
-#define EMMC_SDMA_BOUNDARY 512 * 1024
-#define EMMC_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1))
-
-typedef enum {
- EmmcCommandTypeBc, // Broadcast commands, no response
- EmmcCommandTypeBcr, // Broadcast commands with response
- EmmcCommandTypeAc, // Addressed(point-to-point) commands
- EmmcCommandTypeAdtc // Addressed(point-to-point) data transfer commands
-} EMMC_COMMAND_TYPE;
-
-typedef enum {
- EmmcResponceTypeR1,
- EmmcResponceTypeR1b,
- EmmcResponceTypeR2,
- EmmcResponceTypeR3,
- EmmcResponceTypeR4,
- EmmcResponceTypeR5,
- EmmcResponceTypeR5b,
- EmmcResponceTypeR6,
- EmmcResponceTypeR7
-} EMMC_RESPONSE_TYPE;
-
-typedef struct _EMMC_COMMAND_BLOCK {
- UINT16 CommandIndex;
- UINT32 CommandArgument;
- UINT32 CommandType; // One of the EMMC_COMMAND_TYPE values
- UINT32 ResponseType; // One of the EMMC_RESPONSE_TYPE values
-} EMMC_COMMAND_BLOCK;
-
-typedef struct _EMMC_STATUS_BLOCK {
- UINT32 Resp0;
- UINT32 Resp1;
- UINT32 Resp2;
- UINT32 Resp3;
-} EMMC_STATUS_BLOCK;
-
-typedef struct _EMMC_COMMAND_PACKET {
- UINT64 Timeout;
- EMMC_COMMAND_BLOCK *EmmcCmdBlk;
- EMMC_STATUS_BLOCK *EmmcStatusBlk;
- VOID *InDataBuffer;
- VOID *OutDataBuffer;
- UINT32 InTransferLength;
- UINT32 OutTransferLength;
-} EMMC_COMMAND_PACKET;
-
-#pragma pack(1)
-
-typedef struct {
- UINT32 Valid : 1;
- UINT32 End : 1;
- UINT32 Int : 1;
- UINT32 Reserved : 1;
- UINT32 Act : 2;
- UINT32 Reserved1 : 10;
- UINT32 Length : 16;
- UINT32 Address;
-} EMMC_HC_ADMA_DESC_LINE;
-
-typedef struct {
- UINT32 TimeoutFreq : 6; // bit 0:5
- UINT32 Reserved : 1; // bit 6
- UINT32 TimeoutUnit : 1; // bit 7
- UINT32 BaseClkFreq : 8; // bit 8:15
- UINT32 MaxBlkLen : 2; // bit 16:17
- UINT32 BusWidth8 : 1; // bit 18
- UINT32 Adma2 : 1; // bit 19
- UINT32 Reserved2 : 1; // bit 20
- UINT32 HighSpeed : 1; // bit 21
- UINT32 Sdma : 1; // bit 22
- UINT32 SuspRes : 1; // bit 23
- UINT32 Voltage33 : 1; // bit 24
- UINT32 Voltage30 : 1; // bit 25
- UINT32 Voltage18 : 1; // bit 26
- UINT32 Reserved3 : 1; // bit 27
- UINT32 SysBus64 : 1; // bit 28
- UINT32 AsyncInt : 1; // bit 29
- UINT32 SlotType : 2; // bit 30:31
- UINT32 Sdr50 : 1; // bit 32
- UINT32 Sdr104 : 1; // bit 33
- UINT32 Ddr50 : 1; // bit 34
- UINT32 Reserved4 : 1; // bit 35
- UINT32 DriverTypeA : 1; // bit 36
- UINT32 DriverTypeC : 1; // bit 37
- UINT32 DriverTypeD : 1; // bit 38
- UINT32 DriverType4 : 1; // bit 39
- UINT32 TimerCount : 4; // bit 40:43
- UINT32 Reserved5 : 1; // bit 44
- UINT32 TuningSDR50 : 1; // bit 45
- UINT32 RetuningMod : 2; // bit 46:47
- UINT32 ClkMultiplier : 8; // bit 48:55
- UINT32 Reserved6 : 7; // bit 56:62
- UINT32 Hs400 : 1; // bit 63
-} EMMC_HC_SLOT_CAP;
-
-#pragma pack()
-
-/**
- Software reset the specified EMMC host controller and enable all interrupts.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The software reset executes successfully.
- @retval Others The software reset fails.
-
-**/
-EFI_STATUS
-EmmcPeimHcReset (
- IN UINTN Bar
- );
-
-/**
- Set all interrupt status bits in Normal and Error Interrupt Status Enable
- register.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The operation executes successfully.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimHcEnableInterrupt (
- IN UINTN Bar
- );
-
-/**
- Get the capability data from the specified slot.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[out] Capability The buffer to store the capability data.
-
- @retval EFI_SUCCESS The operation executes successfully.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimHcGetCapability (
- IN UINTN Bar,
- OUT EMMC_HC_SLOT_CAP *Capability
- );
-
-/**
- Detect whether there is a EMMC card attached at the specified EMMC host controller
- slot.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS There is a EMMC card attached.
- @retval EFI_NO_MEDIA There is not a EMMC card attached.
- @retval Others The detection fails.
-
-**/
-EFI_STATUS
-EmmcPeimHcCardDetect (
- IN UINTN Bar
- );
-
-/**
- Initial EMMC host controller with lowest clock frequency, max power and max timeout value
- at initialization.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The host controller is initialized successfully.
- @retval Others The host controller isn't initialized successfully.
-
-**/
-EFI_STATUS
-EmmcPeimHcInitHost (
- IN UINTN Bar
- );
-
-/**
- Send command SWITCH to the EMMC device to switch the mode of operation of the
- selected Device or modifies the EXT_CSD registers.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] Access The access mode of SWITCH command.
- @param[in] Index The offset of the field to be access.
- @param[in] Value The value to be set to the specified field of EXT_CSD register.
- @param[in] CmdSet The value of CmdSet field of EXT_CSD register.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimSwitch (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN UINT8 Access,
- IN UINT8 Index,
- IN UINT8 Value,
- IN UINT8 CmdSet
- );
-
-/**
- Send command SET_BLOCK_COUNT to the addressed EMMC device to set the number of
- blocks for the following block read/write cmd.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] BlockCount The number of the logical block to access.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimSetBlkCount (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN UINT16 BlockCount
- );
-
-/**
- Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed EMMC device
- to read/write the specified number of blocks.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
- @param[in] Lba The logical block address of starting access.
- @param[in] BlockSize The block size of specified EMMC device partition.
- @param[in] Buffer The pointer to the transfer buffer.
- @param[in] BufferSize The size of transfer buffer.
- @param[in] IsRead Boolean to show the operation direction.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-EmmcPeimRwMultiBlocks (
- IN EMMC_PEIM_HC_SLOT *Slot,
- IN EFI_LBA Lba,
- IN UINT32 BlockSize,
- IN VOID *Buffer,
- IN UINTN BufferSize,
- IN BOOLEAN IsRead
- );
-
-/**
- Execute EMMC device identification procedure.
-
- Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
-
- @param[in] Slot The slot number of the Emmc card to send the command to.
-
- @retval EFI_SUCCESS There is a EMMC card.
- @retval Others There is not a EMMC card.
-
-**/
-EFI_STATUS
-EmmcPeimIdentification (
- IN EMMC_PEIM_HC_SLOT *Slot
- );
-
-/**
- Free the resource used by the TRB.
-
- @param[in] Trb The pointer to the EMMC_TRB instance.
-
-**/
-VOID
-EmmcPeimFreeTrb (
- IN EMMC_TRB *Trb
- );
-
-#endif
+/** @file + + Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EMMC_HCI_H_ +#define _EMMC_HCI_H_ + +// +// EMMC Host Controller MMIO Register Offset +// +#define EMMC_HC_SDMA_ADDR 0x00 +#define EMMC_HC_ARG2 0x00 +#define EMMC_HC_BLK_SIZE 0x04 +#define EMMC_HC_BLK_COUNT 0x06 +#define EMMC_HC_ARG1 0x08 +#define EMMC_HC_TRANS_MOD 0x0C +#define EMMC_HC_COMMAND 0x0E +#define EMMC_HC_RESPONSE 0x10 +#define EMMC_HC_BUF_DAT_PORT 0x20 +#define EMMC_HC_PRESENT_STATE 0x24 +#define EMMC_HC_HOST_CTRL1 0x28 +#define EMMC_HC_POWER_CTRL 0x29 +#define EMMC_HC_BLK_GAP_CTRL 0x2A +#define EMMC_HC_WAKEUP_CTRL 0x2B +#define EMMC_HC_CLOCK_CTRL 0x2C +#define EMMC_HC_TIMEOUT_CTRL 0x2E +#define EMMC_HC_SW_RST 0x2F +#define EMMC_HC_NOR_INT_STS 0x30 +#define EMMC_HC_ERR_INT_STS 0x32 +#define EMMC_HC_NOR_INT_STS_EN 0x34 +#define EMMC_HC_ERR_INT_STS_EN 0x36 +#define EMMC_HC_NOR_INT_SIG_EN 0x38 +#define EMMC_HC_ERR_INT_SIG_EN 0x3A +#define EMMC_HC_AUTO_CMD_ERR_STS 0x3C +#define EMMC_HC_HOST_CTRL2 0x3E +#define EMMC_HC_CAP 0x40 +#define EMMC_HC_MAX_CURRENT_CAP 0x48 +#define EMMC_HC_FORCE_EVT_AUTO_CMD 0x50 +#define EMMC_HC_FORCE_EVT_ERR_INT 0x52 +#define EMMC_HC_ADMA_ERR_STS 0x54 +#define EMMC_HC_ADMA_SYS_ADDR 0x58 +#define EMMC_HC_PRESET_VAL 0x60 +#define EMMC_HC_SHARED_BUS_CTRL 0xE0 +#define EMMC_HC_SLOT_INT_STS 0xFC +#define EMMC_HC_CTRL_VER 0xFE + +// +// The transfer modes supported by SD Host Controller +// Simplified Spec 3.0 Table 1-2 +// +typedef enum { + EmmcNoData, + EmmcPioMode, + EmmcSdmaMode, + EmmcAdmaMode +} EMMC_HC_TRANSFER_MODE; + +// +// The maximum data length of each descriptor line +// +#define ADMA_MAX_DATA_PER_LINE 0x10000 +#define EMMC_SDMA_BOUNDARY 512 * 1024 +#define EMMC_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1)) + +typedef enum { + EmmcCommandTypeBc, // Broadcast commands, no response + EmmcCommandTypeBcr, // Broadcast commands with response + EmmcCommandTypeAc, // Addressed(point-to-point) commands + EmmcCommandTypeAdtc // Addressed(point-to-point) data transfer commands +} EMMC_COMMAND_TYPE; + +typedef enum { + EmmcResponceTypeR1, + EmmcResponceTypeR1b, + EmmcResponceTypeR2, + EmmcResponceTypeR3, + EmmcResponceTypeR4, + EmmcResponceTypeR5, + EmmcResponceTypeR5b, + EmmcResponceTypeR6, + EmmcResponceTypeR7 +} EMMC_RESPONSE_TYPE; + +typedef struct _EMMC_COMMAND_BLOCK { + UINT16 CommandIndex; + UINT32 CommandArgument; + UINT32 CommandType; // One of the EMMC_COMMAND_TYPE values + UINT32 ResponseType; // One of the EMMC_RESPONSE_TYPE values +} EMMC_COMMAND_BLOCK; + +typedef struct _EMMC_STATUS_BLOCK { + UINT32 Resp0; + UINT32 Resp1; + UINT32 Resp2; + UINT32 Resp3; +} EMMC_STATUS_BLOCK; + +typedef struct _EMMC_COMMAND_PACKET { + UINT64 Timeout; + EMMC_COMMAND_BLOCK *EmmcCmdBlk; + EMMC_STATUS_BLOCK *EmmcStatusBlk; + VOID *InDataBuffer; + VOID *OutDataBuffer; + UINT32 InTransferLength; + UINT32 OutTransferLength; +} EMMC_COMMAND_PACKET; + +#pragma pack(1) + +typedef struct { + UINT32 Valid : 1; + UINT32 End : 1; + UINT32 Int : 1; + UINT32 Reserved : 1; + UINT32 Act : 2; + UINT32 Reserved1 : 10; + UINT32 Length : 16; + UINT32 Address; +} EMMC_HC_ADMA_DESC_LINE; + +typedef struct { + UINT32 TimeoutFreq : 6; // bit 0:5 + UINT32 Reserved : 1; // bit 6 + UINT32 TimeoutUnit : 1; // bit 7 + UINT32 BaseClkFreq : 8; // bit 8:15 + UINT32 MaxBlkLen : 2; // bit 16:17 + UINT32 BusWidth8 : 1; // bit 18 + UINT32 Adma2 : 1; // bit 19 + UINT32 Reserved2 : 1; // bit 20 + UINT32 HighSpeed : 1; // bit 21 + UINT32 Sdma : 1; // bit 22 + UINT32 SuspRes : 1; // bit 23 + UINT32 Voltage33 : 1; // bit 24 + UINT32 Voltage30 : 1; // bit 25 + UINT32 Voltage18 : 1; // bit 26 + UINT32 Reserved3 : 1; // bit 27 + UINT32 SysBus64 : 1; // bit 28 + UINT32 AsyncInt : 1; // bit 29 + UINT32 SlotType : 2; // bit 30:31 + UINT32 Sdr50 : 1; // bit 32 + UINT32 Sdr104 : 1; // bit 33 + UINT32 Ddr50 : 1; // bit 34 + UINT32 Reserved4 : 1; // bit 35 + UINT32 DriverTypeA : 1; // bit 36 + UINT32 DriverTypeC : 1; // bit 37 + UINT32 DriverTypeD : 1; // bit 38 + UINT32 DriverType4 : 1; // bit 39 + UINT32 TimerCount : 4; // bit 40:43 + UINT32 Reserved5 : 1; // bit 44 + UINT32 TuningSDR50 : 1; // bit 45 + UINT32 RetuningMod : 2; // bit 46:47 + UINT32 ClkMultiplier : 8; // bit 48:55 + UINT32 Reserved6 : 7; // bit 56:62 + UINT32 Hs400 : 1; // bit 63 +} EMMC_HC_SLOT_CAP; + +#pragma pack() + +/** + Software reset the specified EMMC host controller and enable all interrupts. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The software reset executes successfully. + @retval Others The software reset fails. + +**/ +EFI_STATUS +EmmcPeimHcReset ( + IN UINTN Bar + ); + +/** + Set all interrupt status bits in Normal and Error Interrupt Status Enable + register. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimHcEnableInterrupt ( + IN UINTN Bar + ); + +/** + Get the capability data from the specified slot. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[out] Capability The buffer to store the capability data. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimHcGetCapability ( + IN UINTN Bar, + OUT EMMC_HC_SLOT_CAP *Capability + ); + +/** + Detect whether there is a EMMC card attached at the specified EMMC host controller + slot. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS There is a EMMC card attached. + @retval EFI_NO_MEDIA There is not a EMMC card attached. + @retval Others The detection fails. + +**/ +EFI_STATUS +EmmcPeimHcCardDetect ( + IN UINTN Bar + ); + +/** + Initial EMMC host controller with lowest clock frequency, max power and max timeout value + at initialization. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The host controller is initialized successfully. + @retval Others The host controller isn't initialized successfully. + +**/ +EFI_STATUS +EmmcPeimHcInitHost ( + IN UINTN Bar + ); + +/** + Send command SWITCH to the EMMC device to switch the mode of operation of the + selected Device or modifies the EXT_CSD registers. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] Access The access mode of SWITCH command. + @param[in] Index The offset of the field to be access. + @param[in] Value The value to be set to the specified field of EXT_CSD register. + @param[in] CmdSet The value of CmdSet field of EXT_CSD register. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimSwitch ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN UINT8 Access, + IN UINT8 Index, + IN UINT8 Value, + IN UINT8 CmdSet + ); + +/** + Send command SET_BLOCK_COUNT to the addressed EMMC device to set the number of + blocks for the following block read/write cmd. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] BlockCount The number of the logical block to access. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimSetBlkCount ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN UINT16 BlockCount + ); + +/** + Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed EMMC device + to read/write the specified number of blocks. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + @param[in] Lba The logical block address of starting access. + @param[in] BlockSize The block size of specified EMMC device partition. + @param[in] Buffer The pointer to the transfer buffer. + @param[in] BufferSize The size of transfer buffer. + @param[in] IsRead Boolean to show the operation direction. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +EmmcPeimRwMultiBlocks ( + IN EMMC_PEIM_HC_SLOT *Slot, + IN EFI_LBA Lba, + IN UINT32 BlockSize, + IN VOID *Buffer, + IN UINTN BufferSize, + IN BOOLEAN IsRead + ); + +/** + Execute EMMC device identification procedure. + + Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] Slot The slot number of the Emmc card to send the command to. + + @retval EFI_SUCCESS There is a EMMC card. + @retval Others There is not a EMMC card. + +**/ +EFI_STATUS +EmmcPeimIdentification ( + IN EMMC_PEIM_HC_SLOT *Slot + ); + +/** + Free the resource used by the TRB. + + @param[in] Trb The pointer to the EMMC_TRB instance. + +**/ +VOID +EmmcPeimFreeTrb ( + IN EMMC_TRB *Trb + ); + +#endif diff --git a/MdeModulePkg/Bus/Sd/EmmcDxe/ComponentName.c b/MdeModulePkg/Bus/Sd/EmmcDxe/ComponentName.c index b66bbff824..65c737f20c 100644 --- a/MdeModulePkg/Bus/Sd/EmmcDxe/ComponentName.c +++ b/MdeModulePkg/Bus/Sd/EmmcDxe/ComponentName.c @@ -1,235 +1,235 @@ -/** @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)
- );
-}
+/** @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/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c index 61fa740be5..8f099b5aa1 100644 --- a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c +++ b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c @@ -1,2197 +1,2197 @@ -/** @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 ((
- DEBUG_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. If there is no
- block IO protocol supported by the physical device, the
- value of MediaId is undefined.
- @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. If there is no
- block IO protocol supported by the physical device, the
- value of MediaId is undefined.
- @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. If there is no
- block IO protocol supported by the physical device, the
- value of MediaId is undefined.
- @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;
-}
+/** @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 (( + DEBUG_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. If there is no + block IO protocol supported by the physical device, the + value of MediaId is undefined. + @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. If there is no + block IO protocol supported by the physical device, the + value of MediaId is undefined. + @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. If there is no + block IO protocol supported by the physical device, the + value of MediaId is undefined. + @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/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h index 8c7e5d2675..e1a8ff525a 100644 --- a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h +++ b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h @@ -1,502 +1,502 @@ -/** @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. If there is no
- block IO protocol supported by the physical device, the
- value of MediaId is undefined.
- @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. If there is no
- block IO protocol supported by the physical device, the
- value of MediaId is undefined.
- @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. If there is no
- block IO protocol supported by the physical device, the
- value of MediaId is undefined.
- @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
+/** @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. If there is no + block IO protocol supported by the physical device, the + value of MediaId is undefined. + @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. If there is no + block IO protocol supported by the physical device, the + value of MediaId is undefined. + @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. If there is no + block IO protocol supported by the physical device, the + value of MediaId is undefined. + @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/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.c b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.c index 1f3ab05db9..c3f0c534e9 100644 --- a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.c +++ b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.c @@ -1,134 +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;
-}
+/** @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/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.h b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.h index 44e691ac30..20dce358c9 100644 --- a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.h +++ b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDiskInfo.h @@ -1,109 +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
+/** @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/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c index c780c396e1..a496f272ae 100644 --- a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c +++ b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c @@ -1,1241 +1,1241 @@ -/** @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 ((DEBUG_ERROR, "The EMMC device version is too low, we don't support!!!\n"));
- return EFI_UNSUPPORTED;
- }
-
- if ((ExtCsd->PartitioningSupport & BIT0) != BIT0) {
- DEBUG ((DEBUG_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;
-}
+/** @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 ((DEBUG_ERROR, "The EMMC device version is too low, we don't support!!!\n")); + return EFI_UNSUPPORTED; + } + + if ((ExtCsd->PartitioningSupport & BIT0) != BIT0) { + DEBUG ((DEBUG_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/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h index a83d4ec1df..33ea70d648 100644 --- a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h +++ b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h @@ -1,500 +1,500 @@ -/** @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
+/** @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/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf index ec7da2794b..9c9123b720 100644 --- a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf +++ b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf @@ -1,67 +1,67 @@ -## @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
-
-[UserExtensions.TianoCore."ExtraFiles"]
- EmmcDxeExtra.uni
+## @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 + +[UserExtensions.TianoCore."ExtraFiles"] + EmmcDxeExtra.uni diff --git a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.uni b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.uni index b47ce27bde..41ad3d337f 100644 --- a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.uni +++ b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.uni @@ -1,15 +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."
-
+// /** @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/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxeExtra.uni b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxeExtra.uni index 0f75ea64c5..6d1b008b08 100644 --- a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxeExtra.uni +++ b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxeExtra.uni @@ -1,14 +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"
-
-
+// /** @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" + + diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/DmaMem.c b/MdeModulePkg/Bus/Sd/SdBlockIoPei/DmaMem.c index 3954e2a5d1..3b80728959 100644 --- a/MdeModulePkg/Bus/Sd/SdBlockIoPei/DmaMem.c +++ b/MdeModulePkg/Bus/Sd/SdBlockIoPei/DmaMem.c @@ -1,249 +1,249 @@ -/** @file
- The DMA memory help function.
-
- Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
-
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "SdBlockIoPei.h"
-
-EDKII_IOMMU_PPI *mIoMmu;
-
-/**
- Provides the controller-specific addresses required to access system memory from a
- DMA bus master.
-
- @param Operation Indicates if the bus master is going to read or write to system memory.
- @param HostAddress The system memory address to map to the PCI controller.
- @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
- that were mapped.
- @param DeviceAddress The resulting map address for the bus master PCI controller to use to
- access the hosts HostAddress.
- @param Mapping A resulting value to pass to Unmap().
-
- @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
- @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
- @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
- @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
-
-**/
-EFI_STATUS
-IoMmuMap (
- IN EDKII_IOMMU_OPERATION Operation,
- IN VOID *HostAddress,
- IN OUT UINTN *NumberOfBytes,
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
- OUT VOID **Mapping
- )
-{
- EFI_STATUS Status;
- UINT64 Attribute;
-
- if (mIoMmu != NULL) {
- Status = mIoMmu->Map (
- mIoMmu,
- Operation,
- HostAddress,
- NumberOfBytes,
- DeviceAddress,
- Mapping
- );
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- switch (Operation) {
- case EdkiiIoMmuOperationBusMasterRead:
- case EdkiiIoMmuOperationBusMasterRead64:
- Attribute = EDKII_IOMMU_ACCESS_READ;
- break;
- case EdkiiIoMmuOperationBusMasterWrite:
- case EdkiiIoMmuOperationBusMasterWrite64:
- Attribute = EDKII_IOMMU_ACCESS_WRITE;
- break;
- case EdkiiIoMmuOperationBusMasterCommonBuffer:
- case EdkiiIoMmuOperationBusMasterCommonBuffer64:
- Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;
- break;
- default:
- ASSERT (FALSE);
- return EFI_INVALID_PARAMETER;
- }
-
- Status = mIoMmu->SetAttribute (
- mIoMmu,
- *Mapping,
- Attribute
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- } else {
- *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
- *Mapping = NULL;
- Status = EFI_SUCCESS;
- }
-
- return Status;
-}
-
-/**
- Completes the Map() operation and releases any corresponding resources.
-
- @param Mapping The mapping value returned from Map().
-
- @retval EFI_SUCCESS The range was unmapped.
- @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
- @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
-**/
-EFI_STATUS
-IoMmuUnmap (
- IN VOID *Mapping
- )
-{
- EFI_STATUS Status;
-
- if (mIoMmu != NULL) {
- Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);
- Status = mIoMmu->Unmap (mIoMmu, Mapping);
- } else {
- Status = EFI_SUCCESS;
- }
-
- return Status;
-}
-
-/**
- Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
- OperationBusMasterCommonBuffer64 mapping.
-
- @param Pages The number of pages to allocate.
- @param HostAddress A pointer to store the base system memory address of the
- allocated range.
- @param DeviceAddress The resulting map address for the bus master PCI controller to use to
- access the hosts HostAddress.
- @param Mapping A resulting value to pass to Unmap().
-
- @retval EFI_SUCCESS The requested memory pages were allocated.
- @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
- MEMORY_WRITE_COMBINE and MEMORY_CACHED.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
- @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
-
-**/
-EFI_STATUS
-IoMmuAllocateBuffer (
- IN UINTN Pages,
- OUT VOID **HostAddress,
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
- OUT VOID **Mapping
- )
-{
- EFI_STATUS Status;
- UINTN NumberOfBytes;
- EFI_PHYSICAL_ADDRESS HostPhyAddress;
-
- *HostAddress = NULL;
- *DeviceAddress = 0;
-
- if (mIoMmu != NULL) {
- Status = mIoMmu->AllocateBuffer (
- mIoMmu,
- EfiBootServicesData,
- Pages,
- HostAddress,
- 0
- );
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
- Status = mIoMmu->Map (
- mIoMmu,
- EdkiiIoMmuOperationBusMasterCommonBuffer,
- *HostAddress,
- &NumberOfBytes,
- DeviceAddress,
- Mapping
- );
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Status = mIoMmu->SetAttribute (
- mIoMmu,
- *Mapping,
- EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- } else {
- Status = PeiServicesAllocatePages (
- EfiBootServicesData,
- Pages,
- &HostPhyAddress
- );
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- *HostAddress = (VOID *)(UINTN)HostPhyAddress;
- *DeviceAddress = HostPhyAddress;
- *Mapping = NULL;
- }
-
- return Status;
-}
-
-/**
- Frees memory that was allocated with AllocateBuffer().
-
- @param Pages The number of pages to free.
- @param HostAddress The base system memory address of the allocated range.
- @param Mapping The mapping value returned from Map().
-
- @retval EFI_SUCCESS The requested memory pages were freed.
- @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
- was not allocated with AllocateBuffer().
-
-**/
-EFI_STATUS
-IoMmuFreeBuffer (
- IN UINTN Pages,
- IN VOID *HostAddress,
- IN VOID *Mapping
- )
-{
- EFI_STATUS Status;
-
- if (mIoMmu != NULL) {
- Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);
- Status = mIoMmu->Unmap (mIoMmu, Mapping);
- Status = mIoMmu->FreeBuffer (mIoMmu, Pages, HostAddress);
- } else {
- Status = EFI_SUCCESS;
- }
-
- return Status;
-}
-
-/**
- Initialize IOMMU.
-**/
-VOID
-IoMmuInit (
- VOID
- )
-{
- PeiServicesLocatePpi (
- &gEdkiiIoMmuPpiGuid,
- 0,
- NULL,
- (VOID **)&mIoMmu
- );
-}
+/** @file + The DMA memory help function. + + Copyright (c) 2017, Intel Corporation. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SdBlockIoPei.h" + +EDKII_IOMMU_PPI *mIoMmu; + +/** + Provides the controller-specific addresses required to access system memory from a + DMA bus master. + + @param Operation Indicates if the bus master is going to read or write to system memory. + @param HostAddress The system memory address to map to the PCI controller. + @param NumberOfBytes On input the number of bytes to map. On output the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + +**/ +EFI_STATUS +IoMmuMap ( + IN EDKII_IOMMU_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + EFI_STATUS Status; + UINT64 Attribute; + + if (mIoMmu != NULL) { + Status = mIoMmu->Map ( + mIoMmu, + Operation, + HostAddress, + NumberOfBytes, + DeviceAddress, + Mapping + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + switch (Operation) { + case EdkiiIoMmuOperationBusMasterRead: + case EdkiiIoMmuOperationBusMasterRead64: + Attribute = EDKII_IOMMU_ACCESS_READ; + break; + case EdkiiIoMmuOperationBusMasterWrite: + case EdkiiIoMmuOperationBusMasterWrite64: + Attribute = EDKII_IOMMU_ACCESS_WRITE; + break; + case EdkiiIoMmuOperationBusMasterCommonBuffer: + case EdkiiIoMmuOperationBusMasterCommonBuffer64: + Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE; + break; + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + Status = mIoMmu->SetAttribute ( + mIoMmu, + *Mapping, + Attribute + ); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress; + *Mapping = NULL; + Status = EFI_SUCCESS; + } + + return Status; +} + +/** + Completes the Map() operation and releases any corresponding resources. + + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map(). + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. +**/ +EFI_STATUS +IoMmuUnmap ( + IN VOID *Mapping + ) +{ + EFI_STATUS Status; + + if (mIoMmu != NULL) { + Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0); + Status = mIoMmu->Unmap (mIoMmu, Mapping); + } else { + Status = EFI_SUCCESS; + } + + return Status; +} + +/** + Allocates pages that are suitable for an OperationBusMasterCommonBuffer or + OperationBusMasterCommonBuffer64 mapping. + + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +IoMmuAllocateBuffer ( + IN UINTN Pages, + OUT VOID **HostAddress, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + EFI_STATUS Status; + UINTN NumberOfBytes; + EFI_PHYSICAL_ADDRESS HostPhyAddress; + + *HostAddress = NULL; + *DeviceAddress = 0; + + if (mIoMmu != NULL) { + Status = mIoMmu->AllocateBuffer ( + mIoMmu, + EfiBootServicesData, + Pages, + HostAddress, + 0 + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + NumberOfBytes = EFI_PAGES_TO_SIZE (Pages); + Status = mIoMmu->Map ( + mIoMmu, + EdkiiIoMmuOperationBusMasterCommonBuffer, + *HostAddress, + &NumberOfBytes, + DeviceAddress, + Mapping + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + Status = mIoMmu->SetAttribute ( + mIoMmu, + *Mapping, + EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE + ); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + Status = PeiServicesAllocatePages ( + EfiBootServicesData, + Pages, + &HostPhyAddress + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + *HostAddress = (VOID *)(UINTN)HostPhyAddress; + *DeviceAddress = HostPhyAddress; + *Mapping = NULL; + } + + return Status; +} + +/** + Frees memory that was allocated with AllocateBuffer(). + + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages + was not allocated with AllocateBuffer(). + +**/ +EFI_STATUS +IoMmuFreeBuffer ( + IN UINTN Pages, + IN VOID *HostAddress, + IN VOID *Mapping + ) +{ + EFI_STATUS Status; + + if (mIoMmu != NULL) { + Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0); + Status = mIoMmu->Unmap (mIoMmu, Mapping); + Status = mIoMmu->FreeBuffer (mIoMmu, Pages, HostAddress); + } else { + Status = EFI_SUCCESS; + } + + return Status; +} + +/** + Initialize IOMMU. +**/ +VOID +IoMmuInit ( + VOID + ) +{ + PeiServicesLocatePpi ( + &gEdkiiIoMmuPpiGuid, + 0, + NULL, + (VOID **)&mIoMmu + ); +} diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c index 06058e9ea0..53f6545382 100644 --- a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c +++ b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c @@ -1,660 +1,660 @@ -/** @file
-
- Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "SdBlockIoPei.h"
-
-//
-// Template for SD HC Slot Data.
-//
-SD_PEIM_HC_SLOT gSdHcSlotTemplate = {
- SD_PEIM_SLOT_SIG, // Signature
- { // Media
- MSG_SD_DP,
- FALSE,
- TRUE,
- FALSE,
- 0x200,
- 0
- },
- 0, // SdHcBase
- { // Capability
- 0,
- },
- { // Csd
- 0,
- },
- TRUE, // SectorAddressing
- NULL // Private
-};
-
-//
-// Template for SD HC Private Data.
-//
-SD_PEIM_HC_PRIVATE_DATA gSdHcPrivateTemplate = {
- SD_PEIM_SIG, // Signature
- NULL, // Pool
- { // BlkIoPpi
- SdBlockIoPeimGetDeviceNo,
- SdBlockIoPeimGetMediaInfo,
- SdBlockIoPeimReadBlocks
- },
- { // BlkIo2Ppi
- EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,
- SdBlockIoPeimGetDeviceNo2,
- SdBlockIoPeimGetMediaInfo2,
- SdBlockIoPeimReadBlocks2
- },
- { // BlkIoPpiList
- EFI_PEI_PPI_DESCRIPTOR_PPI,
- &gEfiPeiVirtualBlockIoPpiGuid,
- NULL
- },
- { // BlkIo2PpiList
- EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
- &gEfiPeiVirtualBlockIo2PpiGuid,
- NULL
- },
- {
- (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
- &gEfiEndOfPeiSignalPpiGuid,
- SdBlockIoPeimEndOfPei
- },
- { // Slot
- {
- 0,
- },
- {
- 0,
- },
- {
- 0,
- },
- {
- 0,
- },
- {
- 0,
- },
- {
- 0,
- }
- },
- 0, // SlotNum
- 0 // TotalBlkIoDevices
-};
-
-/**
- Gets the count of block I/O devices that one specific block driver detects.
-
- This function is used for getting the count of block I/O devices that one
- specific block driver detects. To the PEI ATAPI driver, it returns the number
- of all the detected ATAPI devices it detects during the enumeration process.
- To the PEI legacy floppy driver, it returns the number of all the legacy
- devices it finds during its enumeration process. If no device is detected,
- then the function will return zero.
-
- @param[in] PeiServices General-purpose services that are available
- to every PEIM.
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
- instance.
- @param[out] NumberBlockDevices The number of block I/O devices discovered.
-
- @retval EFI_SUCCESS The operation performed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-SdBlockIoPeimGetDeviceNo (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
- OUT UINTN *NumberBlockDevices
- )
-{
- SD_PEIM_HC_PRIVATE_DATA *Private;
-
- Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
- *NumberBlockDevices = Private->TotalBlkIoDevices;
- return EFI_SUCCESS;
-}
-
-/**
- Gets a block device's media information.
-
- This function will provide the caller with the specified block device's media
- information. If the media changes, calling this function will update the media
- information accordingly.
-
- @param[in] PeiServices General-purpose services that are available to every
- PEIM
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
- @param[in] DeviceIndex Specifies the block device to which the function wants
- to talk. Because the driver that implements Block I/O
- PPIs will manage multiple block devices, the PPIs that
- want to talk to a single device must specify the
- device index that was assigned during the enumeration
- process. This index is a number from one to
- NumberBlockDevices.
- @param[out] MediaInfo The media information of the specified block media.
- The caller is responsible for the ownership of this
- data structure.
-
- @par Note:
- The MediaInfo structure describes an enumeration of possible block device
- types. This enumeration exists because no device paths are actually passed
- across interfaces that describe the type or class of hardware that is publishing
- the block I/O interface. This enumeration will allow for policy decisions
- in the Recovery PEIM, such as "Try to recover from legacy floppy first,
- LS-120 second, CD-ROM third." If there are multiple partitions abstracted
- by a given device type, they should be reported in ascending order; this
- order also applies to nested partitions, such as legacy MBR, where the
- outermost partitions would have precedence in the reporting order. The
- same logic applies to systems such as IDE that have precedence relationships
- like "Master/Slave" or "Primary/Secondary". The master device should be
- reported first, the slave second.
-
- @retval EFI_SUCCESS Media information about the specified block device
- was obtained successfully.
- @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
- error.
-
-**/
-EFI_STATUS
-EFIAPI
-SdBlockIoPeimGetMediaInfo (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
- IN UINTN DeviceIndex,
- OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
- )
-{
- SD_PEIM_HC_PRIVATE_DATA *Private;
-
- Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
-
- if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices) || (DeviceIndex > SD_PEIM_MAX_SLOTS)) {
- return EFI_INVALID_PARAMETER;
- }
-
- MediaInfo->DeviceType = SD;
- MediaInfo->MediaPresent = TRUE;
- MediaInfo->LastBlock = (UINTN)Private->Slot[DeviceIndex - 1].Media.LastBlock;
- MediaInfo->BlockSize = Private->Slot[DeviceIndex - 1].Media.BlockSize;
-
- return EFI_SUCCESS;
-}
-
-/**
- Reads the requested number of blocks from the specified block device.
-
- The function reads the requested number of blocks from the device. All the
- blocks are read, or an error is returned. If there is no media in the device,
- the function returns EFI_NO_MEDIA.
-
- @param[in] PeiServices General-purpose services that are available to
- every PEIM.
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
- @param[in] DeviceIndex Specifies the block device to which the function wants
- to talk. Because the driver that implements Block I/O
- PPIs will manage multiple block devices, PPIs that
- want to talk to a single device must specify the device
- index that was assigned during the enumeration process.
- This index is a number from one to NumberBlockDevices.
- @param[in] StartLBA The starting logical block address (LBA) to read from
- on the device
- @param[in] BufferSize The size of the Buffer in bytes. This number must be
- a multiple of the intrinsic block size of the device.
- @param[out] Buffer A pointer to the destination buffer for the data.
- The caller is responsible for the 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 attempting
- to perform the read operation.
- @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
- valid, or the buffer is not properly aligned.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
- the intrinsic block size of the device.
-
-**/
-EFI_STATUS
-EFIAPI
-SdBlockIoPeimReadBlocks (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
- IN UINTN DeviceIndex,
- IN EFI_PEI_LBA StartLBA,
- IN UINTN BufferSize,
- OUT VOID *Buffer
- )
-{
- EFI_STATUS Status;
- UINT32 BlockSize;
- UINTN NumberOfBlocks;
- SD_PEIM_HC_PRIVATE_DATA *Private;
- UINTN Remaining;
- UINT32 MaxBlock;
-
- Status = EFI_SUCCESS;
- Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
-
- //
- // Check parameters
- //
- if (Buffer == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (BufferSize == 0) {
- return EFI_SUCCESS;
- }
-
- if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices) || (DeviceIndex > SD_PEIM_MAX_SLOTS)) {
- return EFI_INVALID_PARAMETER;
- }
-
- BlockSize = Private->Slot[DeviceIndex - 1].Media.BlockSize;
- if (BufferSize % BlockSize != 0) {
- return EFI_BAD_BUFFER_SIZE;
- }
-
- if (StartLBA > Private->Slot[DeviceIndex - 1].Media.LastBlock) {
- return EFI_INVALID_PARAMETER;
- }
-
- NumberOfBlocks = BufferSize / BlockSize;
-
- //
- // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
- //
- Remaining = NumberOfBlocks;
- MaxBlock = 0xFFFF;
-
- while (Remaining > 0) {
- if (Remaining <= MaxBlock) {
- NumberOfBlocks = Remaining;
- } else {
- NumberOfBlocks = MaxBlock;
- }
-
- BufferSize = NumberOfBlocks * BlockSize;
- if (NumberOfBlocks != 1) {
- Status = SdPeimRwMultiBlocks (&Private->Slot[DeviceIndex - 1], StartLBA, BlockSize, Buffer, BufferSize, TRUE);
- } else {
- Status = SdPeimRwSingleBlock (&Private->Slot[DeviceIndex - 1], StartLBA, BlockSize, Buffer, BufferSize, TRUE);
- }
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- StartLBA += NumberOfBlocks;
- Buffer = (UINT8 *)Buffer + BufferSize;
- Remaining -= NumberOfBlocks;
- }
-
- return Status;
-}
-
-/**
- Gets the count of block I/O devices that one specific block driver detects.
-
- This function is used for getting the count of block I/O devices that one
- specific block driver detects. To the PEI ATAPI driver, it returns the number
- of all the detected ATAPI devices it detects during the enumeration process.
- To the PEI legacy floppy driver, it returns the number of all the legacy
- devices it finds during its enumeration process. If no device is detected,
- then the function will return zero.
-
- @param[in] PeiServices General-purpose services that are available
- to every PEIM.
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
- instance.
- @param[out] NumberBlockDevices The number of block I/O devices discovered.
-
- @retval EFI_SUCCESS The operation performed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-SdBlockIoPeimGetDeviceNo2 (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
- OUT UINTN *NumberBlockDevices
- )
-{
- SD_PEIM_HC_PRIVATE_DATA *Private;
-
- Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
- *NumberBlockDevices = Private->TotalBlkIoDevices;
-
- return EFI_SUCCESS;
-}
-
-/**
- Gets a block device's media information.
-
- This function will provide the caller with the specified block device's media
- information. If the media changes, calling this function will update the media
- information accordingly.
-
- @param[in] PeiServices General-purpose services that are available to every
- PEIM
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
- @param[in] DeviceIndex Specifies the block device to which the function wants
- to talk. Because the driver that implements Block I/O
- PPIs will manage multiple block devices, the PPIs that
- want to talk to a single device must specify the
- device index that was assigned during the enumeration
- process. This index is a number from one to
- NumberBlockDevices.
- @param[out] MediaInfo The media information of the specified block media.
- The caller is responsible for the ownership of this
- data structure.
-
- @par Note:
- The MediaInfo structure describes an enumeration of possible block device
- types. This enumeration exists because no device paths are actually passed
- across interfaces that describe the type or class of hardware that is publishing
- the block I/O interface. This enumeration will allow for policy decisions
- in the Recovery PEIM, such as "Try to recover from legacy floppy first,
- LS-120 second, CD-ROM third." If there are multiple partitions abstracted
- by a given device type, they should be reported in ascending order; this
- order also applies to nested partitions, such as legacy MBR, where the
- outermost partitions would have precedence in the reporting order. The
- same logic applies to systems such as IDE that have precedence relationships
- like "Master/Slave" or "Primary/Secondary". The master device should be
- reported first, the slave second.
-
- @retval EFI_SUCCESS Media information about the specified block device
- was obtained successfully.
- @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
- error.
-
-**/
-EFI_STATUS
-EFIAPI
-SdBlockIoPeimGetMediaInfo2 (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
- IN UINTN DeviceIndex,
- OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
- )
-{
- EFI_STATUS Status;
- SD_PEIM_HC_PRIVATE_DATA *Private;
- EFI_PEI_BLOCK_IO_MEDIA Media;
-
- Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
-
- Status = SdBlockIoPeimGetMediaInfo (
- PeiServices,
- &Private->BlkIoPpi,
- DeviceIndex,
- &Media
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- CopyMem (MediaInfo, &(Private->Slot[DeviceIndex - 1].Media), sizeof (EFI_PEI_BLOCK_IO2_MEDIA));
- return EFI_SUCCESS;
-}
-
-/**
- Reads the requested number of blocks from the specified block device.
-
- The function reads the requested number of blocks from the device. All the
- blocks are read, or an error is returned. If there is no media in the device,
- the function returns EFI_NO_MEDIA.
-
- @param[in] PeiServices General-purpose services that are available to
- every PEIM.
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
- @param[in] DeviceIndex Specifies the block device to which the function wants
- to talk. Because the driver that implements Block I/O
- PPIs will manage multiple block devices, PPIs that
- want to talk to a single device must specify the device
- index that was assigned during the enumeration process.
- This index is a number from one to NumberBlockDevices.
- @param[in] StartLBA The starting logical block address (LBA) to read from
- on the device
- @param[in] BufferSize The size of the Buffer in bytes. This number must be
- a multiple of the intrinsic block size of the device.
- @param[out] Buffer A pointer to the destination buffer for the data.
- The caller is responsible for the 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 attempting
- to perform the read operation.
- @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
- valid, or the buffer is not properly aligned.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
- the intrinsic block size of the device.
-
-**/
-EFI_STATUS
-EFIAPI
-SdBlockIoPeimReadBlocks2 (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
- IN UINTN DeviceIndex,
- IN EFI_PEI_LBA StartLBA,
- IN UINTN BufferSize,
- OUT VOID *Buffer
- )
-{
- EFI_STATUS Status;
- SD_PEIM_HC_PRIVATE_DATA *Private;
-
- Status = EFI_SUCCESS;
- Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
-
- Status = SdBlockIoPeimReadBlocks (
- PeiServices,
- &Private->BlkIoPpi,
- DeviceIndex,
- StartLBA,
- BufferSize,
- Buffer
- );
- return Status;
-}
-
-/**
- One notified function to cleanup the allocated DMA buffers at the end of PEI.
-
- @param[in] PeiServices Pointer to PEI Services Table.
- @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
- event that caused this function to execute.
- @param[in] Ppi Pointer to the PPI data associated with this function.
-
- @retval EFI_SUCCESS The function completes successfully
-
-**/
-EFI_STATUS
-EFIAPI
-SdBlockIoPeimEndOfPei (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
- IN VOID *Ppi
- )
-{
- SD_PEIM_HC_PRIVATE_DATA *Private;
-
- Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);
-
- if ((Private->Pool != NULL) && (Private->Pool->Head != NULL)) {
- SdPeimFreeMemPool (Private->Pool);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- The user code starts with this function.
-
- @param FileHandle Handle of the file being invoked.
- @param PeiServices Describes the list of possible PEI Services.
-
- @retval EFI_SUCCESS The driver is successfully initialized.
- @retval Others Can't initialize the driver.
-
-**/
-EFI_STATUS
-EFIAPI
-InitializeSdBlockIoPeim (
- IN EFI_PEI_FILE_HANDLE FileHandle,
- IN CONST EFI_PEI_SERVICES **PeiServices
- )
-{
- EFI_STATUS Status;
- SD_PEIM_HC_PRIVATE_DATA *Private;
- EDKII_SD_MMC_HOST_CONTROLLER_PPI *SdMmcHcPpi;
- UINT32 Index;
- UINTN *MmioBase;
- UINT8 BarNum;
- UINT8 SlotNum;
- UINT8 Controller;
- UINT64 Capacity;
- SD_HC_SLOT_CAP Capability;
- SD_PEIM_HC_SLOT *Slot;
- SD_CSD *Csd;
- SD_CSD2 *Csd2;
- UINT32 CSize;
- UINT32 CSizeMul;
- UINT32 ReadBlLen;
-
- //
- // Shadow this PEIM to run from memory
- //
- if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
- return EFI_SUCCESS;
- }
-
- //
- // locate Sd host controller PPI
- //
- Status = PeiServicesLocatePpi (
- &gEdkiiPeiSdMmcHostControllerPpiGuid,
- 0,
- NULL,
- (VOID **)&SdMmcHcPpi
- );
- if (EFI_ERROR (Status)) {
- return EFI_DEVICE_ERROR;
- }
-
- IoMmuInit ();
-
- Controller = 0;
- MmioBase = NULL;
- while (TRUE) {
- Status = SdMmcHcPpi->GetSdMmcHcMmioBar (SdMmcHcPpi, Controller, &MmioBase, &BarNum);
- //
- // When status is error, meant no controller is found
- //
- if (EFI_ERROR (Status)) {
- break;
- }
-
- if (BarNum == 0) {
- Controller++;
- continue;
- }
-
- Private = AllocateCopyPool (sizeof (SD_PEIM_HC_PRIVATE_DATA), &gSdHcPrivateTemplate);
- if (Private == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- break;
- }
-
- Private->BlkIoPpiList.Ppi = (VOID *)&Private->BlkIoPpi;
- Private->BlkIo2PpiList.Ppi = (VOID *)&Private->BlkIo2Ppi;
- //
- // Initialize the memory pool which will be used in all transactions.
- //
- Status = SdPeimInitMemPool (Private);
- if (EFI_ERROR (Status)) {
- Status = EFI_OUT_OF_RESOURCES;
- break;
- }
-
- for (Index = 0; Index < BarNum; Index++) {
- Status = SdPeimHcGetCapability (MmioBase[Index], &Capability);
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- if (Capability.SlotType != 0x1) {
- DEBUG ((DEBUG_INFO, "The slot at 0x%x is not embedded slot type\n", MmioBase[Index]));
- Status = EFI_UNSUPPORTED;
- continue;
- }
-
- Status = SdPeimHcReset (MmioBase[Index]);
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- Status = SdPeimHcCardDetect (MmioBase[Index]);
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- Status = SdPeimHcInitHost (MmioBase[Index]);
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- SlotNum = Private->SlotNum;
- Slot = &Private->Slot[SlotNum];
- CopyMem (Slot, &gSdHcSlotTemplate, sizeof (SD_PEIM_HC_SLOT));
- Slot->Private = Private;
- Slot->SdHcBase = MmioBase[Index];
- CopyMem (&Slot->Capability, &Capability, sizeof (Capability));
-
- Status = SdPeimIdentification (Slot);
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- Csd = &Slot->Csd;
- if (Csd->CsdStructure == 0) {
- Slot->SectorAddressing = FALSE;
- CSize = (Csd->CSizeHigh << 2 | Csd->CSizeLow) + 1;
- CSizeMul = (1 << (Csd->CSizeMul + 2));
- ReadBlLen = (1 << (Csd->ReadBlLen));
- Capacity = MultU64x32 (MultU64x32 ((UINT64)CSize, CSizeMul), ReadBlLen);
- } else {
- Slot->SectorAddressing = TRUE;
- Csd2 = (SD_CSD2 *)(VOID *)Csd;
- CSize = (Csd2->CSizeHigh << 16 | Csd2->CSizeLow) + 1;
- Capacity = MultU64x32 ((UINT64)CSize, SIZE_512KB);
- }
-
- Slot->Media.LastBlock = DivU64x32 (Capacity, Slot->Media.BlockSize) - 1;
-
- Private->TotalBlkIoDevices++;
- Private->SlotNum++;
- }
-
- Controller++;
- if (!EFI_ERROR (Status)) {
- PeiServicesInstallPpi (&Private->BlkIoPpiList);
- PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);
- } else {
- if (Private->Pool->Head != NULL) {
- SdPeimFreeMemPool (Private->Pool);
- }
- }
- }
-
- return EFI_SUCCESS;
-}
+/** @file + + Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SdBlockIoPei.h" + +// +// Template for SD HC Slot Data. +// +SD_PEIM_HC_SLOT gSdHcSlotTemplate = { + SD_PEIM_SLOT_SIG, // Signature + { // Media + MSG_SD_DP, + FALSE, + TRUE, + FALSE, + 0x200, + 0 + }, + 0, // SdHcBase + { // Capability + 0, + }, + { // Csd + 0, + }, + TRUE, // SectorAddressing + NULL // Private +}; + +// +// Template for SD HC Private Data. +// +SD_PEIM_HC_PRIVATE_DATA gSdHcPrivateTemplate = { + SD_PEIM_SIG, // Signature + NULL, // Pool + { // BlkIoPpi + SdBlockIoPeimGetDeviceNo, + SdBlockIoPeimGetMediaInfo, + SdBlockIoPeimReadBlocks + }, + { // BlkIo2Ppi + EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION, + SdBlockIoPeimGetDeviceNo2, + SdBlockIoPeimGetMediaInfo2, + SdBlockIoPeimReadBlocks2 + }, + { // BlkIoPpiList + EFI_PEI_PPI_DESCRIPTOR_PPI, + &gEfiPeiVirtualBlockIoPpiGuid, + NULL + }, + { // BlkIo2PpiList + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gEfiPeiVirtualBlockIo2PpiGuid, + NULL + }, + { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiEndOfPeiSignalPpiGuid, + SdBlockIoPeimEndOfPei + }, + { // Slot + { + 0, + }, + { + 0, + }, + { + 0, + }, + { + 0, + }, + { + 0, + }, + { + 0, + } + }, + 0, // SlotNum + 0 // TotalBlkIoDevices +}; + +/** + Gets the count of block I/O devices that one specific block driver detects. + + This function is used for getting the count of block I/O devices that one + specific block driver detects. To the PEI ATAPI driver, it returns the number + of all the detected ATAPI devices it detects during the enumeration process. + To the PEI legacy floppy driver, it returns the number of all the legacy + devices it finds during its enumeration process. If no device is detected, + then the function will return zero. + + @param[in] PeiServices General-purpose services that are available + to every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI + instance. + @param[out] NumberBlockDevices The number of block I/O devices discovered. + + @retval EFI_SUCCESS The operation performed successfully. + +**/ +EFI_STATUS +EFIAPI +SdBlockIoPeimGetDeviceNo ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + OUT UINTN *NumberBlockDevices + ) +{ + SD_PEIM_HC_PRIVATE_DATA *Private; + + Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This); + *NumberBlockDevices = Private->TotalBlkIoDevices; + return EFI_SUCCESS; +} + +/** + Gets a block device's media information. + + This function will provide the caller with the specified block device's media + information. If the media changes, calling this function will update the media + information accordingly. + + @param[in] PeiServices General-purpose services that are available to every + PEIM + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, the PPIs that + want to talk to a single device must specify the + device index that was assigned during the enumeration + process. This index is a number from one to + NumberBlockDevices. + @param[out] MediaInfo The media information of the specified block media. + The caller is responsible for the ownership of this + data structure. + + @par Note: + The MediaInfo structure describes an enumeration of possible block device + types. This enumeration exists because no device paths are actually passed + across interfaces that describe the type or class of hardware that is publishing + the block I/O interface. This enumeration will allow for policy decisions + in the Recovery PEIM, such as "Try to recover from legacy floppy first, + LS-120 second, CD-ROM third." If there are multiple partitions abstracted + by a given device type, they should be reported in ascending order; this + order also applies to nested partitions, such as legacy MBR, where the + outermost partitions would have precedence in the reporting order. The + same logic applies to systems such as IDE that have precedence relationships + like "Master/Slave" or "Primary/Secondary". The master device should be + reported first, the slave second. + + @retval EFI_SUCCESS Media information about the specified block device + was obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware + error. + +**/ +EFI_STATUS +EFIAPI +SdBlockIoPeimGetMediaInfo ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + IN UINTN DeviceIndex, + OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo + ) +{ + SD_PEIM_HC_PRIVATE_DATA *Private; + + Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This); + + if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices) || (DeviceIndex > SD_PEIM_MAX_SLOTS)) { + return EFI_INVALID_PARAMETER; + } + + MediaInfo->DeviceType = SD; + MediaInfo->MediaPresent = TRUE; + MediaInfo->LastBlock = (UINTN)Private->Slot[DeviceIndex - 1].Media.LastBlock; + MediaInfo->BlockSize = Private->Slot[DeviceIndex - 1].Media.BlockSize; + + return EFI_SUCCESS; +} + +/** + Reads the requested number of blocks from the specified block device. + + The function reads the requested number of blocks from the device. All the + blocks are read, or an error is returned. If there is no media in the device, + the function returns EFI_NO_MEDIA. + + @param[in] PeiServices General-purpose services that are available to + every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, PPIs that + want to talk to a single device must specify the device + index that was assigned during the enumeration process. + This index is a number from one to NumberBlockDevices. + @param[in] StartLBA The starting logical block address (LBA) to read from + on the device + @param[in] BufferSize The size of the Buffer in bytes. This number must be + a multiple of the intrinsic block size of the device. + @param[out] Buffer A pointer to the destination buffer for the data. + The caller is responsible for the 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 attempting + to perform the read operation. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not + valid, or the buffer is not properly aligned. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of + the intrinsic block size of the device. + +**/ +EFI_STATUS +EFIAPI +SdBlockIoPeimReadBlocks ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + IN UINTN DeviceIndex, + IN EFI_PEI_LBA StartLBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT32 BlockSize; + UINTN NumberOfBlocks; + SD_PEIM_HC_PRIVATE_DATA *Private; + UINTN Remaining; + UINT32 MaxBlock; + + Status = EFI_SUCCESS; + Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This); + + // + // Check parameters + // + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices) || (DeviceIndex > SD_PEIM_MAX_SLOTS)) { + return EFI_INVALID_PARAMETER; + } + + BlockSize = Private->Slot[DeviceIndex - 1].Media.BlockSize; + if (BufferSize % BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (StartLBA > Private->Slot[DeviceIndex - 1].Media.LastBlock) { + return EFI_INVALID_PARAMETER; + } + + NumberOfBlocks = BufferSize / BlockSize; + + // + // Start to execute data transfer. The max block number in single cmd is 65535 blocks. + // + Remaining = NumberOfBlocks; + MaxBlock = 0xFFFF; + + while (Remaining > 0) { + if (Remaining <= MaxBlock) { + NumberOfBlocks = Remaining; + } else { + NumberOfBlocks = MaxBlock; + } + + BufferSize = NumberOfBlocks * BlockSize; + if (NumberOfBlocks != 1) { + Status = SdPeimRwMultiBlocks (&Private->Slot[DeviceIndex - 1], StartLBA, BlockSize, Buffer, BufferSize, TRUE); + } else { + Status = SdPeimRwSingleBlock (&Private->Slot[DeviceIndex - 1], StartLBA, BlockSize, Buffer, BufferSize, TRUE); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + StartLBA += NumberOfBlocks; + Buffer = (UINT8 *)Buffer + BufferSize; + Remaining -= NumberOfBlocks; + } + + return Status; +} + +/** + Gets the count of block I/O devices that one specific block driver detects. + + This function is used for getting the count of block I/O devices that one + specific block driver detects. To the PEI ATAPI driver, it returns the number + of all the detected ATAPI devices it detects during the enumeration process. + To the PEI legacy floppy driver, it returns the number of all the legacy + devices it finds during its enumeration process. If no device is detected, + then the function will return zero. + + @param[in] PeiServices General-purpose services that are available + to every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI + instance. + @param[out] NumberBlockDevices The number of block I/O devices discovered. + + @retval EFI_SUCCESS The operation performed successfully. + +**/ +EFI_STATUS +EFIAPI +SdBlockIoPeimGetDeviceNo2 ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, + OUT UINTN *NumberBlockDevices + ) +{ + SD_PEIM_HC_PRIVATE_DATA *Private; + + Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This); + *NumberBlockDevices = Private->TotalBlkIoDevices; + + return EFI_SUCCESS; +} + +/** + Gets a block device's media information. + + This function will provide the caller with the specified block device's media + information. If the media changes, calling this function will update the media + information accordingly. + + @param[in] PeiServices General-purpose services that are available to every + PEIM + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, the PPIs that + want to talk to a single device must specify the + device index that was assigned during the enumeration + process. This index is a number from one to + NumberBlockDevices. + @param[out] MediaInfo The media information of the specified block media. + The caller is responsible for the ownership of this + data structure. + + @par Note: + The MediaInfo structure describes an enumeration of possible block device + types. This enumeration exists because no device paths are actually passed + across interfaces that describe the type or class of hardware that is publishing + the block I/O interface. This enumeration will allow for policy decisions + in the Recovery PEIM, such as "Try to recover from legacy floppy first, + LS-120 second, CD-ROM third." If there are multiple partitions abstracted + by a given device type, they should be reported in ascending order; this + order also applies to nested partitions, such as legacy MBR, where the + outermost partitions would have precedence in the reporting order. The + same logic applies to systems such as IDE that have precedence relationships + like "Master/Slave" or "Primary/Secondary". The master device should be + reported first, the slave second. + + @retval EFI_SUCCESS Media information about the specified block device + was obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware + error. + +**/ +EFI_STATUS +EFIAPI +SdBlockIoPeimGetMediaInfo2 ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, + IN UINTN DeviceIndex, + OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo + ) +{ + EFI_STATUS Status; + SD_PEIM_HC_PRIVATE_DATA *Private; + EFI_PEI_BLOCK_IO_MEDIA Media; + + Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This); + + Status = SdBlockIoPeimGetMediaInfo ( + PeiServices, + &Private->BlkIoPpi, + DeviceIndex, + &Media + ); + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem (MediaInfo, &(Private->Slot[DeviceIndex - 1].Media), sizeof (EFI_PEI_BLOCK_IO2_MEDIA)); + return EFI_SUCCESS; +} + +/** + Reads the requested number of blocks from the specified block device. + + The function reads the requested number of blocks from the device. All the + blocks are read, or an error is returned. If there is no media in the device, + the function returns EFI_NO_MEDIA. + + @param[in] PeiServices General-purpose services that are available to + every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, PPIs that + want to talk to a single device must specify the device + index that was assigned during the enumeration process. + This index is a number from one to NumberBlockDevices. + @param[in] StartLBA The starting logical block address (LBA) to read from + on the device + @param[in] BufferSize The size of the Buffer in bytes. This number must be + a multiple of the intrinsic block size of the device. + @param[out] Buffer A pointer to the destination buffer for the data. + The caller is responsible for the 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 attempting + to perform the read operation. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not + valid, or the buffer is not properly aligned. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of + the intrinsic block size of the device. + +**/ +EFI_STATUS +EFIAPI +SdBlockIoPeimReadBlocks2 ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, + IN UINTN DeviceIndex, + IN EFI_PEI_LBA StartLBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + SD_PEIM_HC_PRIVATE_DATA *Private; + + Status = EFI_SUCCESS; + Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This); + + Status = SdBlockIoPeimReadBlocks ( + PeiServices, + &Private->BlkIoPpi, + DeviceIndex, + StartLBA, + BufferSize, + Buffer + ); + return Status; +} + +/** + One notified function to cleanup the allocated DMA buffers at the end of PEI. + + @param[in] PeiServices Pointer to PEI Services Table. + @param[in] NotifyDescriptor Pointer to the descriptor for the Notification + event that caused this function to execute. + @param[in] Ppi Pointer to the PPI data associated with this function. + + @retval EFI_SUCCESS The function completes successfully + +**/ +EFI_STATUS +EFIAPI +SdBlockIoPeimEndOfPei ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + SD_PEIM_HC_PRIVATE_DATA *Private; + + Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor); + + if ((Private->Pool != NULL) && (Private->Pool->Head != NULL)) { + SdPeimFreeMemPool (Private->Pool); + } + + return EFI_SUCCESS; +} + +/** + The user code starts with this function. + + @param FileHandle Handle of the file being invoked. + @param PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCESS The driver is successfully initialized. + @retval Others Can't initialize the driver. + +**/ +EFI_STATUS +EFIAPI +InitializeSdBlockIoPeim ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + SD_PEIM_HC_PRIVATE_DATA *Private; + EDKII_SD_MMC_HOST_CONTROLLER_PPI *SdMmcHcPpi; + UINT32 Index; + UINTN *MmioBase; + UINT8 BarNum; + UINT8 SlotNum; + UINT8 Controller; + UINT64 Capacity; + SD_HC_SLOT_CAP Capability; + SD_PEIM_HC_SLOT *Slot; + SD_CSD *Csd; + SD_CSD2 *Csd2; + UINT32 CSize; + UINT32 CSizeMul; + UINT32 ReadBlLen; + + // + // Shadow this PEIM to run from memory + // + if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { + return EFI_SUCCESS; + } + + // + // locate Sd host controller PPI + // + Status = PeiServicesLocatePpi ( + &gEdkiiPeiSdMmcHostControllerPpiGuid, + 0, + NULL, + (VOID **)&SdMmcHcPpi + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + IoMmuInit (); + + Controller = 0; + MmioBase = NULL; + while (TRUE) { + Status = SdMmcHcPpi->GetSdMmcHcMmioBar (SdMmcHcPpi, Controller, &MmioBase, &BarNum); + // + // When status is error, meant no controller is found + // + if (EFI_ERROR (Status)) { + break; + } + + if (BarNum == 0) { + Controller++; + continue; + } + + Private = AllocateCopyPool (sizeof (SD_PEIM_HC_PRIVATE_DATA), &gSdHcPrivateTemplate); + if (Private == NULL) { + Status = EFI_OUT_OF_RESOURCES; + break; + } + + Private->BlkIoPpiList.Ppi = (VOID *)&Private->BlkIoPpi; + Private->BlkIo2PpiList.Ppi = (VOID *)&Private->BlkIo2Ppi; + // + // Initialize the memory pool which will be used in all transactions. + // + Status = SdPeimInitMemPool (Private); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + break; + } + + for (Index = 0; Index < BarNum; Index++) { + Status = SdPeimHcGetCapability (MmioBase[Index], &Capability); + if (EFI_ERROR (Status)) { + continue; + } + + if (Capability.SlotType != 0x1) { + DEBUG ((DEBUG_INFO, "The slot at 0x%x is not embedded slot type\n", MmioBase[Index])); + Status = EFI_UNSUPPORTED; + continue; + } + + Status = SdPeimHcReset (MmioBase[Index]); + if (EFI_ERROR (Status)) { + continue; + } + + Status = SdPeimHcCardDetect (MmioBase[Index]); + if (EFI_ERROR (Status)) { + continue; + } + + Status = SdPeimHcInitHost (MmioBase[Index]); + if (EFI_ERROR (Status)) { + continue; + } + + SlotNum = Private->SlotNum; + Slot = &Private->Slot[SlotNum]; + CopyMem (Slot, &gSdHcSlotTemplate, sizeof (SD_PEIM_HC_SLOT)); + Slot->Private = Private; + Slot->SdHcBase = MmioBase[Index]; + CopyMem (&Slot->Capability, &Capability, sizeof (Capability)); + + Status = SdPeimIdentification (Slot); + if (EFI_ERROR (Status)) { + continue; + } + + Csd = &Slot->Csd; + if (Csd->CsdStructure == 0) { + Slot->SectorAddressing = FALSE; + CSize = (Csd->CSizeHigh << 2 | Csd->CSizeLow) + 1; + CSizeMul = (1 << (Csd->CSizeMul + 2)); + ReadBlLen = (1 << (Csd->ReadBlLen)); + Capacity = MultU64x32 (MultU64x32 ((UINT64)CSize, CSizeMul), ReadBlLen); + } else { + Slot->SectorAddressing = TRUE; + Csd2 = (SD_CSD2 *)(VOID *)Csd; + CSize = (Csd2->CSizeHigh << 16 | Csd2->CSizeLow) + 1; + Capacity = MultU64x32 ((UINT64)CSize, SIZE_512KB); + } + + Slot->Media.LastBlock = DivU64x32 (Capacity, Slot->Media.BlockSize) - 1; + + Private->TotalBlkIoDevices++; + Private->SlotNum++; + } + + Controller++; + if (!EFI_ERROR (Status)) { + PeiServicesInstallPpi (&Private->BlkIoPpiList); + PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList); + } else { + if (Private->Pool->Head != NULL) { + SdPeimFreeMemPool (Private->Pool); + } + } + } + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.h b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.h index 2261d8c798..702a01a86c 100644 --- a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.h +++ b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.h @@ -1,510 +1,510 @@ -/** @file
-
- Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _SD_BLOCK_IO_PEI_H_
-#define _SD_BLOCK_IO_PEI_H_
-
-#include <PiPei.h>
-
-#include <Ppi/SdMmcHostController.h>
-#include <Ppi/BlockIo.h>
-#include <Ppi/BlockIo2.h>
-#include <Ppi/IoMmu.h>
-#include <Ppi/EndOfPeiPhase.h>
-
-#include <Library/DebugLib.h>
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/IoLib.h>
-#include <Library/TimerLib.h>
-#include <Library/PeiServicesLib.h>
-
-#include <IndustryStandard/Sd.h>
-
-typedef struct _SD_PEIM_HC_PRIVATE_DATA SD_PEIM_HC_PRIVATE_DATA;
-typedef struct _SD_PEIM_HC_SLOT SD_PEIM_HC_SLOT;
-typedef struct _SD_TRB SD_TRB;
-
-#include "SdHci.h"
-#include "SdHcMem.h"
-
-#define SD_PEIM_SIG SIGNATURE_32 ('S', 'D', 'C', 'P')
-#define SD_PEIM_SLOT_SIG SIGNATURE_32 ('S', 'D', 'C', 'S')
-
-#define SD_PEIM_MAX_SLOTS 6
-
-struct _SD_PEIM_HC_SLOT {
- UINT32 Signature;
- EFI_PEI_BLOCK_IO2_MEDIA Media;
-
- UINTN SdHcBase;
- SD_HC_SLOT_CAP Capability;
- SD_CSD Csd;
- BOOLEAN SectorAddressing;
- SD_PEIM_HC_PRIVATE_DATA *Private;
-};
-
-struct _SD_PEIM_HC_PRIVATE_DATA {
- UINT32 Signature;
- SD_PEIM_MEM_POOL *Pool;
- EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi;
- EFI_PEI_RECOVERY_BLOCK_IO2_PPI BlkIo2Ppi;
- EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList;
- EFI_PEI_PPI_DESCRIPTOR BlkIo2PpiList;
-
- //
- // EndOfPei callback is used to do the cleanups before exit of PEI phase.
- //
- EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList;
-
- SD_PEIM_HC_SLOT Slot[SD_PEIM_MAX_SLOTS];
- UINT8 SlotNum;
- UINT8 TotalBlkIoDevices;
-};
-
-#define SD_TIMEOUT MultU64x32((UINT64)(3), 1000000)
-#define GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS(a) CR (a, SD_PEIM_HC_PRIVATE_DATA, BlkIoPpi, SD_PEIM_SIG)
-#define GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2(a) CR (a, SD_PEIM_HC_PRIVATE_DATA, BlkIo2Ppi, SD_PEIM_SIG)
-#define GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY(a) CR (a, SD_PEIM_HC_PRIVATE_DATA, EndOfPeiNotifyList, SD_PEIM_SIG)
-
-struct _SD_TRB {
- SD_PEIM_HC_SLOT *Slot;
- UINT16 BlockSize;
-
- SD_COMMAND_PACKET *Packet;
- VOID *Data;
- UINT32 DataLen;
- BOOLEAN Read;
- EFI_PHYSICAL_ADDRESS DataPhy;
- VOID *DataMap;
- SD_HC_TRANSFER_MODE Mode;
-
- UINT64 Timeout;
-
- SD_HC_ADMA_DESC_LINE *AdmaDesc;
- UINTN AdmaDescSize;
-};
-
-/**
- Gets the count of block I/O devices that one specific block driver detects.
-
- This function is used for getting the count of block I/O devices that one
- specific block driver detects. To the PEI ATAPI driver, it returns the number
- of all the detected ATAPI devices it detects during the enumeration process.
- To the PEI legacy floppy driver, it returns the number of all the legacy
- devices it finds during its enumeration process. If no device is detected,
- then the function will return zero.
-
- @param[in] PeiServices General-purpose services that are available
- to every PEIM.
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
- instance.
- @param[out] NumberBlockDevices The number of block I/O devices discovered.
-
- @retval EFI_SUCCESS The operation performed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-SdBlockIoPeimGetDeviceNo (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
- OUT UINTN *NumberBlockDevices
- );
-
-/**
- Gets a block device's media information.
-
- This function will provide the caller with the specified block device's media
- information. If the media changes, calling this function will update the media
- information accordingly.
-
- @param[in] PeiServices General-purpose services that are available to every
- PEIM
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
- @param[in] DeviceIndex Specifies the block device to which the function wants
- to talk. Because the driver that implements Block I/O
- PPIs will manage multiple block devices, the PPIs that
- want to talk to a single device must specify the
- device index that was assigned during the enumeration
- process. This index is a number from one to
- NumberBlockDevices.
- @param[out] MediaInfo The media information of the specified block media.
- The caller is responsible for the ownership of this
- data structure.
-
- @par Note:
- The MediaInfo structure describes an enumeration of possible block device
- types. This enumeration exists because no device paths are actually passed
- across interfaces that describe the type or class of hardware that is publishing
- the block I/O interface. This enumeration will allow for policy decisions
- in the Recovery PEIM, such as "Try to recover from legacy floppy first,
- LS-120 second, CD-ROM third." If there are multiple partitions abstracted
- by a given device type, they should be reported in ascending order; this
- order also applies to nested partitions, such as legacy MBR, where the
- outermost partitions would have precedence in the reporting order. The
- same logic applies to systems such as IDE that have precedence relationships
- like "Master/Slave" or "Primary/Secondary". The master device should be
- reported first, the slave second.
-
- @retval EFI_SUCCESS Media information about the specified block device
- was obtained successfully.
- @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
- error.
-
-**/
-EFI_STATUS
-EFIAPI
-SdBlockIoPeimGetMediaInfo (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
- IN UINTN DeviceIndex,
- OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
- );
-
-/**
- Reads the requested number of blocks from the specified block device.
-
- The function reads the requested number of blocks from the device. All the
- blocks are read, or an error is returned. If there is no media in the device,
- the function returns EFI_NO_MEDIA.
-
- @param[in] PeiServices General-purpose services that are available to
- every PEIM.
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
- @param[in] DeviceIndex Specifies the block device to which the function wants
- to talk. Because the driver that implements Block I/O
- PPIs will manage multiple block devices, PPIs that
- want to talk to a single device must specify the device
- index that was assigned during the enumeration process.
- This index is a number from one to NumberBlockDevices.
- @param[in] StartLBA The starting logical block address (LBA) to read from
- on the device
- @param[in] BufferSize The size of the Buffer in bytes. This number must be
- a multiple of the intrinsic block size of the device.
- @param[out] Buffer A pointer to the destination buffer for the data.
- The caller is responsible for the 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 attempting
- to perform the read operation.
- @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
- valid, or the buffer is not properly aligned.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
- the intrinsic block size of the device.
-
-**/
-EFI_STATUS
-EFIAPI
-SdBlockIoPeimReadBlocks (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
- IN UINTN DeviceIndex,
- IN EFI_PEI_LBA StartLBA,
- IN UINTN BufferSize,
- OUT VOID *Buffer
- );
-
-/**
- Gets the count of block I/O devices that one specific block driver detects.
-
- This function is used for getting the count of block I/O devices that one
- specific block driver detects. To the PEI ATAPI driver, it returns the number
- of all the detected ATAPI devices it detects during the enumeration process.
- To the PEI legacy floppy driver, it returns the number of all the legacy
- devices it finds during its enumeration process. If no device is detected,
- then the function will return zero.
-
- @param[in] PeiServices General-purpose services that are available
- to every PEIM.
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
- instance.
- @param[out] NumberBlockDevices The number of block I/O devices discovered.
-
- @retval EFI_SUCCESS The operation performed successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-SdBlockIoPeimGetDeviceNo2 (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
- OUT UINTN *NumberBlockDevices
- );
-
-/**
- Gets a block device's media information.
-
- This function will provide the caller with the specified block device's media
- information. If the media changes, calling this function will update the media
- information accordingly.
-
- @param[in] PeiServices General-purpose services that are available to every
- PEIM
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
- @param[in] DeviceIndex Specifies the block device to which the function wants
- to talk. Because the driver that implements Block I/O
- PPIs will manage multiple block devices, the PPIs that
- want to talk to a single device must specify the
- device index that was assigned during the enumeration
- process. This index is a number from one to
- NumberBlockDevices.
- @param[out] MediaInfo The media information of the specified block media.
- The caller is responsible for the ownership of this
- data structure.
-
- @par Note:
- The MediaInfo structure describes an enumeration of possible block device
- types. This enumeration exists because no device paths are actually passed
- across interfaces that describe the type or class of hardware that is publishing
- the block I/O interface. This enumeration will allow for policy decisions
- in the Recovery PEIM, such as "Try to recover from legacy floppy first,
- LS-120 second, CD-ROM third." If there are multiple partitions abstracted
- by a given device type, they should be reported in ascending order; this
- order also applies to nested partitions, such as legacy MBR, where the
- outermost partitions would have precedence in the reporting order. The
- same logic applies to systems such as IDE that have precedence relationships
- like "Master/Slave" or "Primary/Secondary". The master device should be
- reported first, the slave second.
-
- @retval EFI_SUCCESS Media information about the specified block device
- was obtained successfully.
- @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
- error.
-
-**/
-EFI_STATUS
-EFIAPI
-SdBlockIoPeimGetMediaInfo2 (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
- IN UINTN DeviceIndex,
- OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
- );
-
-/**
- Reads the requested number of blocks from the specified block device.
-
- The function reads the requested number of blocks from the device. All the
- blocks are read, or an error is returned. If there is no media in the device,
- the function returns EFI_NO_MEDIA.
-
- @param[in] PeiServices General-purpose services that are available to
- every PEIM.
- @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
- @param[in] DeviceIndex Specifies the block device to which the function wants
- to talk. Because the driver that implements Block I/O
- PPIs will manage multiple block devices, PPIs that
- want to talk to a single device must specify the device
- index that was assigned during the enumeration process.
- This index is a number from one to NumberBlockDevices.
- @param[in] StartLBA The starting logical block address (LBA) to read from
- on the device
- @param[in] BufferSize The size of the Buffer in bytes. This number must be
- a multiple of the intrinsic block size of the device.
- @param[out] Buffer A pointer to the destination buffer for the data.
- The caller is responsible for the 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 attempting
- to perform the read operation.
- @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
- valid, or the buffer is not properly aligned.
- @retval EFI_NO_MEDIA There is no media in the device.
- @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
- the intrinsic block size of the device.
-
-**/
-EFI_STATUS
-EFIAPI
-SdBlockIoPeimReadBlocks2 (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
- IN UINTN DeviceIndex,
- IN EFI_PEI_LBA StartLBA,
- IN UINTN BufferSize,
- OUT VOID *Buffer
- );
-
-/**
- Initialize the memory management pool for the host controller.
-
- @param Private The Sd Peim driver private data.
-
- @retval EFI_SUCCESS The memory pool is initialized.
- @retval Others Fail to init the memory pool.
-
-**/
-EFI_STATUS
-SdPeimInitMemPool (
- IN SD_PEIM_HC_PRIVATE_DATA *Private
- );
-
-/**
- Release the memory management pool.
-
- @param Pool The memory pool to free.
-
- @retval EFI_DEVICE_ERROR Fail to free the memory pool.
- @retval EFI_SUCCESS The memory pool is freed.
-
-**/
-EFI_STATUS
-SdPeimFreeMemPool (
- IN SD_PEIM_MEM_POOL *Pool
- );
-
-/**
- Allocate some memory from the host controller's memory pool
- which can be used to communicate with host controller.
-
- @param Pool The host controller's memory pool.
- @param Size Size of the memory to allocate.
-
- @return The allocated memory or NULL.
-
-**/
-VOID *
-SdPeimAllocateMem (
- IN SD_PEIM_MEM_POOL *Pool,
- IN UINTN Size
- );
-
-/**
- Free the allocated memory back to the memory pool.
-
- @param Pool The memory pool of the host controller.
- @param Mem The memory to free.
- @param Size The size of the memory to free.
-
-**/
-VOID
-SdPeimFreeMem (
- IN SD_PEIM_MEM_POOL *Pool,
- IN VOID *Mem,
- IN UINTN Size
- );
-
-/**
- Initialize IOMMU.
-**/
-VOID
-IoMmuInit (
- VOID
- );
-
-/**
- Provides the controller-specific addresses required to access system memory from a
- DMA bus master.
-
- @param Operation Indicates if the bus master is going to read or write to system memory.
- @param HostAddress The system memory address to map to the PCI controller.
- @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
- that were mapped.
- @param DeviceAddress The resulting map address for the bus master PCI controller to use to
- access the hosts HostAddress.
- @param Mapping A resulting value to pass to Unmap().
-
- @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
- @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
- @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
- @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
-
-**/
-EFI_STATUS
-IoMmuMap (
- IN EDKII_IOMMU_OPERATION Operation,
- IN VOID *HostAddress,
- IN OUT UINTN *NumberOfBytes,
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
- OUT VOID **Mapping
- );
-
-/**
- Completes the Map() operation and releases any corresponding resources.
-
- @param Mapping The mapping value returned from Map().
-
- @retval EFI_SUCCESS The range was unmapped.
- @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
- @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
-**/
-EFI_STATUS
-IoMmuUnmap (
- IN VOID *Mapping
- );
-
-/**
- Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
- OperationBusMasterCommonBuffer64 mapping.
-
- @param Pages The number of pages to allocate.
- @param HostAddress A pointer to store the base system memory address of the
- allocated range.
- @param DeviceAddress The resulting map address for the bus master PCI controller to use to
- access the hosts HostAddress.
- @param Mapping A resulting value to pass to Unmap().
-
- @retval EFI_SUCCESS The requested memory pages were allocated.
- @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
- MEMORY_WRITE_COMBINE and MEMORY_CACHED.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
- @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
-
-**/
-EFI_STATUS
-IoMmuAllocateBuffer (
- IN UINTN Pages,
- OUT VOID **HostAddress,
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
- OUT VOID **Mapping
- );
-
-/**
- Frees memory that was allocated with AllocateBuffer().
-
- @param Pages The number of pages to free.
- @param HostAddress The base system memory address of the allocated range.
- @param Mapping The mapping value returned from Map().
-
- @retval EFI_SUCCESS The requested memory pages were freed.
- @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
- was not allocated with AllocateBuffer().
-
-**/
-EFI_STATUS
-IoMmuFreeBuffer (
- IN UINTN Pages,
- IN VOID *HostAddress,
- IN VOID *Mapping
- );
-
-/**
- One notified function to cleanup the allocated DMA buffers at the end of PEI.
-
- @param[in] PeiServices Pointer to PEI Services Table.
- @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
- event that caused this function to execute.
- @param[in] Ppi Pointer to the PPI data associated with this function.
-
- @retval EFI_SUCCESS The function completes successfully
-
-**/
-EFI_STATUS
-EFIAPI
-SdBlockIoPeimEndOfPei (
- IN EFI_PEI_SERVICES **PeiServices,
- IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
- IN VOID *Ppi
- );
-
-#endif
+/** @file + + Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SD_BLOCK_IO_PEI_H_ +#define _SD_BLOCK_IO_PEI_H_ + +#include <PiPei.h> + +#include <Ppi/SdMmcHostController.h> +#include <Ppi/BlockIo.h> +#include <Ppi/BlockIo2.h> +#include <Ppi/IoMmu.h> +#include <Ppi/EndOfPeiPhase.h> + +#include <Library/DebugLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/IoLib.h> +#include <Library/TimerLib.h> +#include <Library/PeiServicesLib.h> + +#include <IndustryStandard/Sd.h> + +typedef struct _SD_PEIM_HC_PRIVATE_DATA SD_PEIM_HC_PRIVATE_DATA; +typedef struct _SD_PEIM_HC_SLOT SD_PEIM_HC_SLOT; +typedef struct _SD_TRB SD_TRB; + +#include "SdHci.h" +#include "SdHcMem.h" + +#define SD_PEIM_SIG SIGNATURE_32 ('S', 'D', 'C', 'P') +#define SD_PEIM_SLOT_SIG SIGNATURE_32 ('S', 'D', 'C', 'S') + +#define SD_PEIM_MAX_SLOTS 6 + +struct _SD_PEIM_HC_SLOT { + UINT32 Signature; + EFI_PEI_BLOCK_IO2_MEDIA Media; + + UINTN SdHcBase; + SD_HC_SLOT_CAP Capability; + SD_CSD Csd; + BOOLEAN SectorAddressing; + SD_PEIM_HC_PRIVATE_DATA *Private; +}; + +struct _SD_PEIM_HC_PRIVATE_DATA { + UINT32 Signature; + SD_PEIM_MEM_POOL *Pool; + EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi; + EFI_PEI_RECOVERY_BLOCK_IO2_PPI BlkIo2Ppi; + EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList; + EFI_PEI_PPI_DESCRIPTOR BlkIo2PpiList; + + // + // EndOfPei callback is used to do the cleanups before exit of PEI phase. + // + EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList; + + SD_PEIM_HC_SLOT Slot[SD_PEIM_MAX_SLOTS]; + UINT8 SlotNum; + UINT8 TotalBlkIoDevices; +}; + +#define SD_TIMEOUT MultU64x32((UINT64)(3), 1000000) +#define GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS(a) CR (a, SD_PEIM_HC_PRIVATE_DATA, BlkIoPpi, SD_PEIM_SIG) +#define GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2(a) CR (a, SD_PEIM_HC_PRIVATE_DATA, BlkIo2Ppi, SD_PEIM_SIG) +#define GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY(a) CR (a, SD_PEIM_HC_PRIVATE_DATA, EndOfPeiNotifyList, SD_PEIM_SIG) + +struct _SD_TRB { + SD_PEIM_HC_SLOT *Slot; + UINT16 BlockSize; + + SD_COMMAND_PACKET *Packet; + VOID *Data; + UINT32 DataLen; + BOOLEAN Read; + EFI_PHYSICAL_ADDRESS DataPhy; + VOID *DataMap; + SD_HC_TRANSFER_MODE Mode; + + UINT64 Timeout; + + SD_HC_ADMA_DESC_LINE *AdmaDesc; + UINTN AdmaDescSize; +}; + +/** + Gets the count of block I/O devices that one specific block driver detects. + + This function is used for getting the count of block I/O devices that one + specific block driver detects. To the PEI ATAPI driver, it returns the number + of all the detected ATAPI devices it detects during the enumeration process. + To the PEI legacy floppy driver, it returns the number of all the legacy + devices it finds during its enumeration process. If no device is detected, + then the function will return zero. + + @param[in] PeiServices General-purpose services that are available + to every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI + instance. + @param[out] NumberBlockDevices The number of block I/O devices discovered. + + @retval EFI_SUCCESS The operation performed successfully. + +**/ +EFI_STATUS +EFIAPI +SdBlockIoPeimGetDeviceNo ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + OUT UINTN *NumberBlockDevices + ); + +/** + Gets a block device's media information. + + This function will provide the caller with the specified block device's media + information. If the media changes, calling this function will update the media + information accordingly. + + @param[in] PeiServices General-purpose services that are available to every + PEIM + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, the PPIs that + want to talk to a single device must specify the + device index that was assigned during the enumeration + process. This index is a number from one to + NumberBlockDevices. + @param[out] MediaInfo The media information of the specified block media. + The caller is responsible for the ownership of this + data structure. + + @par Note: + The MediaInfo structure describes an enumeration of possible block device + types. This enumeration exists because no device paths are actually passed + across interfaces that describe the type or class of hardware that is publishing + the block I/O interface. This enumeration will allow for policy decisions + in the Recovery PEIM, such as "Try to recover from legacy floppy first, + LS-120 second, CD-ROM third." If there are multiple partitions abstracted + by a given device type, they should be reported in ascending order; this + order also applies to nested partitions, such as legacy MBR, where the + outermost partitions would have precedence in the reporting order. The + same logic applies to systems such as IDE that have precedence relationships + like "Master/Slave" or "Primary/Secondary". The master device should be + reported first, the slave second. + + @retval EFI_SUCCESS Media information about the specified block device + was obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware + error. + +**/ +EFI_STATUS +EFIAPI +SdBlockIoPeimGetMediaInfo ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + IN UINTN DeviceIndex, + OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo + ); + +/** + Reads the requested number of blocks from the specified block device. + + The function reads the requested number of blocks from the device. All the + blocks are read, or an error is returned. If there is no media in the device, + the function returns EFI_NO_MEDIA. + + @param[in] PeiServices General-purpose services that are available to + every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, PPIs that + want to talk to a single device must specify the device + index that was assigned during the enumeration process. + This index is a number from one to NumberBlockDevices. + @param[in] StartLBA The starting logical block address (LBA) to read from + on the device + @param[in] BufferSize The size of the Buffer in bytes. This number must be + a multiple of the intrinsic block size of the device. + @param[out] Buffer A pointer to the destination buffer for the data. + The caller is responsible for the 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 attempting + to perform the read operation. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not + valid, or the buffer is not properly aligned. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of + the intrinsic block size of the device. + +**/ +EFI_STATUS +EFIAPI +SdBlockIoPeimReadBlocks ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + IN UINTN DeviceIndex, + IN EFI_PEI_LBA StartLBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +/** + Gets the count of block I/O devices that one specific block driver detects. + + This function is used for getting the count of block I/O devices that one + specific block driver detects. To the PEI ATAPI driver, it returns the number + of all the detected ATAPI devices it detects during the enumeration process. + To the PEI legacy floppy driver, it returns the number of all the legacy + devices it finds during its enumeration process. If no device is detected, + then the function will return zero. + + @param[in] PeiServices General-purpose services that are available + to every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI + instance. + @param[out] NumberBlockDevices The number of block I/O devices discovered. + + @retval EFI_SUCCESS The operation performed successfully. + +**/ +EFI_STATUS +EFIAPI +SdBlockIoPeimGetDeviceNo2 ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, + OUT UINTN *NumberBlockDevices + ); + +/** + Gets a block device's media information. + + This function will provide the caller with the specified block device's media + information. If the media changes, calling this function will update the media + information accordingly. + + @param[in] PeiServices General-purpose services that are available to every + PEIM + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, the PPIs that + want to talk to a single device must specify the + device index that was assigned during the enumeration + process. This index is a number from one to + NumberBlockDevices. + @param[out] MediaInfo The media information of the specified block media. + The caller is responsible for the ownership of this + data structure. + + @par Note: + The MediaInfo structure describes an enumeration of possible block device + types. This enumeration exists because no device paths are actually passed + across interfaces that describe the type or class of hardware that is publishing + the block I/O interface. This enumeration will allow for policy decisions + in the Recovery PEIM, such as "Try to recover from legacy floppy first, + LS-120 second, CD-ROM third." If there are multiple partitions abstracted + by a given device type, they should be reported in ascending order; this + order also applies to nested partitions, such as legacy MBR, where the + outermost partitions would have precedence in the reporting order. The + same logic applies to systems such as IDE that have precedence relationships + like "Master/Slave" or "Primary/Secondary". The master device should be + reported first, the slave second. + + @retval EFI_SUCCESS Media information about the specified block device + was obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware + error. + +**/ +EFI_STATUS +EFIAPI +SdBlockIoPeimGetMediaInfo2 ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, + IN UINTN DeviceIndex, + OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo + ); + +/** + Reads the requested number of blocks from the specified block device. + + The function reads the requested number of blocks from the device. All the + blocks are read, or an error is returned. If there is no media in the device, + the function returns EFI_NO_MEDIA. + + @param[in] PeiServices General-purpose services that are available to + every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, PPIs that + want to talk to a single device must specify the device + index that was assigned during the enumeration process. + This index is a number from one to NumberBlockDevices. + @param[in] StartLBA The starting logical block address (LBA) to read from + on the device + @param[in] BufferSize The size of the Buffer in bytes. This number must be + a multiple of the intrinsic block size of the device. + @param[out] Buffer A pointer to the destination buffer for the data. + The caller is responsible for the 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 attempting + to perform the read operation. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not + valid, or the buffer is not properly aligned. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of + the intrinsic block size of the device. + +**/ +EFI_STATUS +EFIAPI +SdBlockIoPeimReadBlocks2 ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This, + IN UINTN DeviceIndex, + IN EFI_PEI_LBA StartLBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +/** + Initialize the memory management pool for the host controller. + + @param Private The Sd Peim driver private data. + + @retval EFI_SUCCESS The memory pool is initialized. + @retval Others Fail to init the memory pool. + +**/ +EFI_STATUS +SdPeimInitMemPool ( + IN SD_PEIM_HC_PRIVATE_DATA *Private + ); + +/** + Release the memory management pool. + + @param Pool The memory pool to free. + + @retval EFI_DEVICE_ERROR Fail to free the memory pool. + @retval EFI_SUCCESS The memory pool is freed. + +**/ +EFI_STATUS +SdPeimFreeMemPool ( + IN SD_PEIM_MEM_POOL *Pool + ); + +/** + Allocate some memory from the host controller's memory pool + which can be used to communicate with host controller. + + @param Pool The host controller's memory pool. + @param Size Size of the memory to allocate. + + @return The allocated memory or NULL. + +**/ +VOID * +SdPeimAllocateMem ( + IN SD_PEIM_MEM_POOL *Pool, + IN UINTN Size + ); + +/** + Free the allocated memory back to the memory pool. + + @param Pool The memory pool of the host controller. + @param Mem The memory to free. + @param Size The size of the memory to free. + +**/ +VOID +SdPeimFreeMem ( + IN SD_PEIM_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ); + +/** + Initialize IOMMU. +**/ +VOID +IoMmuInit ( + VOID + ); + +/** + Provides the controller-specific addresses required to access system memory from a + DMA bus master. + + @param Operation Indicates if the bus master is going to read or write to system memory. + @param HostAddress The system memory address to map to the PCI controller. + @param NumberOfBytes On input the number of bytes to map. On output the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + +**/ +EFI_STATUS +IoMmuMap ( + IN EDKII_IOMMU_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +/** + Completes the Map() operation and releases any corresponding resources. + + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map(). + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. +**/ +EFI_STATUS +IoMmuUnmap ( + IN VOID *Mapping + ); + +/** + Allocates pages that are suitable for an OperationBusMasterCommonBuffer or + OperationBusMasterCommonBuffer64 mapping. + + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +IoMmuAllocateBuffer ( + IN UINTN Pages, + OUT VOID **HostAddress, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +/** + Frees memory that was allocated with AllocateBuffer(). + + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages + was not allocated with AllocateBuffer(). + +**/ +EFI_STATUS +IoMmuFreeBuffer ( + IN UINTN Pages, + IN VOID *HostAddress, + IN VOID *Mapping + ); + +/** + One notified function to cleanup the allocated DMA buffers at the end of PEI. + + @param[in] PeiServices Pointer to PEI Services Table. + @param[in] NotifyDescriptor Pointer to the descriptor for the Notification + event that caused this function to execute. + @param[in] Ppi Pointer to the PPI data associated with this function. + + @retval EFI_SUCCESS The function completes successfully + +**/ +EFI_STATUS +EFIAPI +SdBlockIoPeimEndOfPei ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +#endif diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.inf b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.inf index 2647192e34..94fe29a03d 100644 --- a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.inf +++ b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.inf @@ -1,60 +1,60 @@ -## @file
-# Description file for the SD memory card Peim driver.
-#
-# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = SdBlockIoPei
- MODULE_UNI_FILE = SdBlockIoPei.uni
- FILE_GUID = 17851FBF-45C4-4ff7-A2A0-C3B12D63C27E
- MODULE_TYPE = PEIM
- VERSION_STRING = 1.0
-
- ENTRY_POINT = InitializeSdBlockIoPeim
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64 EBC
-#
-
-[Sources]
- SdBlockIoPei.c
- SdBlockIoPei.h
- SdHci.c
- SdHci.h
- SdHcMem.c
- SdHcMem.h
- DmaMem.c
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
-
-[LibraryClasses]
- IoLib
- TimerLib
- BaseMemoryLib
- PeimEntryPoint
- PeiServicesLib
- DebugLib
-
-[Ppis]
- gEfiPeiVirtualBlockIoPpiGuid ## PRODUCES
- gEfiPeiVirtualBlockIo2PpiGuid ## PRODUCES
- gEdkiiPeiSdMmcHostControllerPpiGuid ## CONSUMES
- gEdkiiIoMmuPpiGuid ## CONSUMES
- gEfiEndOfPeiSignalPpiGuid ## CONSUMES
-
-[Depex]
- gEfiPeiMemoryDiscoveredPpiGuid AND gEdkiiPeiSdMmcHostControllerPpiGuid
-
-[UserExtensions.TianoCore."ExtraFiles"]
- SdBlockIoPeiExtra.uni
-
+## @file +# Description file for the SD memory card Peim driver. +# +# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SdBlockIoPei + MODULE_UNI_FILE = SdBlockIoPei.uni + FILE_GUID = 17851FBF-45C4-4ff7-A2A0-C3B12D63C27E + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeSdBlockIoPeim + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + SdBlockIoPei.c + SdBlockIoPei.h + SdHci.c + SdHci.h + SdHcMem.c + SdHcMem.h + DmaMem.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + IoLib + TimerLib + BaseMemoryLib + PeimEntryPoint + PeiServicesLib + DebugLib + +[Ppis] + gEfiPeiVirtualBlockIoPpiGuid ## PRODUCES + gEfiPeiVirtualBlockIo2PpiGuid ## PRODUCES + gEdkiiPeiSdMmcHostControllerPpiGuid ## CONSUMES + gEdkiiIoMmuPpiGuid ## CONSUMES + gEfiEndOfPeiSignalPpiGuid ## CONSUMES + +[Depex] + gEfiPeiMemoryDiscoveredPpiGuid AND gEdkiiPeiSdMmcHostControllerPpiGuid + +[UserExtensions.TianoCore."ExtraFiles"] + SdBlockIoPeiExtra.uni + diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.uni b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.uni index d2de43e5e4..8776267cce 100644 --- a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.uni +++ b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.uni @@ -1,14 +1,14 @@ -// /** @file
-// The SdBlockIoPei driver is used to support recovery from SD memory card device.
-//
-// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Support recovery from SD memory card devices"
-
-#string STR_MODULE_DESCRIPTION #language en-US "The SdBlockIoPei driver is used to support recovery from SD memory card device."
-
+// /** @file +// The SdBlockIoPei driver is used to support recovery from SD memory card device. +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Support recovery from SD memory card devices" + +#string STR_MODULE_DESCRIPTION #language en-US "The SdBlockIoPei driver is used to support recovery from SD memory card device." + diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPeiExtra.uni b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPeiExtra.uni index 1bbdb8c71e..b38f0f9e51 100644 --- a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPeiExtra.uni +++ b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPeiExtra.uni @@ -1,14 +1,14 @@ -// /** @file
-// SdBlockIoPei Localized Strings and Content
-//
-// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-#string STR_PROPERTIES_MODULE_NAME
-#language en-US
-"SD BlockIo Peim for Recovery"
-
-
+// /** @file +// SdBlockIoPei Localized Strings and Content +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"SD BlockIo Peim for Recovery" + + diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.c b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.c index 27aec1fbf3..06b001ae09 100644 --- a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.c +++ b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.c @@ -1,425 +1,425 @@ -/** @file
-
-Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
-
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "SdBlockIoPei.h"
-
-/**
- Allocate a block of memory to be used by the buffer pool.
-
- @param Pages How many pages to allocate.
-
- @return The allocated memory block or NULL if failed.
-
-**/
-SD_PEIM_MEM_BLOCK *
-SdPeimAllocMemBlock (
- IN UINTN Pages
- )
-{
- SD_PEIM_MEM_BLOCK *Block;
- VOID *BufHost;
- VOID *Mapping;
- EFI_PHYSICAL_ADDRESS MappedAddr;
- EFI_STATUS Status;
- VOID *TempPtr;
-
- TempPtr = NULL;
- Block = NULL;
-
- Status = PeiServicesAllocatePool (sizeof (SD_PEIM_MEM_BLOCK), &TempPtr);
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- ZeroMem ((VOID *)(UINTN)TempPtr, sizeof (SD_PEIM_MEM_BLOCK));
-
- //
- // each bit in the bit array represents SD_PEIM_MEM_UNIT
- // bytes of memory in the memory block.
- //
- ASSERT (SD_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
-
- Block = (SD_PEIM_MEM_BLOCK *)(UINTN)TempPtr;
- Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
- Block->BitsLen = Block->BufLen / (SD_PEIM_MEM_UNIT * 8);
-
- Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr);
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- ZeroMem ((VOID *)(UINTN)TempPtr, Block->BitsLen);
-
- Block->Bits = (UINT8 *)(UINTN)TempPtr;
-
- Status = IoMmuAllocateBuffer (
- Pages,
- &BufHost,
- &MappedAddr,
- &Mapping
- );
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- ZeroMem ((VOID *)(UINTN)BufHost, EFI_PAGES_TO_SIZE (Pages));
-
- Block->BufHost = (UINT8 *)(UINTN)BufHost;
- Block->Buf = (UINT8 *)(UINTN)MappedAddr;
- Block->Mapping = Mapping;
- Block->Next = NULL;
-
- return Block;
-}
-
-/**
- Free the memory block from the memory pool.
-
- @param Pool The memory pool to free the block from.
- @param Block The memory block to free.
-
-**/
-VOID
-SdPeimFreeMemBlock (
- IN SD_PEIM_MEM_POOL *Pool,
- IN SD_PEIM_MEM_BLOCK *Block
- )
-{
- ASSERT ((Pool != NULL) && (Block != NULL));
-
- IoMmuFreeBuffer (EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost, Block->Mapping);
-}
-
-/**
- Alloc some memory from the block.
-
- @param Block The memory block to allocate memory from.
- @param Units Number of memory units to allocate.
-
- @return The pointer to the allocated memory. If couldn't allocate the needed memory,
- the return value is NULL.
-
-**/
-VOID *
-SdPeimAllocMemFromBlock (
- IN SD_PEIM_MEM_BLOCK *Block,
- IN UINTN Units
- )
-{
- UINTN Byte;
- UINT8 Bit;
- UINTN StartByte;
- UINT8 StartBit;
- UINTN Available;
- UINTN Count;
-
- ASSERT ((Block != 0) && (Units != 0));
-
- StartByte = 0;
- StartBit = 0;
- Available = 0;
-
- for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
- //
- // If current bit is zero, the corresponding memory unit is
- // available, otherwise we need to restart our searching.
- // Available counts the consecutive number of zero bit.
- //
- if (!SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)) {
- Available++;
-
- if (Available >= Units) {
- break;
- }
-
- SD_PEIM_NEXT_BIT (Byte, Bit);
- } else {
- SD_PEIM_NEXT_BIT (Byte, Bit);
-
- Available = 0;
- StartByte = Byte;
- StartBit = Bit;
- }
- }
-
- if (Available < Units) {
- return NULL;
- }
-
- //
- // Mark the memory as allocated
- //
- Byte = StartByte;
- Bit = StartBit;
-
- for (Count = 0; Count < Units; Count++) {
- ASSERT (!SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));
-
- Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] | (UINT8)SD_PEIM_MEM_BIT (Bit));
- SD_PEIM_NEXT_BIT (Byte, Bit);
- }
-
- return Block->Buf + (StartByte * 8 + StartBit) * SD_PEIM_MEM_UNIT;
-}
-
-/**
- Insert the memory block to the pool's list of the blocks.
-
- @param Head The head of the memory pool's block list.
- @param Block The memory block to insert.
-
-**/
-VOID
-SdPeimInsertMemBlockToPool (
- IN SD_PEIM_MEM_BLOCK *Head,
- IN SD_PEIM_MEM_BLOCK *Block
- )
-{
- ASSERT ((Head != NULL) && (Block != NULL));
- Block->Next = Head->Next;
- Head->Next = Block;
-}
-
-/**
- Is the memory block empty?
-
- @param Block The memory block to check.
-
- @retval TRUE The memory block is empty.
- @retval FALSE The memory block isn't empty.
-
-**/
-BOOLEAN
-SdPeimIsMemBlockEmpty (
- IN SD_PEIM_MEM_BLOCK *Block
- )
-{
- UINTN Index;
-
- for (Index = 0; Index < Block->BitsLen; Index++) {
- if (Block->Bits[Index] != 0) {
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-/**
- Initialize the memory management pool for the host controller.
-
- @param Private The Sd Peim driver private data.
-
- @retval EFI_SUCCESS The memory pool is initialized.
- @retval Others Fail to init the memory pool.
-
-**/
-EFI_STATUS
-SdPeimInitMemPool (
- IN SD_PEIM_HC_PRIVATE_DATA *Private
- )
-{
- SD_PEIM_MEM_POOL *Pool;
- EFI_STATUS Status;
- VOID *TempPtr;
-
- TempPtr = NULL;
- Pool = NULL;
-
- Status = PeiServicesAllocatePool (sizeof (SD_PEIM_MEM_POOL), &TempPtr);
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- ZeroMem ((VOID *)(UINTN)TempPtr, sizeof (SD_PEIM_MEM_POOL));
-
- Pool = (SD_PEIM_MEM_POOL *)((UINTN)TempPtr);
-
- Pool->Head = SdPeimAllocMemBlock (SD_PEIM_MEM_DEFAULT_PAGES);
-
- if (Pool->Head == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Private->Pool = Pool;
- return EFI_SUCCESS;
-}
-
-/**
- Release the memory management pool.
-
- @param Pool The memory pool to free.
-
- @retval EFI_DEVICE_ERROR Fail to free the memory pool.
- @retval EFI_SUCCESS The memory pool is freed.
-
-**/
-EFI_STATUS
-SdPeimFreeMemPool (
- IN SD_PEIM_MEM_POOL *Pool
- )
-{
- SD_PEIM_MEM_BLOCK *Block;
-
- ASSERT (Pool->Head != NULL);
-
- //
- // Unlink all the memory blocks from the pool, then free them.
- //
- for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
- SdPeimFreeMemBlock (Pool, Block);
- }
-
- SdPeimFreeMemBlock (Pool, Pool->Head);
-
- return EFI_SUCCESS;
-}
-
-/**
- Allocate some memory from the host controller's memory pool
- which can be used to communicate with host controller.
-
- @param Pool The host controller's memory pool.
- @param Size Size of the memory to allocate.
-
- @return The allocated memory or NULL.
-
-**/
-VOID *
-SdPeimAllocateMem (
- IN SD_PEIM_MEM_POOL *Pool,
- IN UINTN Size
- )
-{
- SD_PEIM_MEM_BLOCK *Head;
- SD_PEIM_MEM_BLOCK *Block;
- SD_PEIM_MEM_BLOCK *NewBlock;
- VOID *Mem;
- UINTN AllocSize;
- UINTN Pages;
-
- Mem = NULL;
- AllocSize = SD_PEIM_MEM_ROUND (Size);
- Head = Pool->Head;
- ASSERT (Head != NULL);
-
- //
- // First check whether current memory blocks can satisfy the allocation.
- //
- for (Block = Head; Block != NULL; Block = Block->Next) {
- Mem = SdPeimAllocMemFromBlock (Block, AllocSize / SD_PEIM_MEM_UNIT);
-
- if (Mem != NULL) {
- ZeroMem (Mem, Size);
- break;
- }
- }
-
- if (Mem != NULL) {
- return Mem;
- }
-
- //
- // Create a new memory block if there is not enough memory
- // in the pool. If the allocation size is larger than the
- // default page number, just allocate a large enough memory
- // block. Otherwise allocate default pages.
- //
- if (AllocSize > EFI_PAGES_TO_SIZE (SD_PEIM_MEM_DEFAULT_PAGES)) {
- Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
- } else {
- Pages = SD_PEIM_MEM_DEFAULT_PAGES;
- }
-
- NewBlock = SdPeimAllocMemBlock (Pages);
- if (NewBlock == NULL) {
- return NULL;
- }
-
- //
- // Add the new memory block to the pool, then allocate memory from it
- //
- SdPeimInsertMemBlockToPool (Head, NewBlock);
- Mem = SdPeimAllocMemFromBlock (NewBlock, AllocSize / SD_PEIM_MEM_UNIT);
-
- if (Mem != NULL) {
- ZeroMem (Mem, Size);
- }
-
- return Mem;
-}
-
-/**
- Free the allocated memory back to the memory pool.
-
- @param Pool The memory pool of the host controller.
- @param Mem The memory to free.
- @param Size The size of the memory to free.
-
-**/
-VOID
-SdPeimFreeMem (
- IN SD_PEIM_MEM_POOL *Pool,
- IN VOID *Mem,
- IN UINTN Size
- )
-{
- SD_PEIM_MEM_BLOCK *Head;
- SD_PEIM_MEM_BLOCK *Block;
- UINT8 *ToFree;
- UINTN AllocSize;
- UINTN Byte;
- UINTN Bit;
- UINTN Count;
-
- Head = Pool->Head;
- AllocSize = SD_PEIM_MEM_ROUND (Size);
- ToFree = (UINT8 *)Mem;
-
- for (Block = Head; Block != NULL; Block = Block->Next) {
- //
- // scan the memory block list for the memory block that
- // completely contains the memory to free.
- //
- if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {
- //
- // compute the start byte and bit in the bit array
- //
- Byte = ((ToFree - Block->Buf) / SD_PEIM_MEM_UNIT) / 8;
- Bit = ((ToFree - Block->Buf) / SD_PEIM_MEM_UNIT) % 8;
-
- //
- // reset associated bits in bit array
- //
- for (Count = 0; Count < (AllocSize / SD_PEIM_MEM_UNIT); Count++) {
- ASSERT (SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));
-
- Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] ^ SD_PEIM_MEM_BIT (Bit));
- SD_PEIM_NEXT_BIT (Byte, Bit);
- }
-
- break;
- }
- }
-
- //
- // If Block == NULL, it means that the current memory isn't
- // in the host controller's pool. This is critical because
- // the caller has passed in a wrong memory point
- //
- ASSERT (Block != NULL);
-
- //
- // Release the current memory block if it is empty and not the head
- //
- if ((Block != Head) && SdPeimIsMemBlockEmpty (Block)) {
- SdPeimFreeMemBlock (Pool, Block);
- }
-
- return;
-}
+/** @file + +Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SdBlockIoPei.h" + +/** + Allocate a block of memory to be used by the buffer pool. + + @param Pages How many pages to allocate. + + @return The allocated memory block or NULL if failed. + +**/ +SD_PEIM_MEM_BLOCK * +SdPeimAllocMemBlock ( + IN UINTN Pages + ) +{ + SD_PEIM_MEM_BLOCK *Block; + VOID *BufHost; + VOID *Mapping; + EFI_PHYSICAL_ADDRESS MappedAddr; + EFI_STATUS Status; + VOID *TempPtr; + + TempPtr = NULL; + Block = NULL; + + Status = PeiServicesAllocatePool (sizeof (SD_PEIM_MEM_BLOCK), &TempPtr); + if (EFI_ERROR (Status)) { + return NULL; + } + + ZeroMem ((VOID *)(UINTN)TempPtr, sizeof (SD_PEIM_MEM_BLOCK)); + + // + // each bit in the bit array represents SD_PEIM_MEM_UNIT + // bytes of memory in the memory block. + // + ASSERT (SD_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE); + + Block = (SD_PEIM_MEM_BLOCK *)(UINTN)TempPtr; + Block->BufLen = EFI_PAGES_TO_SIZE (Pages); + Block->BitsLen = Block->BufLen / (SD_PEIM_MEM_UNIT * 8); + + Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr); + if (EFI_ERROR (Status)) { + return NULL; + } + + ZeroMem ((VOID *)(UINTN)TempPtr, Block->BitsLen); + + Block->Bits = (UINT8 *)(UINTN)TempPtr; + + Status = IoMmuAllocateBuffer ( + Pages, + &BufHost, + &MappedAddr, + &Mapping + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + ZeroMem ((VOID *)(UINTN)BufHost, EFI_PAGES_TO_SIZE (Pages)); + + Block->BufHost = (UINT8 *)(UINTN)BufHost; + Block->Buf = (UINT8 *)(UINTN)MappedAddr; + Block->Mapping = Mapping; + Block->Next = NULL; + + return Block; +} + +/** + Free the memory block from the memory pool. + + @param Pool The memory pool to free the block from. + @param Block The memory block to free. + +**/ +VOID +SdPeimFreeMemBlock ( + IN SD_PEIM_MEM_POOL *Pool, + IN SD_PEIM_MEM_BLOCK *Block + ) +{ + ASSERT ((Pool != NULL) && (Block != NULL)); + + IoMmuFreeBuffer (EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost, Block->Mapping); +} + +/** + Alloc some memory from the block. + + @param Block The memory block to allocate memory from. + @param Units Number of memory units to allocate. + + @return The pointer to the allocated memory. If couldn't allocate the needed memory, + the return value is NULL. + +**/ +VOID * +SdPeimAllocMemFromBlock ( + IN SD_PEIM_MEM_BLOCK *Block, + IN UINTN Units + ) +{ + UINTN Byte; + UINT8 Bit; + UINTN StartByte; + UINT8 StartBit; + UINTN Available; + UINTN Count; + + ASSERT ((Block != 0) && (Units != 0)); + + StartByte = 0; + StartBit = 0; + Available = 0; + + for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) { + // + // If current bit is zero, the corresponding memory unit is + // available, otherwise we need to restart our searching. + // Available counts the consecutive number of zero bit. + // + if (!SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)) { + Available++; + + if (Available >= Units) { + break; + } + + SD_PEIM_NEXT_BIT (Byte, Bit); + } else { + SD_PEIM_NEXT_BIT (Byte, Bit); + + Available = 0; + StartByte = Byte; + StartBit = Bit; + } + } + + if (Available < Units) { + return NULL; + } + + // + // Mark the memory as allocated + // + Byte = StartByte; + Bit = StartBit; + + for (Count = 0; Count < Units; Count++) { + ASSERT (!SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)); + + Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] | (UINT8)SD_PEIM_MEM_BIT (Bit)); + SD_PEIM_NEXT_BIT (Byte, Bit); + } + + return Block->Buf + (StartByte * 8 + StartBit) * SD_PEIM_MEM_UNIT; +} + +/** + Insert the memory block to the pool's list of the blocks. + + @param Head The head of the memory pool's block list. + @param Block The memory block to insert. + +**/ +VOID +SdPeimInsertMemBlockToPool ( + IN SD_PEIM_MEM_BLOCK *Head, + IN SD_PEIM_MEM_BLOCK *Block + ) +{ + ASSERT ((Head != NULL) && (Block != NULL)); + Block->Next = Head->Next; + Head->Next = Block; +} + +/** + Is the memory block empty? + + @param Block The memory block to check. + + @retval TRUE The memory block is empty. + @retval FALSE The memory block isn't empty. + +**/ +BOOLEAN +SdPeimIsMemBlockEmpty ( + IN SD_PEIM_MEM_BLOCK *Block + ) +{ + UINTN Index; + + for (Index = 0; Index < Block->BitsLen; Index++) { + if (Block->Bits[Index] != 0) { + return FALSE; + } + } + + return TRUE; +} + +/** + Initialize the memory management pool for the host controller. + + @param Private The Sd Peim driver private data. + + @retval EFI_SUCCESS The memory pool is initialized. + @retval Others Fail to init the memory pool. + +**/ +EFI_STATUS +SdPeimInitMemPool ( + IN SD_PEIM_HC_PRIVATE_DATA *Private + ) +{ + SD_PEIM_MEM_POOL *Pool; + EFI_STATUS Status; + VOID *TempPtr; + + TempPtr = NULL; + Pool = NULL; + + Status = PeiServicesAllocatePool (sizeof (SD_PEIM_MEM_POOL), &TempPtr); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + ZeroMem ((VOID *)(UINTN)TempPtr, sizeof (SD_PEIM_MEM_POOL)); + + Pool = (SD_PEIM_MEM_POOL *)((UINTN)TempPtr); + + Pool->Head = SdPeimAllocMemBlock (SD_PEIM_MEM_DEFAULT_PAGES); + + if (Pool->Head == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Private->Pool = Pool; + return EFI_SUCCESS; +} + +/** + Release the memory management pool. + + @param Pool The memory pool to free. + + @retval EFI_DEVICE_ERROR Fail to free the memory pool. + @retval EFI_SUCCESS The memory pool is freed. + +**/ +EFI_STATUS +SdPeimFreeMemPool ( + IN SD_PEIM_MEM_POOL *Pool + ) +{ + SD_PEIM_MEM_BLOCK *Block; + + ASSERT (Pool->Head != NULL); + + // + // Unlink all the memory blocks from the pool, then free them. + // + for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) { + SdPeimFreeMemBlock (Pool, Block); + } + + SdPeimFreeMemBlock (Pool, Pool->Head); + + return EFI_SUCCESS; +} + +/** + Allocate some memory from the host controller's memory pool + which can be used to communicate with host controller. + + @param Pool The host controller's memory pool. + @param Size Size of the memory to allocate. + + @return The allocated memory or NULL. + +**/ +VOID * +SdPeimAllocateMem ( + IN SD_PEIM_MEM_POOL *Pool, + IN UINTN Size + ) +{ + SD_PEIM_MEM_BLOCK *Head; + SD_PEIM_MEM_BLOCK *Block; + SD_PEIM_MEM_BLOCK *NewBlock; + VOID *Mem; + UINTN AllocSize; + UINTN Pages; + + Mem = NULL; + AllocSize = SD_PEIM_MEM_ROUND (Size); + Head = Pool->Head; + ASSERT (Head != NULL); + + // + // First check whether current memory blocks can satisfy the allocation. + // + for (Block = Head; Block != NULL; Block = Block->Next) { + Mem = SdPeimAllocMemFromBlock (Block, AllocSize / SD_PEIM_MEM_UNIT); + + if (Mem != NULL) { + ZeroMem (Mem, Size); + break; + } + } + + if (Mem != NULL) { + return Mem; + } + + // + // Create a new memory block if there is not enough memory + // in the pool. If the allocation size is larger than the + // default page number, just allocate a large enough memory + // block. Otherwise allocate default pages. + // + if (AllocSize > EFI_PAGES_TO_SIZE (SD_PEIM_MEM_DEFAULT_PAGES)) { + Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1; + } else { + Pages = SD_PEIM_MEM_DEFAULT_PAGES; + } + + NewBlock = SdPeimAllocMemBlock (Pages); + if (NewBlock == NULL) { + return NULL; + } + + // + // Add the new memory block to the pool, then allocate memory from it + // + SdPeimInsertMemBlockToPool (Head, NewBlock); + Mem = SdPeimAllocMemFromBlock (NewBlock, AllocSize / SD_PEIM_MEM_UNIT); + + if (Mem != NULL) { + ZeroMem (Mem, Size); + } + + return Mem; +} + +/** + Free the allocated memory back to the memory pool. + + @param Pool The memory pool of the host controller. + @param Mem The memory to free. + @param Size The size of the memory to free. + +**/ +VOID +SdPeimFreeMem ( + IN SD_PEIM_MEM_POOL *Pool, + IN VOID *Mem, + IN UINTN Size + ) +{ + SD_PEIM_MEM_BLOCK *Head; + SD_PEIM_MEM_BLOCK *Block; + UINT8 *ToFree; + UINTN AllocSize; + UINTN Byte; + UINTN Bit; + UINTN Count; + + Head = Pool->Head; + AllocSize = SD_PEIM_MEM_ROUND (Size); + ToFree = (UINT8 *)Mem; + + for (Block = Head; Block != NULL; Block = Block->Next) { + // + // scan the memory block list for the memory block that + // completely contains the memory to free. + // + if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) { + // + // compute the start byte and bit in the bit array + // + Byte = ((ToFree - Block->Buf) / SD_PEIM_MEM_UNIT) / 8; + Bit = ((ToFree - Block->Buf) / SD_PEIM_MEM_UNIT) % 8; + + // + // reset associated bits in bit array + // + for (Count = 0; Count < (AllocSize / SD_PEIM_MEM_UNIT); Count++) { + ASSERT (SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)); + + Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] ^ SD_PEIM_MEM_BIT (Bit)); + SD_PEIM_NEXT_BIT (Byte, Bit); + } + + break; + } + } + + // + // If Block == NULL, it means that the current memory isn't + // in the host controller's pool. This is critical because + // the caller has passed in a wrong memory point + // + ASSERT (Block != NULL); + + // + // Release the current memory block if it is empty and not the head + // + if ((Block != Head) && SdPeimIsMemBlockEmpty (Block)) { + SdPeimFreeMemBlock (Pool, Block); + } + + return; +} diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.h b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.h index 70620a5f81..4aabd927f2 100644 --- a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.h +++ b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.h @@ -1,55 +1,55 @@ -/** @file
-
-Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
-
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _SD_PEIM_MEM_H_
-#define _SD_PEIM_MEM_H_
-
-#define SD_PEIM_MEM_BIT(a) ((UINTN)(1 << (a)))
-
-#define SD_PEIM_MEM_BIT_IS_SET(Data, Bit) \
- ((BOOLEAN)(((Data) & SD_PEIM_MEM_BIT(Bit)) == SD_PEIM_MEM_BIT(Bit)))
-
-typedef struct _SD_PEIM_MEM_BLOCK SD_PEIM_MEM_BLOCK;
-
-struct _SD_PEIM_MEM_BLOCK {
- UINT8 *Bits; // Bit array to record which unit is allocated
- UINTN BitsLen;
- UINT8 *Buf;
- UINT8 *BufHost;
- UINTN BufLen; // Memory size in bytes
- VOID *Mapping;
- SD_PEIM_MEM_BLOCK *Next;
-};
-
-typedef struct _SD_PEIM_MEM_POOL {
- SD_PEIM_MEM_BLOCK *Head;
-} SD_PEIM_MEM_POOL;
-
-//
-// Memory allocation unit, note that the value must meet SD spec alignment requirement.
-//
-#define SD_PEIM_MEM_UNIT 128
-
-#define SD_PEIM_MEM_UNIT_MASK (SD_PEIM_MEM_UNIT - 1)
-#define SD_PEIM_MEM_DEFAULT_PAGES 16
-
-#define SD_PEIM_MEM_ROUND(Len) (((Len) + SD_PEIM_MEM_UNIT_MASK) & (~SD_PEIM_MEM_UNIT_MASK))
-
-//
-// Advance the byte and bit to the next bit, adjust byte accordingly.
-//
-#define SD_PEIM_NEXT_BIT(Byte, Bit) \
- do { \
- (Bit)++; \
- if ((Bit) > 7) { \
- (Byte)++; \
- (Bit) = 0; \
- } \
- } while (0)
-
-#endif
+/** @file + +Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SD_PEIM_MEM_H_ +#define _SD_PEIM_MEM_H_ + +#define SD_PEIM_MEM_BIT(a) ((UINTN)(1 << (a))) + +#define SD_PEIM_MEM_BIT_IS_SET(Data, Bit) \ + ((BOOLEAN)(((Data) & SD_PEIM_MEM_BIT(Bit)) == SD_PEIM_MEM_BIT(Bit))) + +typedef struct _SD_PEIM_MEM_BLOCK SD_PEIM_MEM_BLOCK; + +struct _SD_PEIM_MEM_BLOCK { + UINT8 *Bits; // Bit array to record which unit is allocated + UINTN BitsLen; + UINT8 *Buf; + UINT8 *BufHost; + UINTN BufLen; // Memory size in bytes + VOID *Mapping; + SD_PEIM_MEM_BLOCK *Next; +}; + +typedef struct _SD_PEIM_MEM_POOL { + SD_PEIM_MEM_BLOCK *Head; +} SD_PEIM_MEM_POOL; + +// +// Memory allocation unit, note that the value must meet SD spec alignment requirement. +// +#define SD_PEIM_MEM_UNIT 128 + +#define SD_PEIM_MEM_UNIT_MASK (SD_PEIM_MEM_UNIT - 1) +#define SD_PEIM_MEM_DEFAULT_PAGES 16 + +#define SD_PEIM_MEM_ROUND(Len) (((Len) + SD_PEIM_MEM_UNIT_MASK) & (~SD_PEIM_MEM_UNIT_MASK)) + +// +// Advance the byte and bit to the next bit, adjust byte accordingly. +// +#define SD_PEIM_NEXT_BIT(Byte, Bit) \ + do { \ + (Bit)++; \ + if ((Bit) > 7) { \ + (Byte)++; \ + (Bit) = 0; \ + } \ + } while (0) + +#endif diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c index 774cae35f2..ba8fb50925 100644 --- a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c +++ b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c @@ -1,3013 +1,3013 @@ -/** @file
-
- Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "SdBlockIoPei.h"
-
-/**
- Read/Write specified SD host controller mmio register.
-
- @param[in] Address The address of the mmio register to be read/written.
- @param[in] Read A boolean to indicate it's read or write operation.
- @param[in] Count The width of the mmio register in bytes.
- Must be 1, 2 , 4 or 8 bytes.
- @param[in, out] Data For read operations, the destination buffer to store
- the results. For write operations, the source buffer
- to write data from. The caller is responsible for
- having ownership of the data buffer and ensuring its
- size not less than Count bytes.
-
- @retval EFI_INVALID_PARAMETER The Address or the Data or the Count is not valid.
- @retval EFI_SUCCESS The read/write operation succeeds.
- @retval Others The read/write operation fails.
-
-**/
-EFI_STATUS
-EFIAPI
-SdPeimHcRwMmio (
- IN UINTN Address,
- IN BOOLEAN Read,
- IN UINT8 Count,
- IN OUT VOID *Data
- )
-{
- if ((Address == 0) || (Data == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) {
- return EFI_INVALID_PARAMETER;
- }
-
- switch (Count) {
- case 1:
- if (Read) {
- *(UINT8 *)Data = MmioRead8 (Address);
- } else {
- MmioWrite8 (Address, *(UINT8 *)Data);
- }
-
- break;
- case 2:
- if (Read) {
- *(UINT16 *)Data = MmioRead16 (Address);
- } else {
- MmioWrite16 (Address, *(UINT16 *)Data);
- }
-
- break;
- case 4:
- if (Read) {
- *(UINT32 *)Data = MmioRead32 (Address);
- } else {
- MmioWrite32 (Address, *(UINT32 *)Data);
- }
-
- break;
- case 8:
- if (Read) {
- *(UINT64 *)Data = MmioRead64 (Address);
- } else {
- MmioWrite64 (Address, *(UINT64 *)Data);
- }
-
- break;
- default:
- ASSERT (FALSE);
- return EFI_INVALID_PARAMETER;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Do OR operation with the value of the specified SD host controller mmio register.
-
- @param[in] Address The address of the mmio register to be read/written.
- @param[in] Count The width of the mmio register in bytes.
- Must be 1, 2 , 4 or 8 bytes.
- @param[in] OrData The pointer to the data used to do OR operation.
- The caller is responsible for having ownership of
- the data buffer and ensuring its size not less than
- Count bytes.
-
- @retval EFI_INVALID_PARAMETER The Address or the OrData or the Count is not valid.
- @retval EFI_SUCCESS The OR operation succeeds.
- @retval Others The OR operation fails.
-
-**/
-EFI_STATUS
-EFIAPI
-SdPeimHcOrMmio (
- IN UINTN Address,
- IN UINT8 Count,
- IN VOID *OrData
- )
-{
- EFI_STATUS Status;
- UINT64 Data;
- UINT64 Or;
-
- Status = SdPeimHcRwMmio (Address, TRUE, Count, &Data);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Count == 1) {
- Or = *(UINT8 *)OrData;
- } else if (Count == 2) {
- Or = *(UINT16 *)OrData;
- } else if (Count == 4) {
- Or = *(UINT32 *)OrData;
- } else if (Count == 8) {
- Or = *(UINT64 *)OrData;
- } else {
- return EFI_INVALID_PARAMETER;
- }
-
- Data |= Or;
- Status = SdPeimHcRwMmio (Address, FALSE, Count, &Data);
-
- return Status;
-}
-
-/**
- Do AND operation with the value of the specified SD host controller mmio register.
-
- @param[in] Address The address of the mmio register to be read/written.
- @param[in] Count The width of the mmio register in bytes.
- Must be 1, 2 , 4 or 8 bytes.
- @param[in] AndData The pointer to the data used to do AND operation.
- The caller is responsible for having ownership of
- the data buffer and ensuring its size not less than
- Count bytes.
-
- @retval EFI_INVALID_PARAMETER The Address or the AndData or the Count is not valid.
- @retval EFI_SUCCESS The AND operation succeeds.
- @retval Others The AND operation fails.
-
-**/
-EFI_STATUS
-EFIAPI
-SdPeimHcAndMmio (
- IN UINTN Address,
- IN UINT8 Count,
- IN VOID *AndData
- )
-{
- EFI_STATUS Status;
- UINT64 Data;
- UINT64 And;
-
- Status = SdPeimHcRwMmio (Address, TRUE, Count, &Data);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Count == 1) {
- And = *(UINT8 *)AndData;
- } else if (Count == 2) {
- And = *(UINT16 *)AndData;
- } else if (Count == 4) {
- And = *(UINT32 *)AndData;
- } else if (Count == 8) {
- And = *(UINT64 *)AndData;
- } else {
- return EFI_INVALID_PARAMETER;
- }
-
- Data &= And;
- Status = SdPeimHcRwMmio (Address, FALSE, Count, &Data);
-
- return Status;
-}
-
-/**
- Wait for the value of the specified MMIO register set to the test value.
-
- @param[in] Address The address of the mmio register to be checked.
- @param[in] Count The width of the mmio register in bytes.
- Must be 1, 2, 4 or 8 bytes.
- @param[in] MaskValue The mask value of memory.
- @param[in] TestValue The test value of memory.
-
- @retval EFI_NOT_READY The MMIO register hasn't set to the expected value.
- @retval EFI_SUCCESS The MMIO register has expected value.
- @retval Others The MMIO operation fails.
-
-**/
-EFI_STATUS
-EFIAPI
-SdPeimHcCheckMmioSet (
- IN UINTN Address,
- IN UINT8 Count,
- IN UINT64 MaskValue,
- IN UINT64 TestValue
- )
-{
- EFI_STATUS Status;
- UINT64 Value;
-
- //
- // Access PCI MMIO space to see if the value is the tested one.
- //
- Value = 0;
- Status = SdPeimHcRwMmio (Address, TRUE, Count, &Value);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Value &= MaskValue;
-
- if (Value == TestValue) {
- return EFI_SUCCESS;
- }
-
- return EFI_NOT_READY;
-}
-
-/**
- Wait for the value of the specified MMIO register set to the test value.
-
- @param[in] Address The address of the mmio register to wait.
- @param[in] Count The width of the mmio register in bytes.
- Must be 1, 2, 4 or 8 bytes.
- @param[in] MaskValue The mask value of memory.
- @param[in] TestValue The test value of memory.
- @param[in] Timeout The time out value for wait memory set, uses 1
- microsecond as a unit.
-
- @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout
- range.
- @retval EFI_SUCCESS The MMIO register has expected value.
- @retval Others The MMIO operation fails.
-
-**/
-EFI_STATUS
-EFIAPI
-SdPeimHcWaitMmioSet (
- IN UINTN Address,
- IN UINT8 Count,
- IN UINT64 MaskValue,
- IN UINT64 TestValue,
- IN UINT64 Timeout
- )
-{
- EFI_STATUS Status;
- BOOLEAN InfiniteWait;
-
- if (Timeout == 0) {
- InfiniteWait = TRUE;
- } else {
- InfiniteWait = FALSE;
- }
-
- while (InfiniteWait || (Timeout > 0)) {
- Status = SdPeimHcCheckMmioSet (
- Address,
- Count,
- MaskValue,
- TestValue
- );
- if (Status != EFI_NOT_READY) {
- return Status;
- }
-
- //
- // Stall for 1 microsecond.
- //
- MicroSecondDelay (1);
-
- Timeout--;
- }
-
- return EFI_TIMEOUT;
-}
-
-/**
- Software reset the specified SD host controller and enable all interrupts.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The software reset executes successfully.
- @retval Others The software reset fails.
-
-**/
-EFI_STATUS
-SdPeimHcReset (
- IN UINTN Bar
- )
-{
- EFI_STATUS Status;
- UINT8 SwReset;
-
- SwReset = 0xFF;
- Status = SdPeimHcRwMmio (Bar + SD_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset);
-
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "SdPeimHcReset: write full 1 fails: %r\n", Status));
- return Status;
- }
-
- Status = SdPeimHcWaitMmioSet (
- Bar + SD_HC_SW_RST,
- sizeof (SwReset),
- 0xFF,
- 0x00,
- SD_TIMEOUT
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_INFO, "SdPeimHcReset: reset done with %r\n", Status));
- return Status;
- }
-
- //
- // Enable all interrupt after reset all.
- //
- Status = SdPeimHcEnableInterrupt (Bar);
-
- return Status;
-}
-
-/**
- Set all interrupt status bits in Normal and Error Interrupt Status Enable
- register.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The operation executes successfully.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimHcEnableInterrupt (
- IN UINTN Bar
- )
-{
- EFI_STATUS Status;
- UINT16 IntStatus;
-
- //
- // Enable all bits in Error Interrupt Status Enable Register
- //
- IntStatus = 0xFFFF;
- Status = SdPeimHcRwMmio (Bar + SD_HC_ERR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Enable all bits in Normal Interrupt Status Enable Register
- //
- IntStatus = 0xFFFF;
- Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);
-
- return Status;
-}
-
-/**
- Get the capability data from the specified slot.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[out] Capability The buffer to store the capability data.
-
- @retval EFI_SUCCESS The operation executes successfully.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimHcGetCapability (
- IN UINTN Bar,
- OUT SD_HC_SLOT_CAP *Capability
- )
-{
- EFI_STATUS Status;
- UINT64 Cap;
-
- Status = SdPeimHcRwMmio (Bar + SD_HC_CAP, TRUE, sizeof (Cap), &Cap);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- CopyMem (Capability, &Cap, sizeof (Cap));
-
- return EFI_SUCCESS;
-}
-
-/**
- Detect whether there is a SD card attached at the specified SD host controller
- slot.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS There is a SD card attached.
- @retval EFI_NO_MEDIA There is not a SD card attached.
- @retval Others The detection fails.
-
-**/
-EFI_STATUS
-SdPeimHcCardDetect (
- IN UINTN Bar
- )
-{
- EFI_STATUS Status;
- UINT16 Data;
- UINT32 PresentState;
-
- //
- // Check Normal Interrupt Status Register
- //
- Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, TRUE, sizeof (Data), &Data);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if ((Data & (BIT6 | BIT7)) != 0) {
- //
- // Clear BIT6 and BIT7 by writing 1 to these two bits if set.
- //
- Data &= BIT6 | BIT7;
- Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, FALSE, sizeof (Data), &Data);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- //
- // Check Present State Register to see if there is a card presented.
- //
- Status = SdPeimHcRwMmio (Bar + SD_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if ((PresentState & BIT16) != 0) {
- return EFI_SUCCESS;
- } else {
- return EFI_NO_MEDIA;
- }
-}
-
-/**
- Stop SD card clock.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS Succeed to stop SD clock.
- @retval Others Fail to stop SD clock.
-
-**/
-EFI_STATUS
-SdPeimHcStopClock (
- IN UINTN Bar
- )
-{
- EFI_STATUS Status;
- UINT32 PresentState;
- UINT16 ClockCtrl;
-
- //
- // Ensure no SD transactions are occurring on the SD Bus by
- // waiting for Command Inhibit (DAT) and Command Inhibit (CMD)
- // in the Present State register to be 0.
- //
- Status = SdPeimHcWaitMmioSet (
- Bar + SD_HC_PRESENT_STATE,
- sizeof (PresentState),
- BIT0 | BIT1,
- 0,
- SD_TIMEOUT
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Set SD Clock Enable in the Clock Control register to 0
- //
- ClockCtrl = (UINT16) ~BIT2;
- Status = SdPeimHcAndMmio (Bar + SD_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
-
- return Status;
-}
-
-/**
- SD card clock supply.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
-
- @retval EFI_SUCCESS The clock is supplied successfully.
- @retval Others The clock isn't supplied successfully.
-
-**/
-EFI_STATUS
-SdPeimHcClockSupply (
- IN UINTN Bar,
- IN UINT64 ClockFreq
- )
-{
- EFI_STATUS Status;
- SD_HC_SLOT_CAP Capability;
- UINT32 BaseClkFreq;
- UINT32 SettingFreq;
- UINT32 Divisor;
- UINT32 Remainder;
- UINT16 ControllerVer;
- UINT16 ClockCtrl;
-
- //
- // Calculate a divisor for SD clock frequency
- //
- Status = SdPeimHcGetCapability (Bar, &Capability);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- ASSERT (Capability.BaseClkFreq != 0);
-
- BaseClkFreq = Capability.BaseClkFreq;
-
- if (ClockFreq == 0) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (ClockFreq > (BaseClkFreq * 1000)) {
- ClockFreq = BaseClkFreq * 1000;
- }
-
- //
- // Calculate the divisor of base frequency.
- //
- Divisor = 0;
- SettingFreq = BaseClkFreq * 1000;
- while (ClockFreq < SettingFreq) {
- Divisor++;
-
- SettingFreq = (BaseClkFreq * 1000) / (2 * Divisor);
- Remainder = (BaseClkFreq * 1000) % (2 * Divisor);
- if ((ClockFreq == SettingFreq) && (Remainder == 0)) {
- break;
- }
-
- if ((ClockFreq == SettingFreq) && (Remainder != 0)) {
- SettingFreq++;
- }
- }
-
- DEBUG ((DEBUG_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq));
-
- Status = SdPeimHcRwMmio (Bar + SD_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register.
- //
- if ((ControllerVer & 0xFF) == 2) {
- ASSERT (Divisor <= 0x3FF);
- ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2);
- } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {
- //
- // Only the most significant bit can be used as divisor.
- //
- if (((Divisor - 1) & Divisor) != 0) {
- Divisor = 1 << (HighBitSet32 (Divisor) + 1);
- }
-
- ASSERT (Divisor <= 0x80);
- ClockCtrl = (Divisor & 0xFF) << 8;
- } else {
- DEBUG ((DEBUG_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer));
- return EFI_UNSUPPORTED;
- }
-
- //
- // Stop bus clock at first
- //
- Status = SdPeimHcStopClock (Bar);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Supply clock frequency with specified divisor
- //
- ClockCtrl |= BIT0;
- Status = SdPeimHcRwMmio (Bar + SD_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n"));
- return Status;
- }
-
- //
- // Wait Internal Clock Stable in the Clock Control register to be 1
- //
- Status = SdPeimHcWaitMmioSet (
- Bar + SD_HC_CLOCK_CTRL,
- sizeof (ClockCtrl),
- BIT1,
- BIT1,
- SD_TIMEOUT
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Set SD Clock Enable in the Clock Control register to 1
- //
- ClockCtrl = BIT2;
- Status = SdPeimHcOrMmio (Bar + SD_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
-
- return Status;
-}
-
-/**
- SD bus power control.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] PowerCtrl The value setting to the power control register.
-
- @retval TRUE There is a SD card attached.
- @retval FALSE There is no a SD card attached.
-
-**/
-EFI_STATUS
-SdPeimHcPowerControl (
- IN UINTN Bar,
- IN UINT8 PowerCtrl
- )
-{
- EFI_STATUS Status;
-
- //
- // Clr SD Bus Power
- //
- PowerCtrl &= (UINT8) ~BIT0;
- Status = SdPeimHcRwMmio (Bar + SD_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register
- //
- PowerCtrl |= BIT0;
- Status = SdPeimHcRwMmio (Bar + SD_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);
-
- return Status;
-}
-
-/**
- Set the SD bus width.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] BusWidth The bus width used by the SD device, it must be 1, 4 or 8.
-
- @retval EFI_SUCCESS The bus width is set successfully.
- @retval Others The bus width isn't set successfully.
-
-**/
-EFI_STATUS
-SdPeimHcSetBusWidth (
- IN UINTN Bar,
- IN UINT16 BusWidth
- )
-{
- EFI_STATUS Status;
- UINT8 HostCtrl1;
-
- if (BusWidth == 1) {
- HostCtrl1 = (UINT8) ~(BIT5 | BIT1);
- Status = SdPeimHcAndMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
- } else if (BusWidth == 4) {
- Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- HostCtrl1 |= BIT1;
- HostCtrl1 &= (UINT8) ~BIT5;
- Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);
- } else if (BusWidth == 8) {
- Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- HostCtrl1 &= (UINT8) ~BIT1;
- HostCtrl1 |= BIT5;
- Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);
- } else {
- ASSERT (FALSE);
- return EFI_INVALID_PARAMETER;
- }
-
- return Status;
-}
-
-/**
- Supply SD card with lowest clock frequency at initialization.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The clock is supplied successfully.
- @retval Others The clock isn't supplied successfully.
-
-**/
-EFI_STATUS
-SdPeimHcInitClockFreq (
- IN UINTN Bar
- )
-{
- EFI_STATUS Status;
- SD_HC_SLOT_CAP Capability;
- UINT32 InitFreq;
-
- //
- // Calculate a divisor for SD clock frequency
- //
- Status = SdPeimHcGetCapability (Bar, &Capability);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Capability.BaseClkFreq == 0) {
- //
- // Don't support get Base Clock Frequency information via another method
- //
- return EFI_UNSUPPORTED;
- }
-
- //
- // Supply 400KHz clock frequency at initialization phase.
- //
- InitFreq = 400;
- Status = SdPeimHcClockSupply (Bar, InitFreq);
- return Status;
-}
-
-/**
- Supply SD card with maximum voltage at initialization.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The voltage is supplied successfully.
- @retval Others The voltage isn't supplied successfully.
-
-**/
-EFI_STATUS
-SdPeimHcInitPowerVoltage (
- IN UINTN Bar
- )
-{
- EFI_STATUS Status;
- SD_HC_SLOT_CAP Capability;
- UINT8 MaxVoltage;
- UINT8 HostCtrl2;
-
- //
- // Get the support voltage of the Host Controller
- //
- Status = SdPeimHcGetCapability (Bar, &Capability);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Calculate supported maximum voltage according to SD Bus Voltage Select
- //
- if (Capability.Voltage33 != 0) {
- //
- // Support 3.3V
- //
- MaxVoltage = 0x0E;
- } else if (Capability.Voltage30 != 0) {
- //
- // Support 3.0V
- //
- MaxVoltage = 0x0C;
- } else if (Capability.Voltage18 != 0) {
- //
- // Support 1.8V
- //
- MaxVoltage = 0x0A;
- HostCtrl2 = BIT3;
- Status = SdPeimHcOrMmio (Bar + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- MicroSecondDelay (5000);
- } else {
- ASSERT (FALSE);
- return EFI_DEVICE_ERROR;
- }
-
- //
- // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register
- //
- Status = SdPeimHcPowerControl (Bar, MaxVoltage);
-
- return Status;
-}
-
-/**
- Initialize the Timeout Control register with most conservative value at initialization.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The timeout control register is configured successfully.
- @retval Others The timeout control register isn't configured successfully.
-
-**/
-EFI_STATUS
-SdPeimHcInitTimeoutCtrl (
- IN UINTN Bar
- )
-{
- EFI_STATUS Status;
- UINT8 Timeout;
-
- Timeout = 0x0E;
- Status = SdPeimHcRwMmio (Bar + SD_HC_TIMEOUT_CTRL, FALSE, sizeof (Timeout), &Timeout);
-
- return Status;
-}
-
-/**
- Initial SD host controller with lowest clock frequency, max power and max timeout value
- at initialization.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The host controller is initialized successfully.
- @retval Others The host controller isn't initialized successfully.
-
-**/
-EFI_STATUS
-SdPeimHcInitHost (
- IN UINTN Bar
- )
-{
- EFI_STATUS Status;
-
- Status = SdPeimHcInitClockFreq (Bar);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = SdPeimHcInitPowerVoltage (Bar);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = SdPeimHcInitTimeoutCtrl (Bar);
- return Status;
-}
-
-/**
- Turn on/off LED.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] On The boolean to turn on/off LED.
-
- @retval EFI_SUCCESS The LED is turned on/off successfully.
- @retval Others The LED isn't turned on/off successfully.
-
-**/
-EFI_STATUS
-SdPeimHcLedOnOff (
- IN UINTN Bar,
- IN BOOLEAN On
- )
-{
- EFI_STATUS Status;
- UINT8 HostCtrl1;
-
- if (On) {
- HostCtrl1 = BIT0;
- Status = SdPeimHcOrMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
- } else {
- HostCtrl1 = (UINT8) ~BIT0;
- Status = SdPeimHcAndMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
- }
-
- return Status;
-}
-
-/**
- Build ADMA descriptor table for transfer.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details.
-
- @param[in] Trb The pointer to the SD_TRB instance.
-
- @retval EFI_SUCCESS The ADMA descriptor table is created successfully.
- @retval Others The ADMA descriptor table isn't created successfully.
-
-**/
-EFI_STATUS
-BuildAdmaDescTable (
- IN SD_TRB *Trb
- )
-{
- EFI_PHYSICAL_ADDRESS Data;
- UINT64 DataLen;
- UINT64 Entries;
- UINT32 Index;
- UINT64 Remaining;
- UINT32 Address;
-
- Data = Trb->DataPhy;
- DataLen = Trb->DataLen;
- //
- // Only support 32bit ADMA Descriptor Table
- //
- if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)
- // for 32-bit address descriptor table.
- //
- if ((Data & (BIT0 | BIT1)) != 0) {
- DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));
- }
-
- Entries = DivU64x32 ((DataLen + ADMA_MAX_DATA_PER_LINE - 1), ADMA_MAX_DATA_PER_LINE);
-
- Trb->AdmaDescSize = (UINTN)MultU64x32 (Entries, sizeof (SD_HC_ADMA_DESC_LINE));
- Trb->AdmaDesc = SdPeimAllocateMem (Trb->Slot->Private->Pool, Trb->AdmaDescSize);
- if (Trb->AdmaDesc == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Remaining = DataLen;
- Address = (UINT32)Data;
- for (Index = 0; Index < Entries; Index++) {
- if (Remaining <= ADMA_MAX_DATA_PER_LINE) {
- Trb->AdmaDesc[Index].Valid = 1;
- Trb->AdmaDesc[Index].Act = 2;
- Trb->AdmaDesc[Index].Length = (UINT16)Remaining;
- Trb->AdmaDesc[Index].Address = Address;
- break;
- } else {
- Trb->AdmaDesc[Index].Valid = 1;
- Trb->AdmaDesc[Index].Act = 2;
- Trb->AdmaDesc[Index].Length = 0;
- Trb->AdmaDesc[Index].Address = Address;
- }
-
- Remaining -= ADMA_MAX_DATA_PER_LINE;
- Address += ADMA_MAX_DATA_PER_LINE;
- }
-
- //
- // Set the last descriptor line as end of descriptor table
- //
- Trb->AdmaDesc[Index].End = 1;
- return EFI_SUCCESS;
-}
-
-/**
- Create a new TRB for the SD cmd request.
-
- @param[in] Slot The slot number of the SD card to send the command to.
- @param[in] Packet A pointer to the SD command data structure.
-
- @return Created Trb or NULL.
-
-**/
-SD_TRB *
-SdPeimCreateTrb (
- IN SD_PEIM_HC_SLOT *Slot,
- IN SD_COMMAND_PACKET *Packet
- )
-{
- SD_TRB *Trb;
- EFI_STATUS Status;
- SD_HC_SLOT_CAP Capability;
- EDKII_IOMMU_OPERATION MapOp;
- UINTN MapLength;
-
- //
- // Calculate a divisor for SD clock frequency
- //
- Status = SdPeimHcGetCapability (Slot->SdHcBase, &Capability);
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- Trb = AllocateZeroPool (sizeof (SD_TRB));
- if (Trb == NULL) {
- return NULL;
- }
-
- Trb->Slot = Slot;
- Trb->BlockSize = 0x200;
- Trb->Packet = Packet;
- Trb->Timeout = Packet->Timeout;
-
- if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {
- Trb->Data = Packet->InDataBuffer;
- Trb->DataLen = Packet->InTransferLength;
- Trb->Read = TRUE;
- } else if ((Packet->OutTransferLength != 0) && (Packet->OutDataBuffer != NULL)) {
- Trb->Data = Packet->OutDataBuffer;
- Trb->DataLen = Packet->OutTransferLength;
- Trb->Read = FALSE;
- } else if ((Packet->InTransferLength == 0) && (Packet->OutTransferLength == 0)) {
- Trb->Data = NULL;
- Trb->DataLen = 0;
- } else {
- goto Error;
- }
-
- if ((Trb->DataLen != 0) && (Trb->DataLen < Trb->BlockSize)) {
- Trb->BlockSize = (UINT16)Trb->DataLen;
- }
-
- if (Packet->SdCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK) {
- Trb->Mode = SdPioMode;
- } else {
- if (Trb->Read) {
- MapOp = EdkiiIoMmuOperationBusMasterWrite;
- } else {
- MapOp = EdkiiIoMmuOperationBusMasterRead;
- }
-
- if (Trb->DataLen != 0) {
- MapLength = Trb->DataLen;
- Status = IoMmuMap (MapOp, Trb->Data, &MapLength, &Trb->DataPhy, &Trb->DataMap);
-
- if (EFI_ERROR (Status) || (MapLength != Trb->DataLen)) {
- DEBUG ((DEBUG_ERROR, "SdPeimCreateTrb: Fail to map data buffer.\n"));
- goto Error;
- }
- }
-
- if (Trb->DataLen == 0) {
- Trb->Mode = SdNoData;
- } else if (Capability.Adma2 != 0) {
- Trb->Mode = SdAdmaMode;
- Status = BuildAdmaDescTable (Trb);
- if (EFI_ERROR (Status)) {
- goto Error;
- }
- } else if (Capability.Sdma != 0) {
- Trb->Mode = SdSdmaMode;
- } else {
- Trb->Mode = SdPioMode;
- }
- }
-
- return Trb;
-
-Error:
- SdPeimFreeTrb (Trb);
- return NULL;
-}
-
-/**
- Free the resource used by the TRB.
-
- @param[in] Trb The pointer to the SD_TRB instance.
-
-**/
-VOID
-SdPeimFreeTrb (
- IN SD_TRB *Trb
- )
-{
- if ((Trb != NULL) && (Trb->DataMap != NULL)) {
- IoMmuUnmap (Trb->DataMap);
- }
-
- if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) {
- SdPeimFreeMem (Trb->Slot->Private->Pool, Trb->AdmaDesc, Trb->AdmaDescSize);
- }
-
- if (Trb != NULL) {
- FreePool (Trb);
- }
-
- return;
-}
-
-/**
- Check if the env is ready for execute specified TRB.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] Trb The pointer to the SD_TRB instance.
-
- @retval EFI_SUCCESS The env is ready for TRB execution.
- @retval EFI_NOT_READY The env is not ready for TRB execution.
- @retval Others Some erros happen.
-
-**/
-EFI_STATUS
-SdPeimCheckTrbEnv (
- IN UINTN Bar,
- IN SD_TRB *Trb
- )
-{
- EFI_STATUS Status;
- SD_COMMAND_PACKET *Packet;
- UINT32 PresentState;
-
- Packet = Trb->Packet;
-
- if ((Packet->SdCmdBlk->CommandType == SdCommandTypeAdtc) ||
- (Packet->SdCmdBlk->ResponseType == SdResponseTypeR1b) ||
- (Packet->SdCmdBlk->ResponseType == SdResponseTypeR5b))
- {
- //
- // Wait Command Inhibit (CMD) and Command Inhibit (DAT) in
- // the Present State register to be 0
- //
- PresentState = BIT0 | BIT1;
- } else {
- //
- // Wait Command Inhibit (CMD) in the Present State register
- // to be 0
- //
- PresentState = BIT0;
- }
-
- Status = SdPeimHcCheckMmioSet (
- Bar + SD_HC_PRESENT_STATE,
- sizeof (PresentState),
- PresentState,
- 0
- );
-
- return Status;
-}
-
-/**
- Wait for the env to be ready for execute specified TRB.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] Trb The pointer to the SD_TRB instance.
-
- @retval EFI_SUCCESS The env is ready for TRB execution.
- @retval EFI_TIMEOUT The env is not ready for TRB execution in time.
- @retval Others Some erros happen.
-
-**/
-EFI_STATUS
-SdPeimWaitTrbEnv (
- IN UINTN Bar,
- IN SD_TRB *Trb
- )
-{
- EFI_STATUS Status;
- SD_COMMAND_PACKET *Packet;
- UINT64 Timeout;
- BOOLEAN InfiniteWait;
-
- //
- // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register
- //
- Packet = Trb->Packet;
- Timeout = Packet->Timeout;
- if (Timeout == 0) {
- InfiniteWait = TRUE;
- } else {
- InfiniteWait = FALSE;
- }
-
- while (InfiniteWait || (Timeout > 0)) {
- //
- // Check Trb execution result by reading Normal Interrupt Status register.
- //
- Status = SdPeimCheckTrbEnv (Bar, Trb);
- if (Status != EFI_NOT_READY) {
- return Status;
- }
-
- //
- // Stall for 1 microsecond.
- //
- MicroSecondDelay (1);
-
- Timeout--;
- }
-
- return EFI_TIMEOUT;
-}
-
-/**
- Execute the specified TRB.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] Trb The pointer to the SD_TRB instance.
-
- @retval EFI_SUCCESS The TRB is sent to host controller successfully.
- @retval Others Some erros happen when sending this request to the host controller.
-
-**/
-EFI_STATUS
-SdPeimExecTrb (
- IN UINTN Bar,
- IN SD_TRB *Trb
- )
-{
- EFI_STATUS Status;
- SD_COMMAND_PACKET *Packet;
- UINT16 Cmd;
- UINT16 IntStatus;
- UINT32 Argument;
- UINT16 BlkCount;
- UINT16 BlkSize;
- UINT16 TransMode;
- UINT8 HostCtrl1;
- UINT32 SdmaAddr;
- UINT64 AdmaAddr;
-
- Packet = Trb->Packet;
- //
- // Clear all bits in Error Interrupt Status Register
- //
- IntStatus = 0xFFFF;
- Status = SdPeimHcRwMmio (Bar + SD_HC_ERR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Clear all bits in Normal Interrupt Status Register
- //
- IntStatus = 0xFFFF;
- Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Set Host Control 1 register DMA Select field
- //
- if (Trb->Mode == SdAdmaMode) {
- HostCtrl1 = BIT4;
- Status = SdPeimHcOrMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- SdPeimHcLedOnOff (Bar, TRUE);
-
- if (Trb->Mode == SdSdmaMode) {
- if ((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul) {
- return EFI_INVALID_PARAMETER;
- }
-
- SdmaAddr = (UINT32)(UINTN)Trb->DataPhy;
- Status = SdPeimHcRwMmio (Bar + SD_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- } else if (Trb->Mode == SdAdmaMode) {
- AdmaAddr = (UINT64)(UINTN)Trb->AdmaDesc;
- Status = SdPeimHcRwMmio (Bar + SD_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- BlkSize = Trb->BlockSize;
- if (Trb->Mode == SdSdmaMode) {
- //
- // Set SDMA boundary to be 512K bytes.
- //
- BlkSize |= 0x7000;
- }
-
- Status = SdPeimHcRwMmio (Bar + SD_HC_BLK_SIZE, FALSE, sizeof (BlkSize), &BlkSize);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- BlkCount = 0;
- if (Trb->Mode != SdNoData) {
- //
- // Calculate Block Count.
- //
- BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);
- }
-
- Status = SdPeimHcRwMmio (Bar + SD_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Argument = Packet->SdCmdBlk->CommandArgument;
- Status = SdPeimHcRwMmio (Bar + SD_HC_ARG1, FALSE, sizeof (Argument), &Argument);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- TransMode = 0;
- if (Trb->Mode != SdNoData) {
- if (Trb->Mode != SdPioMode) {
- TransMode |= BIT0;
- }
-
- if (Trb->Read) {
- TransMode |= BIT4;
- }
-
- if (BlkCount > 1) {
- TransMode |= BIT5 | BIT1;
- }
-
- //
- // SD memory card needs to use AUTO CMD12 feature.
- //
- if (BlkCount > 1) {
- TransMode |= BIT2;
- }
- }
-
- Status = SdPeimHcRwMmio (Bar + SD_HC_TRANS_MOD, FALSE, sizeof (TransMode), &TransMode);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Cmd = (UINT16)LShiftU64 (Packet->SdCmdBlk->CommandIndex, 8);
- if (Packet->SdCmdBlk->CommandType == SdCommandTypeAdtc) {
- Cmd |= BIT5;
- }
-
- //
- // Convert ResponseType to value
- //
- if (Packet->SdCmdBlk->CommandType != SdCommandTypeBc) {
- switch (Packet->SdCmdBlk->ResponseType) {
- case SdResponseTypeR1:
- case SdResponseTypeR5:
- case SdResponseTypeR6:
- case SdResponseTypeR7:
- Cmd |= (BIT1 | BIT3 | BIT4);
- break;
- case SdResponseTypeR2:
- Cmd |= (BIT0 | BIT3);
- break;
- case SdResponseTypeR3:
- case SdResponseTypeR4:
- Cmd |= BIT1;
- break;
- case SdResponseTypeR1b:
- case SdResponseTypeR5b:
- Cmd |= (BIT0 | BIT1 | BIT3 | BIT4);
- break;
- default:
- ASSERT (FALSE);
- break;
- }
- }
-
- //
- // Execute cmd
- //
- Status = SdPeimHcRwMmio (Bar + SD_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd);
- return Status;
-}
-
-/**
- Check the TRB execution result.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] Trb The pointer to the SD_TRB instance.
-
- @retval EFI_SUCCESS The TRB is executed successfully.
- @retval EFI_NOT_READY The TRB is not completed for execution.
- @retval Others Some erros happen when executing this request.
-
-**/
-EFI_STATUS
-SdPeimCheckTrbResult (
- IN UINTN Bar,
- IN SD_TRB *Trb
- )
-{
- EFI_STATUS Status;
- SD_COMMAND_PACKET *Packet;
- UINT16 IntStatus;
- UINT32 Response[4];
- UINT32 SdmaAddr;
- UINT8 Index;
- UINT8 SwReset;
- UINT32 PioLength;
-
- SwReset = 0;
- Packet = Trb->Packet;
- //
- // Check Trb execution result by reading Normal Interrupt Status register.
- //
- Status = SdPeimHcRwMmio (
- Bar + SD_HC_NOR_INT_STS,
- TRUE,
- sizeof (IntStatus),
- &IntStatus
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Check Transfer Complete bit is set or not.
- //
- if ((IntStatus & BIT1) == BIT1) {
- if ((IntStatus & BIT15) == BIT15) {
- //
- // Read Error Interrupt Status register to check if the error is
- // Data Timeout Error.
- // If yes, treat it as success as Transfer Complete has higher
- // priority than Data Timeout Error.
- //
- Status = SdPeimHcRwMmio (
- Bar + SD_HC_ERR_INT_STS,
- TRUE,
- sizeof (IntStatus),
- &IntStatus
- );
- if (!EFI_ERROR (Status)) {
- if ((IntStatus & BIT4) == BIT4) {
- Status = EFI_SUCCESS;
- } else {
- Status = EFI_DEVICE_ERROR;
- }
- }
- }
-
- goto Done;
- }
-
- //
- // Check if there is a error happened during cmd execution.
- // If yes, then do error recovery procedure to follow SD Host Controller
- // Simplified Spec 3.0 section 3.10.1.
- //
- if ((IntStatus & BIT15) == BIT15) {
- Status = SdPeimHcRwMmio (
- Bar + SD_HC_ERR_INT_STS,
- TRUE,
- sizeof (IntStatus),
- &IntStatus
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- if ((IntStatus & 0x0F) != 0) {
- SwReset |= BIT1;
- }
-
- if ((IntStatus & 0xF0) != 0) {
- SwReset |= BIT2;
- }
-
- Status = SdPeimHcRwMmio (
- Bar + SD_HC_SW_RST,
- FALSE,
- sizeof (SwReset),
- &SwReset
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = SdPeimHcWaitMmioSet (
- Bar + SD_HC_SW_RST,
- sizeof (SwReset),
- 0xFF,
- 0,
- SD_TIMEOUT
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = EFI_DEVICE_ERROR;
- goto Done;
- }
-
- //
- // Check if DMA interrupt is signalled for the SDMA transfer.
- //
- if ((Trb->Mode == SdSdmaMode) && ((IntStatus & BIT3) == BIT3)) {
- //
- // Clear DMA interrupt bit.
- //
- IntStatus = BIT3;
- Status = SdPeimHcRwMmio (
- Bar + SD_HC_NOR_INT_STS,
- FALSE,
- sizeof (IntStatus),
- &IntStatus
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Update SDMA Address register.
- //
- SdmaAddr = SD_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->DataPhy, SD_SDMA_BOUNDARY);
- Status = SdPeimHcRwMmio (
- Bar + SD_HC_SDMA_ADDR,
- FALSE,
- sizeof (UINT32),
- &SdmaAddr
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Trb->DataPhy = (UINT32)(UINTN)SdmaAddr;
- }
-
- if ((Packet->SdCmdBlk->CommandType != SdCommandTypeAdtc) &&
- (Packet->SdCmdBlk->ResponseType != SdResponseTypeR1b) &&
- (Packet->SdCmdBlk->ResponseType != SdResponseTypeR5b))
- {
- if ((IntStatus & BIT0) == BIT0) {
- Status = EFI_SUCCESS;
- goto Done;
- }
- }
-
- if (Packet->SdCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK) {
- //
- // When performing tuning procedure (Execute Tuning is set to 1) through PIO mode,
- // wait Buffer Read Ready bit of Normal Interrupt Status Register to be 1.
- // Refer to SD Host Controller Simplified Specification 3.0 figure 2-29 for details.
- //
- if ((IntStatus & BIT5) == BIT5) {
- //
- // Clear Buffer Read Ready interrupt at first.
- //
- IntStatus = BIT5;
- SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
- //
- // Read data out from Buffer Port register
- //
- for (PioLength = 0; PioLength < Trb->DataLen; PioLength += 4) {
- SdPeimHcRwMmio (Bar + SD_HC_BUF_DAT_PORT, TRUE, 4, (UINT8 *)Trb->Data + PioLength);
- }
-
- Status = EFI_SUCCESS;
- goto Done;
- }
- }
-
- Status = EFI_NOT_READY;
-Done:
- //
- // Get response data when the cmd is executed successfully.
- //
- if (!EFI_ERROR (Status)) {
- if (Packet->SdCmdBlk->CommandType != SdCommandTypeBc) {
- for (Index = 0; Index < 4; Index++) {
- Status = SdPeimHcRwMmio (
- Bar + SD_HC_RESPONSE + Index * 4,
- TRUE,
- sizeof (UINT32),
- &Response[Index]
- );
- if (EFI_ERROR (Status)) {
- SdPeimHcLedOnOff (Bar, FALSE);
- return Status;
- }
- }
-
- CopyMem (Packet->SdStatusBlk, Response, sizeof (Response));
- }
- }
-
- if (Status != EFI_NOT_READY) {
- SdPeimHcLedOnOff (Bar, FALSE);
- }
-
- return Status;
-}
-
-/**
- Wait for the TRB execution result.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[in] Trb The pointer to the SD_TRB instance.
-
- @retval EFI_SUCCESS The TRB is executed successfully.
- @retval Others Some erros happen when executing this request.
-
-**/
-EFI_STATUS
-SdPeimWaitTrbResult (
- IN UINTN Bar,
- IN SD_TRB *Trb
- )
-{
- EFI_STATUS Status;
- SD_COMMAND_PACKET *Packet;
- UINT64 Timeout;
- BOOLEAN InfiniteWait;
-
- Packet = Trb->Packet;
- //
- // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register
- //
- Timeout = Packet->Timeout;
- if (Timeout == 0) {
- InfiniteWait = TRUE;
- } else {
- InfiniteWait = FALSE;
- }
-
- while (InfiniteWait || (Timeout > 0)) {
- //
- // Check Trb execution result by reading Normal Interrupt Status register.
- //
- Status = SdPeimCheckTrbResult (Bar, Trb);
- if (Status != EFI_NOT_READY) {
- return Status;
- }
-
- //
- // Stall for 1 microsecond.
- //
- MicroSecondDelay (1);
-
- Timeout--;
- }
-
- return EFI_TIMEOUT;
-}
-
-/**
- Sends SD command to an SD card that is attached to the SD controller.
-
- If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.
-
- If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.
-
- If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER
- is returned.
-
- If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,
- EFI_INVALID_PARAMETER is returned.
-
- @param[in] Slot The slot number of the Sd card to send the command to.
- @param[in,out] Packet A pointer to the SD command data structure.
-
- @retval EFI_SUCCESS The SD Command Packet was sent by the host.
- @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD
- command Packet.
- @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.
- @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and
- OutDataBuffer are NULL.
- @retval EFI_NO_MEDIA SD Device not present in the Slot.
- @retval EFI_UNSUPPORTED The command described by the SD Command Packet is not
- supported by the host controller.
- @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the
- limit supported by SD card ( i.e. if the number of bytes
- exceed the Last LBA).
-
-**/
-EFI_STATUS
-EFIAPI
-SdPeimExecCmd (
- IN SD_PEIM_HC_SLOT *Slot,
- IN OUT SD_COMMAND_PACKET *Packet
- )
-{
- EFI_STATUS Status;
- SD_TRB *Trb;
-
- if (Packet == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if ((Packet->SdCmdBlk == NULL) || (Packet->SdStatusBlk == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Trb = SdPeimCreateTrb (Slot, Packet);
- if (Trb == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- Status = SdPeimWaitTrbEnv (Slot->SdHcBase, Trb);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = SdPeimExecTrb (Slot->SdHcBase, Trb);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = SdPeimWaitTrbResult (Slot->SdHcBase, Trb);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
-Done:
- SdPeimFreeTrb (Trb);
-
- return Status;
-}
-
-/**
- Send command GO_IDLE_STATE to the device to make it go to Idle State.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
-
- @retval EFI_SUCCESS The SD device is reset correctly.
- @retval Others The device reset fails.
-
-**/
-EFI_STATUS
-SdPeimReset (
- IN SD_PEIM_HC_SLOT *Slot
- )
-{
- SD_COMMAND_BLOCK SdCmdBlk;
- SD_STATUS_BLOCK SdStatusBlk;
- SD_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
- ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.SdCmdBlk = &SdCmdBlk;
- Packet.SdStatusBlk = &SdStatusBlk;
- Packet.Timeout = SD_TIMEOUT;
-
- SdCmdBlk.CommandIndex = SD_GO_IDLE_STATE;
- SdCmdBlk.CommandType = SdCommandTypeBc;
- SdCmdBlk.ResponseType = 0;
- SdCmdBlk.CommandArgument = 0;
-
- Status = SdPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Send command SEND_IF_COND to the device to inquiry the SD Memory Card interface
- condition.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
- @param[in] SupplyVoltage The supplied voltage by the host.
- @param[in] CheckPattern The check pattern to be sent to the device.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimVoltageCheck (
- IN SD_PEIM_HC_SLOT *Slot,
- IN UINT8 SupplyVoltage,
- IN UINT8 CheckPattern
- )
-{
- SD_COMMAND_BLOCK SdCmdBlk;
- SD_STATUS_BLOCK SdStatusBlk;
- SD_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
- ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.SdCmdBlk = &SdCmdBlk;
- Packet.SdStatusBlk = &SdStatusBlk;
- Packet.Timeout = SD_TIMEOUT;
-
- SdCmdBlk.CommandIndex = SD_SEND_IF_COND;
- SdCmdBlk.CommandType = SdCommandTypeBcr;
- SdCmdBlk.ResponseType = SdResponseTypeR7;
- SdCmdBlk.CommandArgument = (SupplyVoltage << 8) | CheckPattern;
-
- Status = SdPeimExecCmd (Slot, &Packet);
- if (!EFI_ERROR (Status)) {
- if (SdStatusBlk.Resp0 != SdCmdBlk.CommandArgument) {
- return EFI_DEVICE_ERROR;
- }
- }
-
- return Status;
-}
-
-/**
- Send command SDIO_SEND_OP_COND to the device to see whether it is SDIO device.
-
- Refer to SDIO Simplified Spec 3 Section 3.2 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
- @param[in] VoltageWindow The supply voltage window.
- @param[in] S18r The boolean to show if it should switch to 1.8v.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdioSendOpCond (
- IN SD_PEIM_HC_SLOT *Slot,
- IN UINT32 VoltageWindow,
- IN BOOLEAN S18r
- )
-{
- SD_COMMAND_BLOCK SdCmdBlk;
- SD_STATUS_BLOCK SdStatusBlk;
- SD_COMMAND_PACKET Packet;
- EFI_STATUS Status;
- UINT32 Switch;
-
- ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
- ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.SdCmdBlk = &SdCmdBlk;
- Packet.SdStatusBlk = &SdStatusBlk;
- Packet.Timeout = SD_TIMEOUT;
-
- SdCmdBlk.CommandIndex = SDIO_SEND_OP_COND;
- SdCmdBlk.CommandType = SdCommandTypeBcr;
- SdCmdBlk.ResponseType = SdResponseTypeR4;
-
- Switch = S18r ? BIT24 : 0;
-
- SdCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch;
-
- Status = SdPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Send command SD_SEND_OP_COND to the device to see whether it is SDIO device.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
- @param[in] Rca The relative device address of addressed device.
- @param[in] VoltageWindow The supply voltage window.
- @param[in] S18r The boolean to show if it should switch to 1.8v.
- @param[in] Xpc The boolean to show if it should provide 0.36w power control.
- @param[in] Hcs The boolean to show if it support host capacity info.
- @param[out] Ocr The buffer to store returned OCR register value.
-
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimSendOpCond (
- IN SD_PEIM_HC_SLOT *Slot,
- IN UINT16 Rca,
- IN UINT32 VoltageWindow,
- IN BOOLEAN S18r,
- IN BOOLEAN Xpc,
- IN BOOLEAN Hcs,
- OUT UINT32 *Ocr
- )
-{
- SD_COMMAND_BLOCK SdCmdBlk;
- SD_STATUS_BLOCK SdStatusBlk;
- SD_COMMAND_PACKET Packet;
- EFI_STATUS Status;
- UINT32 Switch;
- UINT32 MaxPower;
- UINT32 HostCapacity;
-
- ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
- ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.SdCmdBlk = &SdCmdBlk;
- Packet.SdStatusBlk = &SdStatusBlk;
- Packet.Timeout = SD_TIMEOUT;
-
- SdCmdBlk.CommandIndex = SD_APP_CMD;
- SdCmdBlk.CommandType = SdCommandTypeAc;
- SdCmdBlk.ResponseType = SdResponseTypeR1;
- SdCmdBlk.CommandArgument = (UINT32)Rca << 16;
-
- Status = SdPeimExecCmd (Slot, &Packet);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- SdCmdBlk.CommandIndex = SD_SEND_OP_COND;
- SdCmdBlk.CommandType = SdCommandTypeBcr;
- SdCmdBlk.ResponseType = SdResponseTypeR3;
-
- Switch = S18r ? BIT24 : 0;
- MaxPower = Xpc ? BIT28 : 0;
- HostCapacity = Hcs ? BIT30 : 0;
- SdCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch | MaxPower | HostCapacity;
-
- Status = SdPeimExecCmd (Slot, &Packet);
- if (!EFI_ERROR (Status)) {
- //
- // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
- //
- *Ocr = SdStatusBlk.Resp0;
- }
-
- return Status;
-}
-
-/**
- Broadcast command ALL_SEND_CID to the bus to ask all the SD devices to send the
- data of their CID registers.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimAllSendCid (
- IN SD_PEIM_HC_SLOT *Slot
- )
-{
- SD_COMMAND_BLOCK SdCmdBlk;
- SD_STATUS_BLOCK SdStatusBlk;
- SD_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
- ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.SdCmdBlk = &SdCmdBlk;
- Packet.SdStatusBlk = &SdStatusBlk;
- Packet.Timeout = SD_TIMEOUT;
-
- SdCmdBlk.CommandIndex = SD_ALL_SEND_CID;
- SdCmdBlk.CommandType = SdCommandTypeBcr;
- SdCmdBlk.ResponseType = SdResponseTypeR2;
- SdCmdBlk.CommandArgument = 0;
-
- Status = SdPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Send command SET_RELATIVE_ADDR to the SD device to assign a Relative device
- Address (RCA).
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
- @param[out] Rca The relative device address to be assigned.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimSetRca (
- IN SD_PEIM_HC_SLOT *Slot,
- OUT UINT16 *Rca
- )
-{
- SD_COMMAND_BLOCK SdCmdBlk;
- SD_STATUS_BLOCK SdStatusBlk;
- SD_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
- ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.SdCmdBlk = &SdCmdBlk;
- Packet.SdStatusBlk = &SdStatusBlk;
- Packet.Timeout = SD_TIMEOUT;
-
- SdCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;
- SdCmdBlk.CommandType = SdCommandTypeBcr;
- SdCmdBlk.ResponseType = SdResponseTypeR6;
-
- Status = SdPeimExecCmd (Slot, &Packet);
- if (!EFI_ERROR (Status)) {
- *Rca = (UINT16)(SdStatusBlk.Resp0 >> 16);
- }
-
- return Status;
-}
-
-/**
- Send command SEND_CSD to the SD device to get the data of the CSD register.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
- @param[in] Rca The relative device address of selected device.
- @param[out] Csd The buffer to store the content of the CSD register.
- Note the caller should ignore the lowest byte of this
- buffer as the content of this byte is meaningless even
- if the operation succeeds.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimGetCsd (
- IN SD_PEIM_HC_SLOT *Slot,
- IN UINT16 Rca,
- OUT SD_CSD *Csd
- )
-{
- SD_COMMAND_BLOCK SdCmdBlk;
- SD_STATUS_BLOCK SdStatusBlk;
- SD_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
- ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.SdCmdBlk = &SdCmdBlk;
- Packet.SdStatusBlk = &SdStatusBlk;
- Packet.Timeout = SD_TIMEOUT;
-
- SdCmdBlk.CommandIndex = SD_SEND_CSD;
- SdCmdBlk.CommandType = SdCommandTypeAc;
- SdCmdBlk.ResponseType = SdResponseTypeR2;
- SdCmdBlk.CommandArgument = (UINT32)Rca << 16;
-
- Status = SdPeimExecCmd (Slot, &Packet);
- if (!EFI_ERROR (Status)) {
- //
- // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
- //
- CopyMem (((UINT8 *)Csd) + 1, &SdStatusBlk.Resp0, sizeof (SD_CSD) - 1);
- }
-
- return Status;
-}
-
-/**
- Send command SELECT_DESELECT_CARD to the SD device to select/deselect it.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
- @param[in] Rca The relative device address of selected device.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimSelect (
- IN SD_PEIM_HC_SLOT *Slot,
- IN UINT16 Rca
- )
-{
- SD_COMMAND_BLOCK SdCmdBlk;
- SD_STATUS_BLOCK SdStatusBlk;
- SD_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
- ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.SdCmdBlk = &SdCmdBlk;
- Packet.SdStatusBlk = &SdStatusBlk;
- Packet.Timeout = SD_TIMEOUT;
-
- SdCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;
- SdCmdBlk.CommandType = SdCommandTypeAc;
- SdCmdBlk.ResponseType = SdResponseTypeR1b;
- SdCmdBlk.CommandArgument = (UINT32)Rca << 16;
-
- Status = SdPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Send command VOLTAGE_SWITCH to the SD device to switch the voltage of the device.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimVoltageSwitch (
- IN SD_PEIM_HC_SLOT *Slot
- )
-{
- SD_COMMAND_BLOCK SdCmdBlk;
- SD_STATUS_BLOCK SdStatusBlk;
- SD_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
- ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.SdCmdBlk = &SdCmdBlk;
- Packet.SdStatusBlk = &SdStatusBlk;
- Packet.Timeout = SD_TIMEOUT;
-
- SdCmdBlk.CommandIndex = SD_VOLTAGE_SWITCH;
- SdCmdBlk.CommandType = SdCommandTypeAc;
- SdCmdBlk.ResponseType = SdResponseTypeR1;
- SdCmdBlk.CommandArgument = 0;
-
- Status = SdPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Send command SET_BUS_WIDTH to the SD device to set the bus width.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
- @param[in] Rca The relative device address of addressed device.
- @param[in] BusWidth The bus width to be set, it could be 1 or 4.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimSetBusWidth (
- IN SD_PEIM_HC_SLOT *Slot,
- IN UINT16 Rca,
- IN UINT8 BusWidth
- )
-{
- SD_COMMAND_BLOCK SdCmdBlk;
- SD_STATUS_BLOCK SdStatusBlk;
- SD_COMMAND_PACKET Packet;
- EFI_STATUS Status;
- UINT8 Value;
-
- ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
- ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.SdCmdBlk = &SdCmdBlk;
- Packet.SdStatusBlk = &SdStatusBlk;
- Packet.Timeout = SD_TIMEOUT;
-
- SdCmdBlk.CommandIndex = SD_APP_CMD;
- SdCmdBlk.CommandType = SdCommandTypeAc;
- SdCmdBlk.ResponseType = SdResponseTypeR1;
- SdCmdBlk.CommandArgument = (UINT32)Rca << 16;
-
- Status = SdPeimExecCmd (Slot, &Packet);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- SdCmdBlk.CommandIndex = SD_SET_BUS_WIDTH;
- SdCmdBlk.CommandType = SdCommandTypeAc;
- SdCmdBlk.ResponseType = SdResponseTypeR1;
-
- if (BusWidth == 1) {
- Value = 0;
- } else if (BusWidth == 4) {
- Value = 2;
- } else {
- return EFI_INVALID_PARAMETER;
- }
-
- SdCmdBlk.CommandArgument = Value & 0x3;
-
- Status = SdPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Send command SWITCH_FUNC to the SD device to check switchable function or switch card function.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
- @param[in] AccessMode The value for access mode group.
- @param[in] CommandSystem The value for command set group.
- @param[in] DriveStrength The value for drive length group.
- @param[in] PowerLimit The value for power limit group.
- @param[in] Mode Switch or check function.
- @param[out] SwitchResp The return switch function status.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimSwitch (
- IN SD_PEIM_HC_SLOT *Slot,
- IN UINT8 AccessMode,
- IN UINT8 CommandSystem,
- IN UINT8 DriveStrength,
- IN UINT8 PowerLimit,
- IN BOOLEAN Mode,
- OUT UINT8 *SwitchResp
- )
-{
- SD_COMMAND_BLOCK SdCmdBlk;
- SD_STATUS_BLOCK SdStatusBlk;
- SD_COMMAND_PACKET Packet;
- EFI_STATUS Status;
- UINT32 ModeValue;
-
- ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
- ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.SdCmdBlk = &SdCmdBlk;
- Packet.SdStatusBlk = &SdStatusBlk;
- Packet.Timeout = SD_TIMEOUT;
-
- SdCmdBlk.CommandIndex = SD_SWITCH_FUNC;
- SdCmdBlk.CommandType = SdCommandTypeAdtc;
- SdCmdBlk.ResponseType = SdResponseTypeR1;
-
- ModeValue = Mode ? BIT31 : 0;
- SdCmdBlk.CommandArgument = (AccessMode & 0xF) | ((PowerLimit & 0xF) << 4) | \
- ((DriveStrength & 0xF) << 8) | ((DriveStrength & 0xF) << 12) | \
- ModeValue;
- Packet.InDataBuffer = SwitchResp;
- Packet.InTransferLength = 64;
-
- Status = SdPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Send command SEND_STATUS to the addressed SD device to get its status register.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
- @param[in] Rca The relative device address of addressed device.
- @param[out] DevStatus The returned device status.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimSendStatus (
- IN SD_PEIM_HC_SLOT *Slot,
- IN UINT16 Rca,
- OUT UINT32 *DevStatus
- )
-{
- SD_COMMAND_BLOCK SdCmdBlk;
- SD_STATUS_BLOCK SdStatusBlk;
- SD_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
- ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.SdCmdBlk = &SdCmdBlk;
- Packet.SdStatusBlk = &SdStatusBlk;
- Packet.Timeout = SD_TIMEOUT;
-
- SdCmdBlk.CommandIndex = SD_SEND_STATUS;
- SdCmdBlk.CommandType = SdCommandTypeAc;
- SdCmdBlk.ResponseType = SdResponseTypeR1;
- SdCmdBlk.CommandArgument = (UINT32)Rca << 16;
-
- Status = SdPeimExecCmd (Slot, &Packet);
- if (!EFI_ERROR (Status)) {
- *DevStatus = SdStatusBlk.Resp0;
- }
-
- return Status;
-}
-
-/**
- Send command READ_SINGLE_BLOCK/WRITE_SINGLE_BLOCK to the addressed SD device
- to read/write the specified number of blocks.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
- @param[in] Lba The logical block address of starting access.
- @param[in] BlockSize The block size of specified SD device partition.
- @param[in] Buffer The pointer to the transfer buffer.
- @param[in] BufferSize The size of transfer buffer.
- @param[in] IsRead Boolean to show the operation direction.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimRwSingleBlock (
- IN SD_PEIM_HC_SLOT *Slot,
- IN EFI_LBA Lba,
- IN UINT32 BlockSize,
- IN VOID *Buffer,
- IN UINTN BufferSize,
- IN BOOLEAN IsRead
- )
-{
- SD_COMMAND_BLOCK SdCmdBlk;
- SD_STATUS_BLOCK SdStatusBlk;
- SD_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
- ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.SdCmdBlk = &SdCmdBlk;
- Packet.SdStatusBlk = &SdStatusBlk;
- //
- // Calculate timeout value through the below formula.
- // Timeout = (transfer size) / (2MB/s).
- // Taking 2MB/s as divisor is because it's the lowest
- // transfer speed of class 2.
- //
- Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
-
- if (IsRead) {
- Packet.InDataBuffer = Buffer;
- Packet.InTransferLength = (UINT32)BufferSize;
-
- SdCmdBlk.CommandIndex = SD_READ_SINGLE_BLOCK;
- SdCmdBlk.CommandType = SdCommandTypeAdtc;
- SdCmdBlk.ResponseType = SdResponseTypeR1;
- } else {
- Packet.OutDataBuffer = Buffer;
- Packet.OutTransferLength = (UINT32)BufferSize;
-
- SdCmdBlk.CommandIndex = SD_WRITE_SINGLE_BLOCK;
- SdCmdBlk.CommandType = SdCommandTypeAdtc;
- SdCmdBlk.ResponseType = SdResponseTypeR1;
- }
-
- if (Slot->SectorAddressing) {
- SdCmdBlk.CommandArgument = (UINT32)Lba;
- } else {
- SdCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, BlockSize);
- }
-
- Status = SdPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed SD device
- to read/write the specified number of blocks.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
- @param[in] Lba The logical block address of starting access.
- @param[in] BlockSize The block size of specified SD device partition.
- @param[in] Buffer The pointer to the transfer buffer.
- @param[in] BufferSize The size of transfer buffer.
- @param[in] IsRead Boolean to show the operation direction.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimRwMultiBlocks (
- IN SD_PEIM_HC_SLOT *Slot,
- IN EFI_LBA Lba,
- IN UINT32 BlockSize,
- IN VOID *Buffer,
- IN UINTN BufferSize,
- IN BOOLEAN IsRead
- )
-{
- SD_COMMAND_BLOCK SdCmdBlk;
- SD_STATUS_BLOCK SdStatusBlk;
- SD_COMMAND_PACKET Packet;
- EFI_STATUS Status;
-
- ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
- ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.SdCmdBlk = &SdCmdBlk;
- Packet.SdStatusBlk = &SdStatusBlk;
- //
- // Calculate timeout value through the below formula.
- // Timeout = (transfer size) / (2MB/s).
- // Taking 2MB/s as divisor is because it's the lowest
- // transfer speed of class 2.
- //
- Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
-
- if (IsRead) {
- Packet.InDataBuffer = Buffer;
- Packet.InTransferLength = (UINT32)BufferSize;
-
- SdCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK;
- SdCmdBlk.CommandType = SdCommandTypeAdtc;
- SdCmdBlk.ResponseType = SdResponseTypeR1;
- } else {
- Packet.OutDataBuffer = Buffer;
- Packet.OutTransferLength = (UINT32)BufferSize;
-
- SdCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK;
- SdCmdBlk.CommandType = SdCommandTypeAdtc;
- SdCmdBlk.ResponseType = SdResponseTypeR1;
- }
-
- if (Slot->SectorAddressing) {
- SdCmdBlk.CommandArgument = (UINT32)Lba;
- } else {
- SdCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, BlockSize);
- }
-
- Status = SdPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Send command SEND_TUNING_BLOCK to the SD device for SDR104/SDR50 optimal sampling point
- detection.
-
- It may be sent up to 40 times until the host finishes the tuning procedure.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimSendTuningBlk (
- IN SD_PEIM_HC_SLOT *Slot
- )
-{
- SD_COMMAND_BLOCK SdCmdBlk;
- SD_STATUS_BLOCK SdStatusBlk;
- SD_COMMAND_PACKET Packet;
- EFI_STATUS Status;
- UINT8 TuningBlock[64];
-
- ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
- ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
- ZeroMem (&Packet, sizeof (Packet));
-
- Packet.SdCmdBlk = &SdCmdBlk;
- Packet.SdStatusBlk = &SdStatusBlk;
- Packet.Timeout = SD_TIMEOUT;
-
- SdCmdBlk.CommandIndex = SD_SEND_TUNING_BLOCK;
- SdCmdBlk.CommandType = SdCommandTypeAdtc;
- SdCmdBlk.ResponseType = SdResponseTypeR1;
- SdCmdBlk.CommandArgument = 0;
-
- Packet.InDataBuffer = TuningBlock;
- Packet.InTransferLength = sizeof (TuningBlock);
-
- Status = SdPeimExecCmd (Slot, &Packet);
-
- return Status;
-}
-
-/**
- Tuning the sampling point of SDR104 or SDR50 bus speed mode.
-
- Command SD_SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the
- tuning procedure.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and SD Host Controller
- Simplified Spec 3.0 Figure 2-29 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimTuningClock (
- IN SD_PEIM_HC_SLOT *Slot
- )
-{
- EFI_STATUS Status;
- UINT8 HostCtrl2;
- UINT8 Retry;
-
- //
- // Notify the host that the sampling clock tuning procedure starts.
- //
- HostCtrl2 = BIT6;
- Status = SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.
- //
- Retry = 0;
- do {
- Status = SdPeimSendTuningBlk (Slot);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if ((HostCtrl2 & (BIT6 | BIT7)) == 0) {
- break;
- }
-
- if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {
- return EFI_SUCCESS;
- }
- } while (++Retry < 40);
-
- DEBUG ((DEBUG_ERROR, "SdPeimTuningClock: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2));
- //
- // Abort the tuning procedure and reset the tuning circuit.
- //
- HostCtrl2 = (UINT8) ~(BIT6 | BIT7);
- Status = SdPeimHcAndMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- return EFI_DEVICE_ERROR;
-}
-
-/**
- Switch the bus width to specified width.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and
- SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
- @param[in] Rca The relative device address to be assigned.
- @param[in] BusWidth The bus width to be set, it could be 4 or 8.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimSwitchBusWidth (
- IN SD_PEIM_HC_SLOT *Slot,
- IN UINT16 Rca,
- IN UINT8 BusWidth
- )
-{
- EFI_STATUS Status;
- UINT32 DevStatus;
-
- Status = SdPeimSetBusWidth (Slot, Rca, BusWidth);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = SdPeimSendStatus (Slot, Rca, &DevStatus);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Check the switch operation is really successful or not.
- //
- if ((DevStatus >> 16) != 0) {
- return EFI_DEVICE_ERROR;
- }
-
- Status = SdPeimHcSetBusWidth (Slot->SdHcBase, BusWidth);
-
- return Status;
-}
-
-/**
- Switch the high speed timing according to request.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and
- SD Host Controller Simplified Spec 3.0 section Figure 2-29 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
- @param[in] Rca The relative device address to be assigned.
- @param[in] S18a The boolean to show if it's a UHS-I SD card.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimSetBusMode (
- IN SD_PEIM_HC_SLOT *Slot,
- IN UINT16 Rca,
- IN BOOLEAN S18a
- )
-{
- EFI_STATUS Status;
- SD_HC_SLOT_CAP Capability;
- UINT32 ClockFreq;
- UINT8 BusWidth;
- UINT8 AccessMode;
- UINT8 HostCtrl1;
- UINT8 HostCtrl2;
- UINT8 SwitchResp[64];
-
- Status = SdPeimGetCsd (Slot, Rca, &Slot->Csd);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "SdPeimSetBusMode: SdPeimGetCsd fails with %r\n", Status));
- return Status;
- }
-
- Status = SdPeimHcGetCapability (Slot->SdHcBase, &Capability);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = SdPeimSelect (Slot, Rca);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "SdPeimSetBusMode: SdPeimSelect fails with %r\n", Status));
- return Status;
- }
-
- BusWidth = 4;
- Status = SdPeimSwitchBusWidth (Slot, Rca, BusWidth);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "SdPeimSetBusMode: SdPeimSwitchBusWidth fails with %r\n", Status));
- return Status;
- }
-
- //
- // Get the supported bus speed from SWITCH cmd return data group #1.
- //
- ZeroMem (SwitchResp, sizeof (SwitchResp));
- Status = SdPeimSwitch (Slot, 0xF, 0xF, 0xF, 0xF, FALSE, SwitchResp);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Calculate supported bus speed/bus width/clock frequency by host and device capability.
- //
- ClockFreq = 0;
- if (S18a && (Capability.Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) {
- ClockFreq = 208;
- AccessMode = 3;
- } else if (S18a && (Capability.Sdr50 != 0) && ((SwitchResp[13] & BIT2) != 0)) {
- ClockFreq = 100;
- AccessMode = 2;
- } else if (S18a && (Capability.Ddr50 != 0) && ((SwitchResp[13] & BIT4) != 0)) {
- ClockFreq = 50;
- AccessMode = 4;
- } else if ((SwitchResp[13] & BIT1) != 0) {
- ClockFreq = 50;
- AccessMode = 1;
- } else {
- ClockFreq = 25;
- AccessMode = 0;
- }
-
- DEBUG ((DEBUG_INFO, "SdPeimSetBusMode: AccessMode %d ClockFreq %d BusWidth %d\n", AccessMode, ClockFreq, BusWidth));
-
- Status = SdPeimSwitch (Slot, AccessMode, 0xF, 0xF, 0xF, TRUE, SwitchResp);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "SdPeimSetBusMode: SdPeimSwitch fails with %r\n", Status));
- return Status;
- }
-
- if ((SwitchResp[16] & 0xF) != AccessMode) {
- DEBUG ((DEBUG_ERROR, "SdPeimSetBusMode: SdPeimSwitch to AccessMode %d ClockFreq %d BusWidth %d fails! The Switch response is 0x%1x\n", AccessMode, ClockFreq, BusWidth, SwitchResp[16] & 0xF));
- return EFI_DEVICE_ERROR;
- }
-
- //
- // Set to High Speed timing
- //
- if (AccessMode == 1) {
- HostCtrl1 = BIT2;
- Status = SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- HostCtrl2 = (UINT8) ~0x7;
- Status = SdPeimHcAndMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- HostCtrl2 = AccessMode;
- Status = SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = SdPeimHcClockSupply (Slot->SdHcBase, ClockFreq * 1000);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "SdPeimSetBusMode: SdPeimHcClockSupply %r\n", Status));
- return Status;
- }
-
- if ((AccessMode == 3) || ((AccessMode == 2) && (Capability.TuningSDR50 != 0))) {
- Status = SdPeimTuningClock (Slot);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "SdPeimSetBusMode: SdPeimTuningClock fails with %r\n", Status));
- return Status;
- }
- }
-
- DEBUG ((DEBUG_INFO, "SdPeimSetBusMode: SdPeimSetBusMode %r\n", Status));
-
- return Status;
-}
-
-/**
- Execute SD device identification procedure.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 3.6 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
-
- @retval EFI_SUCCESS There is a SD card.
- @retval Others There is not a SD card.
-
-**/
-EFI_STATUS
-SdPeimIdentification (
- IN SD_PEIM_HC_SLOT *Slot
- )
-{
- EFI_STATUS Status;
- UINT32 Ocr;
- UINT16 Rca;
- BOOLEAN Xpc;
- BOOLEAN S18r;
- UINT64 MaxCurrent;
- UINT64 Current;
- UINT16 ControllerVer;
- UINT8 PowerCtrl;
- UINT32 PresentState;
- UINT8 HostCtrl2;
- SD_HC_SLOT_CAP Capability;
- UINTN Retry;
-
- //
- // 1. Send Cmd0 to the device
- //
- Status = SdPeimReset (Slot);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "SdPeimIdentification: Executing Cmd0 fails with %r\n", Status));
- return Status;
- }
-
- //
- // 2. Send Cmd8 to the device
- //
- Status = SdPeimVoltageCheck (Slot, 0x1, 0xFF);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "SdPeimIdentification: Executing Cmd8 fails with %r\n", Status));
- return Status;
- }
-
- //
- // 3. Send SDIO Cmd5 to the device to the SDIO device OCR register.
- //
- Status = SdioSendOpCond (Slot, 0, FALSE);
- if (!EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "SdPeimIdentification: Found SDIO device, ignore it as we don't support\n"));
- return EFI_DEVICE_ERROR;
- }
-
- //
- // 4. Send Acmd41 with voltage window 0 to the device
- //
- Status = SdPeimSendOpCond (Slot, 0, 0, FALSE, FALSE, FALSE, &Ocr);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "SdPeimIdentification: Executing SdPeimSendOpCond fails with %r\n", Status));
- return EFI_DEVICE_ERROR;
- }
-
- Status = SdPeimHcGetCapability (Slot->SdHcBase, &Capability);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_MAX_CURRENT_CAP, TRUE, sizeof (Current), &Current);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Capability.Voltage33 != 0) {
- //
- // Support 3.3V
- //
- MaxCurrent = ((UINT32)Current & 0xFF) * 4;
- } else if (Capability.Voltage30 != 0) {
- //
- // Support 3.0V
- //
- MaxCurrent = (((UINT32)Current >> 8) & 0xFF) * 4;
- } else if (Capability.Voltage18 != 0) {
- //
- // Support 1.8V
- //
- MaxCurrent = (((UINT32)Current >> 16) & 0xFF) * 4;
- } else {
- ASSERT (FALSE);
- return EFI_DEVICE_ERROR;
- }
-
- if (MaxCurrent >= 150) {
- Xpc = TRUE;
- } else {
- Xpc = FALSE;
- }
-
- Status = SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if ((ControllerVer & 0xFF) == 2) {
- S18r = TRUE;
- } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {
- S18r = FALSE;
- } else {
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
- }
-
- //
- // 5. Repeatly send Acmd41 with supply voltage window to the device.
- // Note here we only support the cards complied with SD physical
- // layer simplified spec version 2.0 and version 3.0 and above.
- //
- Ocr = 0;
- Retry = 0;
- do {
- Status = SdPeimSendOpCond (Slot, 0, Ocr, S18r, Xpc, TRUE, &Ocr);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "SdPeimIdentification: SdPeimSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n", Status, Ocr, S18r, Xpc));
- return EFI_DEVICE_ERROR;
- }
-
- if (Retry++ == 100) {
- DEBUG ((DEBUG_ERROR, "SdPeimIdentification: SdPeimSendOpCond fails too many times\n"));
- return EFI_DEVICE_ERROR;
- }
-
- MicroSecondDelay (10 * 1000);
- } while ((Ocr & BIT31) == 0);
-
- //
- // 6. If the S18a bit is set and the Host Controller supports 1.8V signaling
- // (One of support bits is set to 1: SDR50, SDR104 or DDR50 in the
- // Capabilities register), switch its voltage to 1.8V.
- //
- if (((Capability.Sdr50 != 0) ||
- (Capability.Sdr104 != 0) ||
- (Capability.Ddr50 != 0)) &&
- ((Ocr & BIT24) != 0))
- {
- Status = SdPeimVoltageSwitch (Slot);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "SdPeimIdentification: Executing SdPeimVoltageSwitch fails with %r\n", Status));
- Status = EFI_DEVICE_ERROR;
- goto Error;
- } else {
- Status = SdPeimHcStopClock (Slot->SdHcBase);
- if (EFI_ERROR (Status)) {
- Status = EFI_DEVICE_ERROR;
- goto Error;
- }
-
- SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
- if (((PresentState >> 20) & 0xF) != 0) {
- DEBUG ((DEBUG_ERROR, "SdPeimIdentification: SwitchVoltage fails with PresentState = 0x%x\n", PresentState));
- Status = EFI_DEVICE_ERROR;
- goto Error;
- }
-
- HostCtrl2 = BIT3;
- SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
-
- MicroSecondDelay (5000);
-
- SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);
- if ((HostCtrl2 & BIT3) == 0) {
- DEBUG ((DEBUG_ERROR, "SdPeimIdentification: SwitchVoltage fails with HostCtrl2 = 0x%x\n", HostCtrl2));
- Status = EFI_DEVICE_ERROR;
- goto Error;
- }
-
- SdPeimHcInitClockFreq (Slot->SdHcBase);
-
- MicroSecondDelay (1000);
-
- SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
- if (((PresentState >> 20) & 0xF) != 0xF) {
- DEBUG ((DEBUG_ERROR, "SdPeimIdentification: SwitchVoltage fails with PresentState = 0x%x, It should be 0xF\n", PresentState));
- Status = EFI_DEVICE_ERROR;
- goto Error;
- }
- }
-
- DEBUG ((DEBUG_INFO, "SdPeimIdentification: Switch to 1.8v signal voltage success\n"));
- }
-
- Status = SdPeimAllSendCid (Slot);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "SdPeimIdentification: Executing SdPeimAllSendCid fails with %r\n", Status));
- return Status;
- }
-
- Status = SdPeimSetRca (Slot, &Rca);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "SdPeimIdentification: Executing SdPeimSetRca fails with %r\n", Status));
- return Status;
- }
-
- //
- // Enter Data Tranfer Mode.
- //
- DEBUG ((DEBUG_INFO, "Found a SD device at slot [%d]\n", Slot));
-
- Status = SdPeimSetBusMode (Slot, Rca, ((Ocr & BIT24) != 0));
-
- return Status;
-
-Error:
- //
- // Set SD Bus Power = 0
- //
- PowerCtrl = (UINT8) ~BIT0;
- Status = SdPeimHcAndMmio (Slot->SdHcBase + SD_HC_POWER_CTRL, sizeof (PowerCtrl), &PowerCtrl);
- return EFI_DEVICE_ERROR;
-}
+/** @file + + Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SdBlockIoPei.h" + +/** + Read/Write specified SD host controller mmio register. + + @param[in] Address The address of the mmio register to be read/written. + @param[in] Read A boolean to indicate it's read or write operation. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in, out] Data For read operations, the destination buffer to store + the results. For write operations, the source buffer + to write data from. The caller is responsible for + having ownership of the data buffer and ensuring its + size not less than Count bytes. + + @retval EFI_INVALID_PARAMETER The Address or the Data or the Count is not valid. + @retval EFI_SUCCESS The read/write operation succeeds. + @retval Others The read/write operation fails. + +**/ +EFI_STATUS +EFIAPI +SdPeimHcRwMmio ( + IN UINTN Address, + IN BOOLEAN Read, + IN UINT8 Count, + IN OUT VOID *Data + ) +{ + if ((Address == 0) || (Data == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) { + return EFI_INVALID_PARAMETER; + } + + switch (Count) { + case 1: + if (Read) { + *(UINT8 *)Data = MmioRead8 (Address); + } else { + MmioWrite8 (Address, *(UINT8 *)Data); + } + + break; + case 2: + if (Read) { + *(UINT16 *)Data = MmioRead16 (Address); + } else { + MmioWrite16 (Address, *(UINT16 *)Data); + } + + break; + case 4: + if (Read) { + *(UINT32 *)Data = MmioRead32 (Address); + } else { + MmioWrite32 (Address, *(UINT32 *)Data); + } + + break; + case 8: + if (Read) { + *(UINT64 *)Data = MmioRead64 (Address); + } else { + MmioWrite64 (Address, *(UINT64 *)Data); + } + + break; + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +/** + Do OR operation with the value of the specified SD host controller mmio register. + + @param[in] Address The address of the mmio register to be read/written. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in] OrData The pointer to the data used to do OR operation. + The caller is responsible for having ownership of + the data buffer and ensuring its size not less than + Count bytes. + + @retval EFI_INVALID_PARAMETER The Address or the OrData or the Count is not valid. + @retval EFI_SUCCESS The OR operation succeeds. + @retval Others The OR operation fails. + +**/ +EFI_STATUS +EFIAPI +SdPeimHcOrMmio ( + IN UINTN Address, + IN UINT8 Count, + IN VOID *OrData + ) +{ + EFI_STATUS Status; + UINT64 Data; + UINT64 Or; + + Status = SdPeimHcRwMmio (Address, TRUE, Count, &Data); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Count == 1) { + Or = *(UINT8 *)OrData; + } else if (Count == 2) { + Or = *(UINT16 *)OrData; + } else if (Count == 4) { + Or = *(UINT32 *)OrData; + } else if (Count == 8) { + Or = *(UINT64 *)OrData; + } else { + return EFI_INVALID_PARAMETER; + } + + Data |= Or; + Status = SdPeimHcRwMmio (Address, FALSE, Count, &Data); + + return Status; +} + +/** + Do AND operation with the value of the specified SD host controller mmio register. + + @param[in] Address The address of the mmio register to be read/written. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2 , 4 or 8 bytes. + @param[in] AndData The pointer to the data used to do AND operation. + The caller is responsible for having ownership of + the data buffer and ensuring its size not less than + Count bytes. + + @retval EFI_INVALID_PARAMETER The Address or the AndData or the Count is not valid. + @retval EFI_SUCCESS The AND operation succeeds. + @retval Others The AND operation fails. + +**/ +EFI_STATUS +EFIAPI +SdPeimHcAndMmio ( + IN UINTN Address, + IN UINT8 Count, + IN VOID *AndData + ) +{ + EFI_STATUS Status; + UINT64 Data; + UINT64 And; + + Status = SdPeimHcRwMmio (Address, TRUE, Count, &Data); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Count == 1) { + And = *(UINT8 *)AndData; + } else if (Count == 2) { + And = *(UINT16 *)AndData; + } else if (Count == 4) { + And = *(UINT32 *)AndData; + } else if (Count == 8) { + And = *(UINT64 *)AndData; + } else { + return EFI_INVALID_PARAMETER; + } + + Data &= And; + Status = SdPeimHcRwMmio (Address, FALSE, Count, &Data); + + return Status; +} + +/** + Wait for the value of the specified MMIO register set to the test value. + + @param[in] Address The address of the mmio register to be checked. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2, 4 or 8 bytes. + @param[in] MaskValue The mask value of memory. + @param[in] TestValue The test value of memory. + + @retval EFI_NOT_READY The MMIO register hasn't set to the expected value. + @retval EFI_SUCCESS The MMIO register has expected value. + @retval Others The MMIO operation fails. + +**/ +EFI_STATUS +EFIAPI +SdPeimHcCheckMmioSet ( + IN UINTN Address, + IN UINT8 Count, + IN UINT64 MaskValue, + IN UINT64 TestValue + ) +{ + EFI_STATUS Status; + UINT64 Value; + + // + // Access PCI MMIO space to see if the value is the tested one. + // + Value = 0; + Status = SdPeimHcRwMmio (Address, TRUE, Count, &Value); + if (EFI_ERROR (Status)) { + return Status; + } + + Value &= MaskValue; + + if (Value == TestValue) { + return EFI_SUCCESS; + } + + return EFI_NOT_READY; +} + +/** + Wait for the value of the specified MMIO register set to the test value. + + @param[in] Address The address of the mmio register to wait. + @param[in] Count The width of the mmio register in bytes. + Must be 1, 2, 4 or 8 bytes. + @param[in] MaskValue The mask value of memory. + @param[in] TestValue The test value of memory. + @param[in] Timeout The time out value for wait memory set, uses 1 + microsecond as a unit. + + @retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout + range. + @retval EFI_SUCCESS The MMIO register has expected value. + @retval Others The MMIO operation fails. + +**/ +EFI_STATUS +EFIAPI +SdPeimHcWaitMmioSet ( + IN UINTN Address, + IN UINT8 Count, + IN UINT64 MaskValue, + IN UINT64 TestValue, + IN UINT64 Timeout + ) +{ + EFI_STATUS Status; + BOOLEAN InfiniteWait; + + if (Timeout == 0) { + InfiniteWait = TRUE; + } else { + InfiniteWait = FALSE; + } + + while (InfiniteWait || (Timeout > 0)) { + Status = SdPeimHcCheckMmioSet ( + Address, + Count, + MaskValue, + TestValue + ); + if (Status != EFI_NOT_READY) { + return Status; + } + + // + // Stall for 1 microsecond. + // + MicroSecondDelay (1); + + Timeout--; + } + + return EFI_TIMEOUT; +} + +/** + Software reset the specified SD host controller and enable all interrupts. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The software reset executes successfully. + @retval Others The software reset fails. + +**/ +EFI_STATUS +SdPeimHcReset ( + IN UINTN Bar + ) +{ + EFI_STATUS Status; + UINT8 SwReset; + + SwReset = 0xFF; + Status = SdPeimHcRwMmio (Bar + SD_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdPeimHcReset: write full 1 fails: %r\n", Status)); + return Status; + } + + Status = SdPeimHcWaitMmioSet ( + Bar + SD_HC_SW_RST, + sizeof (SwReset), + 0xFF, + 0x00, + SD_TIMEOUT + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "SdPeimHcReset: reset done with %r\n", Status)); + return Status; + } + + // + // Enable all interrupt after reset all. + // + Status = SdPeimHcEnableInterrupt (Bar); + + return Status; +} + +/** + Set all interrupt status bits in Normal and Error Interrupt Status Enable + register. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimHcEnableInterrupt ( + IN UINTN Bar + ) +{ + EFI_STATUS Status; + UINT16 IntStatus; + + // + // Enable all bits in Error Interrupt Status Enable Register + // + IntStatus = 0xFFFF; + Status = SdPeimHcRwMmio (Bar + SD_HC_ERR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Enable all bits in Normal Interrupt Status Enable Register + // + IntStatus = 0xFFFF; + Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus); + + return Status; +} + +/** + Get the capability data from the specified slot. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[out] Capability The buffer to store the capability data. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimHcGetCapability ( + IN UINTN Bar, + OUT SD_HC_SLOT_CAP *Capability + ) +{ + EFI_STATUS Status; + UINT64 Cap; + + Status = SdPeimHcRwMmio (Bar + SD_HC_CAP, TRUE, sizeof (Cap), &Cap); + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem (Capability, &Cap, sizeof (Cap)); + + return EFI_SUCCESS; +} + +/** + Detect whether there is a SD card attached at the specified SD host controller + slot. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS There is a SD card attached. + @retval EFI_NO_MEDIA There is not a SD card attached. + @retval Others The detection fails. + +**/ +EFI_STATUS +SdPeimHcCardDetect ( + IN UINTN Bar + ) +{ + EFI_STATUS Status; + UINT16 Data; + UINT32 PresentState; + + // + // Check Normal Interrupt Status Register + // + Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, TRUE, sizeof (Data), &Data); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((Data & (BIT6 | BIT7)) != 0) { + // + // Clear BIT6 and BIT7 by writing 1 to these two bits if set. + // + Data &= BIT6 | BIT7; + Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, FALSE, sizeof (Data), &Data); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Check Present State Register to see if there is a card presented. + // + Status = SdPeimHcRwMmio (Bar + SD_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((PresentState & BIT16) != 0) { + return EFI_SUCCESS; + } else { + return EFI_NO_MEDIA; + } +} + +/** + Stop SD card clock. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS Succeed to stop SD clock. + @retval Others Fail to stop SD clock. + +**/ +EFI_STATUS +SdPeimHcStopClock ( + IN UINTN Bar + ) +{ + EFI_STATUS Status; + UINT32 PresentState; + UINT16 ClockCtrl; + + // + // Ensure no SD transactions are occurring on the SD Bus by + // waiting for Command Inhibit (DAT) and Command Inhibit (CMD) + // in the Present State register to be 0. + // + Status = SdPeimHcWaitMmioSet ( + Bar + SD_HC_PRESENT_STATE, + sizeof (PresentState), + BIT0 | BIT1, + 0, + SD_TIMEOUT + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set SD Clock Enable in the Clock Control register to 0 + // + ClockCtrl = (UINT16) ~BIT2; + Status = SdPeimHcAndMmio (Bar + SD_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl); + + return Status; +} + +/** + SD card clock supply. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] ClockFreq The max clock frequency to be set. The unit is KHz. + + @retval EFI_SUCCESS The clock is supplied successfully. + @retval Others The clock isn't supplied successfully. + +**/ +EFI_STATUS +SdPeimHcClockSupply ( + IN UINTN Bar, + IN UINT64 ClockFreq + ) +{ + EFI_STATUS Status; + SD_HC_SLOT_CAP Capability; + UINT32 BaseClkFreq; + UINT32 SettingFreq; + UINT32 Divisor; + UINT32 Remainder; + UINT16 ControllerVer; + UINT16 ClockCtrl; + + // + // Calculate a divisor for SD clock frequency + // + Status = SdPeimHcGetCapability (Bar, &Capability); + if (EFI_ERROR (Status)) { + return Status; + } + + ASSERT (Capability.BaseClkFreq != 0); + + BaseClkFreq = Capability.BaseClkFreq; + + if (ClockFreq == 0) { + return EFI_INVALID_PARAMETER; + } + + if (ClockFreq > (BaseClkFreq * 1000)) { + ClockFreq = BaseClkFreq * 1000; + } + + // + // Calculate the divisor of base frequency. + // + Divisor = 0; + SettingFreq = BaseClkFreq * 1000; + while (ClockFreq < SettingFreq) { + Divisor++; + + SettingFreq = (BaseClkFreq * 1000) / (2 * Divisor); + Remainder = (BaseClkFreq * 1000) % (2 * Divisor); + if ((ClockFreq == SettingFreq) && (Remainder == 0)) { + break; + } + + if ((ClockFreq == SettingFreq) && (Remainder != 0)) { + SettingFreq++; + } + } + + DEBUG ((DEBUG_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq)); + + Status = SdPeimHcRwMmio (Bar + SD_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register. + // + if ((ControllerVer & 0xFF) == 2) { + ASSERT (Divisor <= 0x3FF); + ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2); + } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) { + // + // Only the most significant bit can be used as divisor. + // + if (((Divisor - 1) & Divisor) != 0) { + Divisor = 1 << (HighBitSet32 (Divisor) + 1); + } + + ASSERT (Divisor <= 0x80); + ClockCtrl = (Divisor & 0xFF) << 8; + } else { + DEBUG ((DEBUG_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer)); + return EFI_UNSUPPORTED; + } + + // + // Stop bus clock at first + // + Status = SdPeimHcStopClock (Bar); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Supply clock frequency with specified divisor + // + ClockCtrl |= BIT0; + Status = SdPeimHcRwMmio (Bar + SD_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n")); + return Status; + } + + // + // Wait Internal Clock Stable in the Clock Control register to be 1 + // + Status = SdPeimHcWaitMmioSet ( + Bar + SD_HC_CLOCK_CTRL, + sizeof (ClockCtrl), + BIT1, + BIT1, + SD_TIMEOUT + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set SD Clock Enable in the Clock Control register to 1 + // + ClockCtrl = BIT2; + Status = SdPeimHcOrMmio (Bar + SD_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl); + + return Status; +} + +/** + SD bus power control. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] PowerCtrl The value setting to the power control register. + + @retval TRUE There is a SD card attached. + @retval FALSE There is no a SD card attached. + +**/ +EFI_STATUS +SdPeimHcPowerControl ( + IN UINTN Bar, + IN UINT8 PowerCtrl + ) +{ + EFI_STATUS Status; + + // + // Clr SD Bus Power + // + PowerCtrl &= (UINT8) ~BIT0; + Status = SdPeimHcRwMmio (Bar + SD_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register + // + PowerCtrl |= BIT0; + Status = SdPeimHcRwMmio (Bar + SD_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl); + + return Status; +} + +/** + Set the SD bus width. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] BusWidth The bus width used by the SD device, it must be 1, 4 or 8. + + @retval EFI_SUCCESS The bus width is set successfully. + @retval Others The bus width isn't set successfully. + +**/ +EFI_STATUS +SdPeimHcSetBusWidth ( + IN UINTN Bar, + IN UINT16 BusWidth + ) +{ + EFI_STATUS Status; + UINT8 HostCtrl1; + + if (BusWidth == 1) { + HostCtrl1 = (UINT8) ~(BIT5 | BIT1); + Status = SdPeimHcAndMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1); + } else if (BusWidth == 4) { + Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1); + if (EFI_ERROR (Status)) { + return Status; + } + + HostCtrl1 |= BIT1; + HostCtrl1 &= (UINT8) ~BIT5; + Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1); + } else if (BusWidth == 8) { + Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1); + if (EFI_ERROR (Status)) { + return Status; + } + + HostCtrl1 &= (UINT8) ~BIT1; + HostCtrl1 |= BIT5; + Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1); + } else { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + return Status; +} + +/** + Supply SD card with lowest clock frequency at initialization. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The clock is supplied successfully. + @retval Others The clock isn't supplied successfully. + +**/ +EFI_STATUS +SdPeimHcInitClockFreq ( + IN UINTN Bar + ) +{ + EFI_STATUS Status; + SD_HC_SLOT_CAP Capability; + UINT32 InitFreq; + + // + // Calculate a divisor for SD clock frequency + // + Status = SdPeimHcGetCapability (Bar, &Capability); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Capability.BaseClkFreq == 0) { + // + // Don't support get Base Clock Frequency information via another method + // + return EFI_UNSUPPORTED; + } + + // + // Supply 400KHz clock frequency at initialization phase. + // + InitFreq = 400; + Status = SdPeimHcClockSupply (Bar, InitFreq); + return Status; +} + +/** + Supply SD card with maximum voltage at initialization. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The voltage is supplied successfully. + @retval Others The voltage isn't supplied successfully. + +**/ +EFI_STATUS +SdPeimHcInitPowerVoltage ( + IN UINTN Bar + ) +{ + EFI_STATUS Status; + SD_HC_SLOT_CAP Capability; + UINT8 MaxVoltage; + UINT8 HostCtrl2; + + // + // Get the support voltage of the Host Controller + // + Status = SdPeimHcGetCapability (Bar, &Capability); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Calculate supported maximum voltage according to SD Bus Voltage Select + // + if (Capability.Voltage33 != 0) { + // + // Support 3.3V + // + MaxVoltage = 0x0E; + } else if (Capability.Voltage30 != 0) { + // + // Support 3.0V + // + MaxVoltage = 0x0C; + } else if (Capability.Voltage18 != 0) { + // + // Support 1.8V + // + MaxVoltage = 0x0A; + HostCtrl2 = BIT3; + Status = SdPeimHcOrMmio (Bar + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + MicroSecondDelay (5000); + } else { + ASSERT (FALSE); + return EFI_DEVICE_ERROR; + } + + // + // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register + // + Status = SdPeimHcPowerControl (Bar, MaxVoltage); + + return Status; +} + +/** + Initialize the Timeout Control register with most conservative value at initialization. + + Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The timeout control register is configured successfully. + @retval Others The timeout control register isn't configured successfully. + +**/ +EFI_STATUS +SdPeimHcInitTimeoutCtrl ( + IN UINTN Bar + ) +{ + EFI_STATUS Status; + UINT8 Timeout; + + Timeout = 0x0E; + Status = SdPeimHcRwMmio (Bar + SD_HC_TIMEOUT_CTRL, FALSE, sizeof (Timeout), &Timeout); + + return Status; +} + +/** + Initial SD host controller with lowest clock frequency, max power and max timeout value + at initialization. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The host controller is initialized successfully. + @retval Others The host controller isn't initialized successfully. + +**/ +EFI_STATUS +SdPeimHcInitHost ( + IN UINTN Bar + ) +{ + EFI_STATUS Status; + + Status = SdPeimHcInitClockFreq (Bar); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = SdPeimHcInitPowerVoltage (Bar); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = SdPeimHcInitTimeoutCtrl (Bar); + return Status; +} + +/** + Turn on/off LED. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] On The boolean to turn on/off LED. + + @retval EFI_SUCCESS The LED is turned on/off successfully. + @retval Others The LED isn't turned on/off successfully. + +**/ +EFI_STATUS +SdPeimHcLedOnOff ( + IN UINTN Bar, + IN BOOLEAN On + ) +{ + EFI_STATUS Status; + UINT8 HostCtrl1; + + if (On) { + HostCtrl1 = BIT0; + Status = SdPeimHcOrMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1); + } else { + HostCtrl1 = (UINT8) ~BIT0; + Status = SdPeimHcAndMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1); + } + + return Status; +} + +/** + Build ADMA descriptor table for transfer. + + Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details. + + @param[in] Trb The pointer to the SD_TRB instance. + + @retval EFI_SUCCESS The ADMA descriptor table is created successfully. + @retval Others The ADMA descriptor table isn't created successfully. + +**/ +EFI_STATUS +BuildAdmaDescTable ( + IN SD_TRB *Trb + ) +{ + EFI_PHYSICAL_ADDRESS Data; + UINT64 DataLen; + UINT64 Entries; + UINT32 Index; + UINT64 Remaining; + UINT32 Address; + + Data = Trb->DataPhy; + DataLen = Trb->DataLen; + // + // Only support 32bit ADMA Descriptor Table + // + if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) { + return EFI_INVALID_PARAMETER; + } + + // + // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0) + // for 32-bit address descriptor table. + // + if ((Data & (BIT0 | BIT1)) != 0) { + DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data)); + } + + Entries = DivU64x32 ((DataLen + ADMA_MAX_DATA_PER_LINE - 1), ADMA_MAX_DATA_PER_LINE); + + Trb->AdmaDescSize = (UINTN)MultU64x32 (Entries, sizeof (SD_HC_ADMA_DESC_LINE)); + Trb->AdmaDesc = SdPeimAllocateMem (Trb->Slot->Private->Pool, Trb->AdmaDescSize); + if (Trb->AdmaDesc == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Remaining = DataLen; + Address = (UINT32)Data; + for (Index = 0; Index < Entries; Index++) { + if (Remaining <= ADMA_MAX_DATA_PER_LINE) { + Trb->AdmaDesc[Index].Valid = 1; + Trb->AdmaDesc[Index].Act = 2; + Trb->AdmaDesc[Index].Length = (UINT16)Remaining; + Trb->AdmaDesc[Index].Address = Address; + break; + } else { + Trb->AdmaDesc[Index].Valid = 1; + Trb->AdmaDesc[Index].Act = 2; + Trb->AdmaDesc[Index].Length = 0; + Trb->AdmaDesc[Index].Address = Address; + } + + Remaining -= ADMA_MAX_DATA_PER_LINE; + Address += ADMA_MAX_DATA_PER_LINE; + } + + // + // Set the last descriptor line as end of descriptor table + // + Trb->AdmaDesc[Index].End = 1; + return EFI_SUCCESS; +} + +/** + Create a new TRB for the SD cmd request. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Packet A pointer to the SD command data structure. + + @return Created Trb or NULL. + +**/ +SD_TRB * +SdPeimCreateTrb ( + IN SD_PEIM_HC_SLOT *Slot, + IN SD_COMMAND_PACKET *Packet + ) +{ + SD_TRB *Trb; + EFI_STATUS Status; + SD_HC_SLOT_CAP Capability; + EDKII_IOMMU_OPERATION MapOp; + UINTN MapLength; + + // + // Calculate a divisor for SD clock frequency + // + Status = SdPeimHcGetCapability (Slot->SdHcBase, &Capability); + if (EFI_ERROR (Status)) { + return NULL; + } + + Trb = AllocateZeroPool (sizeof (SD_TRB)); + if (Trb == NULL) { + return NULL; + } + + Trb->Slot = Slot; + Trb->BlockSize = 0x200; + Trb->Packet = Packet; + Trb->Timeout = Packet->Timeout; + + if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) { + Trb->Data = Packet->InDataBuffer; + Trb->DataLen = Packet->InTransferLength; + Trb->Read = TRUE; + } else if ((Packet->OutTransferLength != 0) && (Packet->OutDataBuffer != NULL)) { + Trb->Data = Packet->OutDataBuffer; + Trb->DataLen = Packet->OutTransferLength; + Trb->Read = FALSE; + } else if ((Packet->InTransferLength == 0) && (Packet->OutTransferLength == 0)) { + Trb->Data = NULL; + Trb->DataLen = 0; + } else { + goto Error; + } + + if ((Trb->DataLen != 0) && (Trb->DataLen < Trb->BlockSize)) { + Trb->BlockSize = (UINT16)Trb->DataLen; + } + + if (Packet->SdCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK) { + Trb->Mode = SdPioMode; + } else { + if (Trb->Read) { + MapOp = EdkiiIoMmuOperationBusMasterWrite; + } else { + MapOp = EdkiiIoMmuOperationBusMasterRead; + } + + if (Trb->DataLen != 0) { + MapLength = Trb->DataLen; + Status = IoMmuMap (MapOp, Trb->Data, &MapLength, &Trb->DataPhy, &Trb->DataMap); + + if (EFI_ERROR (Status) || (MapLength != Trb->DataLen)) { + DEBUG ((DEBUG_ERROR, "SdPeimCreateTrb: Fail to map data buffer.\n")); + goto Error; + } + } + + if (Trb->DataLen == 0) { + Trb->Mode = SdNoData; + } else if (Capability.Adma2 != 0) { + Trb->Mode = SdAdmaMode; + Status = BuildAdmaDescTable (Trb); + if (EFI_ERROR (Status)) { + goto Error; + } + } else if (Capability.Sdma != 0) { + Trb->Mode = SdSdmaMode; + } else { + Trb->Mode = SdPioMode; + } + } + + return Trb; + +Error: + SdPeimFreeTrb (Trb); + return NULL; +} + +/** + Free the resource used by the TRB. + + @param[in] Trb The pointer to the SD_TRB instance. + +**/ +VOID +SdPeimFreeTrb ( + IN SD_TRB *Trb + ) +{ + if ((Trb != NULL) && (Trb->DataMap != NULL)) { + IoMmuUnmap (Trb->DataMap); + } + + if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) { + SdPeimFreeMem (Trb->Slot->Private->Pool, Trb->AdmaDesc, Trb->AdmaDescSize); + } + + if (Trb != NULL) { + FreePool (Trb); + } + + return; +} + +/** + Check if the env is ready for execute specified TRB. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] Trb The pointer to the SD_TRB instance. + + @retval EFI_SUCCESS The env is ready for TRB execution. + @retval EFI_NOT_READY The env is not ready for TRB execution. + @retval Others Some erros happen. + +**/ +EFI_STATUS +SdPeimCheckTrbEnv ( + IN UINTN Bar, + IN SD_TRB *Trb + ) +{ + EFI_STATUS Status; + SD_COMMAND_PACKET *Packet; + UINT32 PresentState; + + Packet = Trb->Packet; + + if ((Packet->SdCmdBlk->CommandType == SdCommandTypeAdtc) || + (Packet->SdCmdBlk->ResponseType == SdResponseTypeR1b) || + (Packet->SdCmdBlk->ResponseType == SdResponseTypeR5b)) + { + // + // Wait Command Inhibit (CMD) and Command Inhibit (DAT) in + // the Present State register to be 0 + // + PresentState = BIT0 | BIT1; + } else { + // + // Wait Command Inhibit (CMD) in the Present State register + // to be 0 + // + PresentState = BIT0; + } + + Status = SdPeimHcCheckMmioSet ( + Bar + SD_HC_PRESENT_STATE, + sizeof (PresentState), + PresentState, + 0 + ); + + return Status; +} + +/** + Wait for the env to be ready for execute specified TRB. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] Trb The pointer to the SD_TRB instance. + + @retval EFI_SUCCESS The env is ready for TRB execution. + @retval EFI_TIMEOUT The env is not ready for TRB execution in time. + @retval Others Some erros happen. + +**/ +EFI_STATUS +SdPeimWaitTrbEnv ( + IN UINTN Bar, + IN SD_TRB *Trb + ) +{ + EFI_STATUS Status; + SD_COMMAND_PACKET *Packet; + UINT64 Timeout; + BOOLEAN InfiniteWait; + + // + // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register + // + Packet = Trb->Packet; + Timeout = Packet->Timeout; + if (Timeout == 0) { + InfiniteWait = TRUE; + } else { + InfiniteWait = FALSE; + } + + while (InfiniteWait || (Timeout > 0)) { + // + // Check Trb execution result by reading Normal Interrupt Status register. + // + Status = SdPeimCheckTrbEnv (Bar, Trb); + if (Status != EFI_NOT_READY) { + return Status; + } + + // + // Stall for 1 microsecond. + // + MicroSecondDelay (1); + + Timeout--; + } + + return EFI_TIMEOUT; +} + +/** + Execute the specified TRB. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] Trb The pointer to the SD_TRB instance. + + @retval EFI_SUCCESS The TRB is sent to host controller successfully. + @retval Others Some erros happen when sending this request to the host controller. + +**/ +EFI_STATUS +SdPeimExecTrb ( + IN UINTN Bar, + IN SD_TRB *Trb + ) +{ + EFI_STATUS Status; + SD_COMMAND_PACKET *Packet; + UINT16 Cmd; + UINT16 IntStatus; + UINT32 Argument; + UINT16 BlkCount; + UINT16 BlkSize; + UINT16 TransMode; + UINT8 HostCtrl1; + UINT32 SdmaAddr; + UINT64 AdmaAddr; + + Packet = Trb->Packet; + // + // Clear all bits in Error Interrupt Status Register + // + IntStatus = 0xFFFF; + Status = SdPeimHcRwMmio (Bar + SD_HC_ERR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Clear all bits in Normal Interrupt Status Register + // + IntStatus = 0xFFFF; + Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set Host Control 1 register DMA Select field + // + if (Trb->Mode == SdAdmaMode) { + HostCtrl1 = BIT4; + Status = SdPeimHcOrMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1); + if (EFI_ERROR (Status)) { + return Status; + } + } + + SdPeimHcLedOnOff (Bar, TRUE); + + if (Trb->Mode == SdSdmaMode) { + if ((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul) { + return EFI_INVALID_PARAMETER; + } + + SdmaAddr = (UINT32)(UINTN)Trb->DataPhy; + Status = SdPeimHcRwMmio (Bar + SD_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr); + if (EFI_ERROR (Status)) { + return Status; + } + } else if (Trb->Mode == SdAdmaMode) { + AdmaAddr = (UINT64)(UINTN)Trb->AdmaDesc; + Status = SdPeimHcRwMmio (Bar + SD_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr); + if (EFI_ERROR (Status)) { + return Status; + } + } + + BlkSize = Trb->BlockSize; + if (Trb->Mode == SdSdmaMode) { + // + // Set SDMA boundary to be 512K bytes. + // + BlkSize |= 0x7000; + } + + Status = SdPeimHcRwMmio (Bar + SD_HC_BLK_SIZE, FALSE, sizeof (BlkSize), &BlkSize); + if (EFI_ERROR (Status)) { + return Status; + } + + BlkCount = 0; + if (Trb->Mode != SdNoData) { + // + // Calculate Block Count. + // + BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize); + } + + Status = SdPeimHcRwMmio (Bar + SD_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount); + if (EFI_ERROR (Status)) { + return Status; + } + + Argument = Packet->SdCmdBlk->CommandArgument; + Status = SdPeimHcRwMmio (Bar + SD_HC_ARG1, FALSE, sizeof (Argument), &Argument); + if (EFI_ERROR (Status)) { + return Status; + } + + TransMode = 0; + if (Trb->Mode != SdNoData) { + if (Trb->Mode != SdPioMode) { + TransMode |= BIT0; + } + + if (Trb->Read) { + TransMode |= BIT4; + } + + if (BlkCount > 1) { + TransMode |= BIT5 | BIT1; + } + + // + // SD memory card needs to use AUTO CMD12 feature. + // + if (BlkCount > 1) { + TransMode |= BIT2; + } + } + + Status = SdPeimHcRwMmio (Bar + SD_HC_TRANS_MOD, FALSE, sizeof (TransMode), &TransMode); + if (EFI_ERROR (Status)) { + return Status; + } + + Cmd = (UINT16)LShiftU64 (Packet->SdCmdBlk->CommandIndex, 8); + if (Packet->SdCmdBlk->CommandType == SdCommandTypeAdtc) { + Cmd |= BIT5; + } + + // + // Convert ResponseType to value + // + if (Packet->SdCmdBlk->CommandType != SdCommandTypeBc) { + switch (Packet->SdCmdBlk->ResponseType) { + case SdResponseTypeR1: + case SdResponseTypeR5: + case SdResponseTypeR6: + case SdResponseTypeR7: + Cmd |= (BIT1 | BIT3 | BIT4); + break; + case SdResponseTypeR2: + Cmd |= (BIT0 | BIT3); + break; + case SdResponseTypeR3: + case SdResponseTypeR4: + Cmd |= BIT1; + break; + case SdResponseTypeR1b: + case SdResponseTypeR5b: + Cmd |= (BIT0 | BIT1 | BIT3 | BIT4); + break; + default: + ASSERT (FALSE); + break; + } + } + + // + // Execute cmd + // + Status = SdPeimHcRwMmio (Bar + SD_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd); + return Status; +} + +/** + Check the TRB execution result. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] Trb The pointer to the SD_TRB instance. + + @retval EFI_SUCCESS The TRB is executed successfully. + @retval EFI_NOT_READY The TRB is not completed for execution. + @retval Others Some erros happen when executing this request. + +**/ +EFI_STATUS +SdPeimCheckTrbResult ( + IN UINTN Bar, + IN SD_TRB *Trb + ) +{ + EFI_STATUS Status; + SD_COMMAND_PACKET *Packet; + UINT16 IntStatus; + UINT32 Response[4]; + UINT32 SdmaAddr; + UINT8 Index; + UINT8 SwReset; + UINT32 PioLength; + + SwReset = 0; + Packet = Trb->Packet; + // + // Check Trb execution result by reading Normal Interrupt Status register. + // + Status = SdPeimHcRwMmio ( + Bar + SD_HC_NOR_INT_STS, + TRUE, + sizeof (IntStatus), + &IntStatus + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Check Transfer Complete bit is set or not. + // + if ((IntStatus & BIT1) == BIT1) { + if ((IntStatus & BIT15) == BIT15) { + // + // Read Error Interrupt Status register to check if the error is + // Data Timeout Error. + // If yes, treat it as success as Transfer Complete has higher + // priority than Data Timeout Error. + // + Status = SdPeimHcRwMmio ( + Bar + SD_HC_ERR_INT_STS, + TRUE, + sizeof (IntStatus), + &IntStatus + ); + if (!EFI_ERROR (Status)) { + if ((IntStatus & BIT4) == BIT4) { + Status = EFI_SUCCESS; + } else { + Status = EFI_DEVICE_ERROR; + } + } + } + + goto Done; + } + + // + // Check if there is a error happened during cmd execution. + // If yes, then do error recovery procedure to follow SD Host Controller + // Simplified Spec 3.0 section 3.10.1. + // + if ((IntStatus & BIT15) == BIT15) { + Status = SdPeimHcRwMmio ( + Bar + SD_HC_ERR_INT_STS, + TRUE, + sizeof (IntStatus), + &IntStatus + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + if ((IntStatus & 0x0F) != 0) { + SwReset |= BIT1; + } + + if ((IntStatus & 0xF0) != 0) { + SwReset |= BIT2; + } + + Status = SdPeimHcRwMmio ( + Bar + SD_HC_SW_RST, + FALSE, + sizeof (SwReset), + &SwReset + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = SdPeimHcWaitMmioSet ( + Bar + SD_HC_SW_RST, + sizeof (SwReset), + 0xFF, + 0, + SD_TIMEOUT + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = EFI_DEVICE_ERROR; + goto Done; + } + + // + // Check if DMA interrupt is signalled for the SDMA transfer. + // + if ((Trb->Mode == SdSdmaMode) && ((IntStatus & BIT3) == BIT3)) { + // + // Clear DMA interrupt bit. + // + IntStatus = BIT3; + Status = SdPeimHcRwMmio ( + Bar + SD_HC_NOR_INT_STS, + FALSE, + sizeof (IntStatus), + &IntStatus + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Update SDMA Address register. + // + SdmaAddr = SD_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->DataPhy, SD_SDMA_BOUNDARY); + Status = SdPeimHcRwMmio ( + Bar + SD_HC_SDMA_ADDR, + FALSE, + sizeof (UINT32), + &SdmaAddr + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Trb->DataPhy = (UINT32)(UINTN)SdmaAddr; + } + + if ((Packet->SdCmdBlk->CommandType != SdCommandTypeAdtc) && + (Packet->SdCmdBlk->ResponseType != SdResponseTypeR1b) && + (Packet->SdCmdBlk->ResponseType != SdResponseTypeR5b)) + { + if ((IntStatus & BIT0) == BIT0) { + Status = EFI_SUCCESS; + goto Done; + } + } + + if (Packet->SdCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK) { + // + // When performing tuning procedure (Execute Tuning is set to 1) through PIO mode, + // wait Buffer Read Ready bit of Normal Interrupt Status Register to be 1. + // Refer to SD Host Controller Simplified Specification 3.0 figure 2-29 for details. + // + if ((IntStatus & BIT5) == BIT5) { + // + // Clear Buffer Read Ready interrupt at first. + // + IntStatus = BIT5; + SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus); + // + // Read data out from Buffer Port register + // + for (PioLength = 0; PioLength < Trb->DataLen; PioLength += 4) { + SdPeimHcRwMmio (Bar + SD_HC_BUF_DAT_PORT, TRUE, 4, (UINT8 *)Trb->Data + PioLength); + } + + Status = EFI_SUCCESS; + goto Done; + } + } + + Status = EFI_NOT_READY; +Done: + // + // Get response data when the cmd is executed successfully. + // + if (!EFI_ERROR (Status)) { + if (Packet->SdCmdBlk->CommandType != SdCommandTypeBc) { + for (Index = 0; Index < 4; Index++) { + Status = SdPeimHcRwMmio ( + Bar + SD_HC_RESPONSE + Index * 4, + TRUE, + sizeof (UINT32), + &Response[Index] + ); + if (EFI_ERROR (Status)) { + SdPeimHcLedOnOff (Bar, FALSE); + return Status; + } + } + + CopyMem (Packet->SdStatusBlk, Response, sizeof (Response)); + } + } + + if (Status != EFI_NOT_READY) { + SdPeimHcLedOnOff (Bar, FALSE); + } + + return Status; +} + +/** + Wait for the TRB execution result. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[in] Trb The pointer to the SD_TRB instance. + + @retval EFI_SUCCESS The TRB is executed successfully. + @retval Others Some erros happen when executing this request. + +**/ +EFI_STATUS +SdPeimWaitTrbResult ( + IN UINTN Bar, + IN SD_TRB *Trb + ) +{ + EFI_STATUS Status; + SD_COMMAND_PACKET *Packet; + UINT64 Timeout; + BOOLEAN InfiniteWait; + + Packet = Trb->Packet; + // + // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register + // + Timeout = Packet->Timeout; + if (Timeout == 0) { + InfiniteWait = TRUE; + } else { + InfiniteWait = FALSE; + } + + while (InfiniteWait || (Timeout > 0)) { + // + // Check Trb execution result by reading Normal Interrupt Status register. + // + Status = SdPeimCheckTrbResult (Bar, Trb); + if (Status != EFI_NOT_READY) { + return Status; + } + + // + // Stall for 1 microsecond. + // + MicroSecondDelay (1); + + Timeout--; + } + + return EFI_TIMEOUT; +} + +/** + Sends SD command to an SD card that is attached to the SD controller. + + If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned. + + If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned. + + If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER + is returned. + + If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL, + EFI_INVALID_PARAMETER is returned. + + @param[in] Slot The slot number of the Sd card to send the command to. + @param[in,out] Packet A pointer to the SD command data structure. + + @retval EFI_SUCCESS The SD Command Packet was sent by the host. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD + command Packet. + @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid. + @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and + OutDataBuffer are NULL. + @retval EFI_NO_MEDIA SD Device not present in the Slot. + @retval EFI_UNSUPPORTED The command described by the SD Command Packet is not + supported by the host controller. + @retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the + limit supported by SD card ( i.e. if the number of bytes + exceed the Last LBA). + +**/ +EFI_STATUS +EFIAPI +SdPeimExecCmd ( + IN SD_PEIM_HC_SLOT *Slot, + IN OUT SD_COMMAND_PACKET *Packet + ) +{ + EFI_STATUS Status; + SD_TRB *Trb; + + if (Packet == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((Packet->SdCmdBlk == NULL) || (Packet->SdStatusBlk == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) { + return EFI_INVALID_PARAMETER; + } + + if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) { + return EFI_INVALID_PARAMETER; + } + + Trb = SdPeimCreateTrb (Slot, Packet); + if (Trb == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = SdPeimWaitTrbEnv (Slot->SdHcBase, Trb); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = SdPeimExecTrb (Slot->SdHcBase, Trb); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = SdPeimWaitTrbResult (Slot->SdHcBase, Trb); + if (EFI_ERROR (Status)) { + goto Done; + } + +Done: + SdPeimFreeTrb (Trb); + + return Status; +} + +/** + Send command GO_IDLE_STATE to the device to make it go to Idle State. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The SD device is reset correctly. + @retval Others The device reset fails. + +**/ +EFI_STATUS +SdPeimReset ( + IN SD_PEIM_HC_SLOT *Slot + ) +{ + SD_COMMAND_BLOCK SdCmdBlk; + SD_STATUS_BLOCK SdStatusBlk; + SD_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk)); + ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdCmdBlk = &SdCmdBlk; + Packet.SdStatusBlk = &SdStatusBlk; + Packet.Timeout = SD_TIMEOUT; + + SdCmdBlk.CommandIndex = SD_GO_IDLE_STATE; + SdCmdBlk.CommandType = SdCommandTypeBc; + SdCmdBlk.ResponseType = 0; + SdCmdBlk.CommandArgument = 0; + + Status = SdPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Send command SEND_IF_COND to the device to inquiry the SD Memory Card interface + condition. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] SupplyVoltage The supplied voltage by the host. + @param[in] CheckPattern The check pattern to be sent to the device. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimVoltageCheck ( + IN SD_PEIM_HC_SLOT *Slot, + IN UINT8 SupplyVoltage, + IN UINT8 CheckPattern + ) +{ + SD_COMMAND_BLOCK SdCmdBlk; + SD_STATUS_BLOCK SdStatusBlk; + SD_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk)); + ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdCmdBlk = &SdCmdBlk; + Packet.SdStatusBlk = &SdStatusBlk; + Packet.Timeout = SD_TIMEOUT; + + SdCmdBlk.CommandIndex = SD_SEND_IF_COND; + SdCmdBlk.CommandType = SdCommandTypeBcr; + SdCmdBlk.ResponseType = SdResponseTypeR7; + SdCmdBlk.CommandArgument = (SupplyVoltage << 8) | CheckPattern; + + Status = SdPeimExecCmd (Slot, &Packet); + if (!EFI_ERROR (Status)) { + if (SdStatusBlk.Resp0 != SdCmdBlk.CommandArgument) { + return EFI_DEVICE_ERROR; + } + } + + return Status; +} + +/** + Send command SDIO_SEND_OP_COND to the device to see whether it is SDIO device. + + Refer to SDIO Simplified Spec 3 Section 3.2 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] VoltageWindow The supply voltage window. + @param[in] S18r The boolean to show if it should switch to 1.8v. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdioSendOpCond ( + IN SD_PEIM_HC_SLOT *Slot, + IN UINT32 VoltageWindow, + IN BOOLEAN S18r + ) +{ + SD_COMMAND_BLOCK SdCmdBlk; + SD_STATUS_BLOCK SdStatusBlk; + SD_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT32 Switch; + + ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk)); + ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdCmdBlk = &SdCmdBlk; + Packet.SdStatusBlk = &SdStatusBlk; + Packet.Timeout = SD_TIMEOUT; + + SdCmdBlk.CommandIndex = SDIO_SEND_OP_COND; + SdCmdBlk.CommandType = SdCommandTypeBcr; + SdCmdBlk.ResponseType = SdResponseTypeR4; + + Switch = S18r ? BIT24 : 0; + + SdCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch; + + Status = SdPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Send command SD_SEND_OP_COND to the device to see whether it is SDIO device. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address of addressed device. + @param[in] VoltageWindow The supply voltage window. + @param[in] S18r The boolean to show if it should switch to 1.8v. + @param[in] Xpc The boolean to show if it should provide 0.36w power control. + @param[in] Hcs The boolean to show if it support host capacity info. + @param[out] Ocr The buffer to store returned OCR register value. + + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimSendOpCond ( + IN SD_PEIM_HC_SLOT *Slot, + IN UINT16 Rca, + IN UINT32 VoltageWindow, + IN BOOLEAN S18r, + IN BOOLEAN Xpc, + IN BOOLEAN Hcs, + OUT UINT32 *Ocr + ) +{ + SD_COMMAND_BLOCK SdCmdBlk; + SD_STATUS_BLOCK SdStatusBlk; + SD_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT32 Switch; + UINT32 MaxPower; + UINT32 HostCapacity; + + ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk)); + ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdCmdBlk = &SdCmdBlk; + Packet.SdStatusBlk = &SdStatusBlk; + Packet.Timeout = SD_TIMEOUT; + + SdCmdBlk.CommandIndex = SD_APP_CMD; + SdCmdBlk.CommandType = SdCommandTypeAc; + SdCmdBlk.ResponseType = SdResponseTypeR1; + SdCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = SdPeimExecCmd (Slot, &Packet); + if (EFI_ERROR (Status)) { + return Status; + } + + SdCmdBlk.CommandIndex = SD_SEND_OP_COND; + SdCmdBlk.CommandType = SdCommandTypeBcr; + SdCmdBlk.ResponseType = SdResponseTypeR3; + + Switch = S18r ? BIT24 : 0; + MaxPower = Xpc ? BIT28 : 0; + HostCapacity = Hcs ? BIT30 : 0; + SdCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch | MaxPower | HostCapacity; + + Status = SdPeimExecCmd (Slot, &Packet); + if (!EFI_ERROR (Status)) { + // + // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12. + // + *Ocr = SdStatusBlk.Resp0; + } + + return Status; +} + +/** + Broadcast command ALL_SEND_CID to the bus to ask all the SD devices to send the + data of their CID registers. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimAllSendCid ( + IN SD_PEIM_HC_SLOT *Slot + ) +{ + SD_COMMAND_BLOCK SdCmdBlk; + SD_STATUS_BLOCK SdStatusBlk; + SD_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk)); + ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdCmdBlk = &SdCmdBlk; + Packet.SdStatusBlk = &SdStatusBlk; + Packet.Timeout = SD_TIMEOUT; + + SdCmdBlk.CommandIndex = SD_ALL_SEND_CID; + SdCmdBlk.CommandType = SdCommandTypeBcr; + SdCmdBlk.ResponseType = SdResponseTypeR2; + SdCmdBlk.CommandArgument = 0; + + Status = SdPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Send command SET_RELATIVE_ADDR to the SD device to assign a Relative device + Address (RCA). + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[out] Rca The relative device address to be assigned. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimSetRca ( + IN SD_PEIM_HC_SLOT *Slot, + OUT UINT16 *Rca + ) +{ + SD_COMMAND_BLOCK SdCmdBlk; + SD_STATUS_BLOCK SdStatusBlk; + SD_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk)); + ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdCmdBlk = &SdCmdBlk; + Packet.SdStatusBlk = &SdStatusBlk; + Packet.Timeout = SD_TIMEOUT; + + SdCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR; + SdCmdBlk.CommandType = SdCommandTypeBcr; + SdCmdBlk.ResponseType = SdResponseTypeR6; + + Status = SdPeimExecCmd (Slot, &Packet); + if (!EFI_ERROR (Status)) { + *Rca = (UINT16)(SdStatusBlk.Resp0 >> 16); + } + + return Status; +} + +/** + Send command SEND_CSD to the SD device to get the data of the CSD register. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address of selected device. + @param[out] Csd The buffer to store the content of the CSD register. + Note the caller should ignore the lowest byte of this + buffer as the content of this byte is meaningless even + if the operation succeeds. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimGetCsd ( + IN SD_PEIM_HC_SLOT *Slot, + IN UINT16 Rca, + OUT SD_CSD *Csd + ) +{ + SD_COMMAND_BLOCK SdCmdBlk; + SD_STATUS_BLOCK SdStatusBlk; + SD_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk)); + ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdCmdBlk = &SdCmdBlk; + Packet.SdStatusBlk = &SdStatusBlk; + Packet.Timeout = SD_TIMEOUT; + + SdCmdBlk.CommandIndex = SD_SEND_CSD; + SdCmdBlk.CommandType = SdCommandTypeAc; + SdCmdBlk.ResponseType = SdResponseTypeR2; + SdCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = SdPeimExecCmd (Slot, &Packet); + if (!EFI_ERROR (Status)) { + // + // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12. + // + CopyMem (((UINT8 *)Csd) + 1, &SdStatusBlk.Resp0, sizeof (SD_CSD) - 1); + } + + return Status; +} + +/** + Send command SELECT_DESELECT_CARD to the SD device to select/deselect it. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address of selected device. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimSelect ( + IN SD_PEIM_HC_SLOT *Slot, + IN UINT16 Rca + ) +{ + SD_COMMAND_BLOCK SdCmdBlk; + SD_STATUS_BLOCK SdStatusBlk; + SD_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk)); + ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdCmdBlk = &SdCmdBlk; + Packet.SdStatusBlk = &SdStatusBlk; + Packet.Timeout = SD_TIMEOUT; + + SdCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD; + SdCmdBlk.CommandType = SdCommandTypeAc; + SdCmdBlk.ResponseType = SdResponseTypeR1b; + SdCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = SdPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Send command VOLTAGE_SWITCH to the SD device to switch the voltage of the device. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimVoltageSwitch ( + IN SD_PEIM_HC_SLOT *Slot + ) +{ + SD_COMMAND_BLOCK SdCmdBlk; + SD_STATUS_BLOCK SdStatusBlk; + SD_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk)); + ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdCmdBlk = &SdCmdBlk; + Packet.SdStatusBlk = &SdStatusBlk; + Packet.Timeout = SD_TIMEOUT; + + SdCmdBlk.CommandIndex = SD_VOLTAGE_SWITCH; + SdCmdBlk.CommandType = SdCommandTypeAc; + SdCmdBlk.ResponseType = SdResponseTypeR1; + SdCmdBlk.CommandArgument = 0; + + Status = SdPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Send command SET_BUS_WIDTH to the SD device to set the bus width. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address of addressed device. + @param[in] BusWidth The bus width to be set, it could be 1 or 4. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimSetBusWidth ( + IN SD_PEIM_HC_SLOT *Slot, + IN UINT16 Rca, + IN UINT8 BusWidth + ) +{ + SD_COMMAND_BLOCK SdCmdBlk; + SD_STATUS_BLOCK SdStatusBlk; + SD_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT8 Value; + + ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk)); + ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdCmdBlk = &SdCmdBlk; + Packet.SdStatusBlk = &SdStatusBlk; + Packet.Timeout = SD_TIMEOUT; + + SdCmdBlk.CommandIndex = SD_APP_CMD; + SdCmdBlk.CommandType = SdCommandTypeAc; + SdCmdBlk.ResponseType = SdResponseTypeR1; + SdCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = SdPeimExecCmd (Slot, &Packet); + if (EFI_ERROR (Status)) { + return Status; + } + + SdCmdBlk.CommandIndex = SD_SET_BUS_WIDTH; + SdCmdBlk.CommandType = SdCommandTypeAc; + SdCmdBlk.ResponseType = SdResponseTypeR1; + + if (BusWidth == 1) { + Value = 0; + } else if (BusWidth == 4) { + Value = 2; + } else { + return EFI_INVALID_PARAMETER; + } + + SdCmdBlk.CommandArgument = Value & 0x3; + + Status = SdPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Send command SWITCH_FUNC to the SD device to check switchable function or switch card function. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] AccessMode The value for access mode group. + @param[in] CommandSystem The value for command set group. + @param[in] DriveStrength The value for drive length group. + @param[in] PowerLimit The value for power limit group. + @param[in] Mode Switch or check function. + @param[out] SwitchResp The return switch function status. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimSwitch ( + IN SD_PEIM_HC_SLOT *Slot, + IN UINT8 AccessMode, + IN UINT8 CommandSystem, + IN UINT8 DriveStrength, + IN UINT8 PowerLimit, + IN BOOLEAN Mode, + OUT UINT8 *SwitchResp + ) +{ + SD_COMMAND_BLOCK SdCmdBlk; + SD_STATUS_BLOCK SdStatusBlk; + SD_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT32 ModeValue; + + ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk)); + ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdCmdBlk = &SdCmdBlk; + Packet.SdStatusBlk = &SdStatusBlk; + Packet.Timeout = SD_TIMEOUT; + + SdCmdBlk.CommandIndex = SD_SWITCH_FUNC; + SdCmdBlk.CommandType = SdCommandTypeAdtc; + SdCmdBlk.ResponseType = SdResponseTypeR1; + + ModeValue = Mode ? BIT31 : 0; + SdCmdBlk.CommandArgument = (AccessMode & 0xF) | ((PowerLimit & 0xF) << 4) | \ + ((DriveStrength & 0xF) << 8) | ((DriveStrength & 0xF) << 12) | \ + ModeValue; + Packet.InDataBuffer = SwitchResp; + Packet.InTransferLength = 64; + + Status = SdPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Send command SEND_STATUS to the addressed SD device to get its status register. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address of addressed device. + @param[out] DevStatus The returned device status. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimSendStatus ( + IN SD_PEIM_HC_SLOT *Slot, + IN UINT16 Rca, + OUT UINT32 *DevStatus + ) +{ + SD_COMMAND_BLOCK SdCmdBlk; + SD_STATUS_BLOCK SdStatusBlk; + SD_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk)); + ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdCmdBlk = &SdCmdBlk; + Packet.SdStatusBlk = &SdStatusBlk; + Packet.Timeout = SD_TIMEOUT; + + SdCmdBlk.CommandIndex = SD_SEND_STATUS; + SdCmdBlk.CommandType = SdCommandTypeAc; + SdCmdBlk.ResponseType = SdResponseTypeR1; + SdCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = SdPeimExecCmd (Slot, &Packet); + if (!EFI_ERROR (Status)) { + *DevStatus = SdStatusBlk.Resp0; + } + + return Status; +} + +/** + Send command READ_SINGLE_BLOCK/WRITE_SINGLE_BLOCK to the addressed SD device + to read/write the specified number of blocks. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Lba The logical block address of starting access. + @param[in] BlockSize The block size of specified SD device partition. + @param[in] Buffer The pointer to the transfer buffer. + @param[in] BufferSize The size of transfer buffer. + @param[in] IsRead Boolean to show the operation direction. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimRwSingleBlock ( + IN SD_PEIM_HC_SLOT *Slot, + IN EFI_LBA Lba, + IN UINT32 BlockSize, + IN VOID *Buffer, + IN UINTN BufferSize, + IN BOOLEAN IsRead + ) +{ + SD_COMMAND_BLOCK SdCmdBlk; + SD_STATUS_BLOCK SdStatusBlk; + SD_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk)); + ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdCmdBlk = &SdCmdBlk; + Packet.SdStatusBlk = &SdStatusBlk; + // + // Calculate timeout value through the below formula. + // Timeout = (transfer size) / (2MB/s). + // Taking 2MB/s as divisor is because it's the lowest + // transfer speed of class 2. + // + Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000; + + if (IsRead) { + Packet.InDataBuffer = Buffer; + Packet.InTransferLength = (UINT32)BufferSize; + + SdCmdBlk.CommandIndex = SD_READ_SINGLE_BLOCK; + SdCmdBlk.CommandType = SdCommandTypeAdtc; + SdCmdBlk.ResponseType = SdResponseTypeR1; + } else { + Packet.OutDataBuffer = Buffer; + Packet.OutTransferLength = (UINT32)BufferSize; + + SdCmdBlk.CommandIndex = SD_WRITE_SINGLE_BLOCK; + SdCmdBlk.CommandType = SdCommandTypeAdtc; + SdCmdBlk.ResponseType = SdResponseTypeR1; + } + + if (Slot->SectorAddressing) { + SdCmdBlk.CommandArgument = (UINT32)Lba; + } else { + SdCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, BlockSize); + } + + Status = SdPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed SD device + to read/write the specified number of blocks. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Lba The logical block address of starting access. + @param[in] BlockSize The block size of specified SD device partition. + @param[in] Buffer The pointer to the transfer buffer. + @param[in] BufferSize The size of transfer buffer. + @param[in] IsRead Boolean to show the operation direction. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimRwMultiBlocks ( + IN SD_PEIM_HC_SLOT *Slot, + IN EFI_LBA Lba, + IN UINT32 BlockSize, + IN VOID *Buffer, + IN UINTN BufferSize, + IN BOOLEAN IsRead + ) +{ + SD_COMMAND_BLOCK SdCmdBlk; + SD_STATUS_BLOCK SdStatusBlk; + SD_COMMAND_PACKET Packet; + EFI_STATUS Status; + + ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk)); + ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdCmdBlk = &SdCmdBlk; + Packet.SdStatusBlk = &SdStatusBlk; + // + // Calculate timeout value through the below formula. + // Timeout = (transfer size) / (2MB/s). + // Taking 2MB/s as divisor is because it's the lowest + // transfer speed of class 2. + // + Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000; + + if (IsRead) { + Packet.InDataBuffer = Buffer; + Packet.InTransferLength = (UINT32)BufferSize; + + SdCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK; + SdCmdBlk.CommandType = SdCommandTypeAdtc; + SdCmdBlk.ResponseType = SdResponseTypeR1; + } else { + Packet.OutDataBuffer = Buffer; + Packet.OutTransferLength = (UINT32)BufferSize; + + SdCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK; + SdCmdBlk.CommandType = SdCommandTypeAdtc; + SdCmdBlk.ResponseType = SdResponseTypeR1; + } + + if (Slot->SectorAddressing) { + SdCmdBlk.CommandArgument = (UINT32)Lba; + } else { + SdCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, BlockSize); + } + + Status = SdPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Send command SEND_TUNING_BLOCK to the SD device for SDR104/SDR50 optimal sampling point + detection. + + It may be sent up to 40 times until the host finishes the tuning procedure. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimSendTuningBlk ( + IN SD_PEIM_HC_SLOT *Slot + ) +{ + SD_COMMAND_BLOCK SdCmdBlk; + SD_STATUS_BLOCK SdStatusBlk; + SD_COMMAND_PACKET Packet; + EFI_STATUS Status; + UINT8 TuningBlock[64]; + + ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk)); + ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + + Packet.SdCmdBlk = &SdCmdBlk; + Packet.SdStatusBlk = &SdStatusBlk; + Packet.Timeout = SD_TIMEOUT; + + SdCmdBlk.CommandIndex = SD_SEND_TUNING_BLOCK; + SdCmdBlk.CommandType = SdCommandTypeAdtc; + SdCmdBlk.ResponseType = SdResponseTypeR1; + SdCmdBlk.CommandArgument = 0; + + Packet.InDataBuffer = TuningBlock; + Packet.InTransferLength = sizeof (TuningBlock); + + Status = SdPeimExecCmd (Slot, &Packet); + + return Status; +} + +/** + Tuning the sampling point of SDR104 or SDR50 bus speed mode. + + Command SD_SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the + tuning procedure. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and SD Host Controller + Simplified Spec 3.0 Figure 2-29 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimTuningClock ( + IN SD_PEIM_HC_SLOT *Slot + ) +{ + EFI_STATUS Status; + UINT8 HostCtrl2; + UINT8 Retry; + + // + // Notify the host that the sampling clock tuning procedure starts. + // + HostCtrl2 = BIT6; + Status = SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Ask the device to send a sequence of tuning blocks till the tuning procedure is done. + // + Retry = 0; + do { + Status = SdPeimSendTuningBlk (Slot); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((HostCtrl2 & (BIT6 | BIT7)) == 0) { + break; + } + + if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) { + return EFI_SUCCESS; + } + } while (++Retry < 40); + + DEBUG ((DEBUG_ERROR, "SdPeimTuningClock: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2)); + // + // Abort the tuning procedure and reset the tuning circuit. + // + HostCtrl2 = (UINT8) ~(BIT6 | BIT7); + Status = SdPeimHcAndMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_DEVICE_ERROR; +} + +/** + Switch the bus width to specified width. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and + SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address to be assigned. + @param[in] BusWidth The bus width to be set, it could be 4 or 8. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimSwitchBusWidth ( + IN SD_PEIM_HC_SLOT *Slot, + IN UINT16 Rca, + IN UINT8 BusWidth + ) +{ + EFI_STATUS Status; + UINT32 DevStatus; + + Status = SdPeimSetBusWidth (Slot, Rca, BusWidth); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = SdPeimSendStatus (Slot, Rca, &DevStatus); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check the switch operation is really successful or not. + // + if ((DevStatus >> 16) != 0) { + return EFI_DEVICE_ERROR; + } + + Status = SdPeimHcSetBusWidth (Slot->SdHcBase, BusWidth); + + return Status; +} + +/** + Switch the high speed timing according to request. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and + SD Host Controller Simplified Spec 3.0 section Figure 2-29 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Rca The relative device address to be assigned. + @param[in] S18a The boolean to show if it's a UHS-I SD card. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimSetBusMode ( + IN SD_PEIM_HC_SLOT *Slot, + IN UINT16 Rca, + IN BOOLEAN S18a + ) +{ + EFI_STATUS Status; + SD_HC_SLOT_CAP Capability; + UINT32 ClockFreq; + UINT8 BusWidth; + UINT8 AccessMode; + UINT8 HostCtrl1; + UINT8 HostCtrl2; + UINT8 SwitchResp[64]; + + Status = SdPeimGetCsd (Slot, Rca, &Slot->Csd); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdPeimSetBusMode: SdPeimGetCsd fails with %r\n", Status)); + return Status; + } + + Status = SdPeimHcGetCapability (Slot->SdHcBase, &Capability); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = SdPeimSelect (Slot, Rca); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdPeimSetBusMode: SdPeimSelect fails with %r\n", Status)); + return Status; + } + + BusWidth = 4; + Status = SdPeimSwitchBusWidth (Slot, Rca, BusWidth); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdPeimSetBusMode: SdPeimSwitchBusWidth fails with %r\n", Status)); + return Status; + } + + // + // Get the supported bus speed from SWITCH cmd return data group #1. + // + ZeroMem (SwitchResp, sizeof (SwitchResp)); + Status = SdPeimSwitch (Slot, 0xF, 0xF, 0xF, 0xF, FALSE, SwitchResp); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Calculate supported bus speed/bus width/clock frequency by host and device capability. + // + ClockFreq = 0; + if (S18a && (Capability.Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) { + ClockFreq = 208; + AccessMode = 3; + } else if (S18a && (Capability.Sdr50 != 0) && ((SwitchResp[13] & BIT2) != 0)) { + ClockFreq = 100; + AccessMode = 2; + } else if (S18a && (Capability.Ddr50 != 0) && ((SwitchResp[13] & BIT4) != 0)) { + ClockFreq = 50; + AccessMode = 4; + } else if ((SwitchResp[13] & BIT1) != 0) { + ClockFreq = 50; + AccessMode = 1; + } else { + ClockFreq = 25; + AccessMode = 0; + } + + DEBUG ((DEBUG_INFO, "SdPeimSetBusMode: AccessMode %d ClockFreq %d BusWidth %d\n", AccessMode, ClockFreq, BusWidth)); + + Status = SdPeimSwitch (Slot, AccessMode, 0xF, 0xF, 0xF, TRUE, SwitchResp); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdPeimSetBusMode: SdPeimSwitch fails with %r\n", Status)); + return Status; + } + + if ((SwitchResp[16] & 0xF) != AccessMode) { + DEBUG ((DEBUG_ERROR, "SdPeimSetBusMode: SdPeimSwitch to AccessMode %d ClockFreq %d BusWidth %d fails! The Switch response is 0x%1x\n", AccessMode, ClockFreq, BusWidth, SwitchResp[16] & 0xF)); + return EFI_DEVICE_ERROR; + } + + // + // Set to High Speed timing + // + if (AccessMode == 1) { + HostCtrl1 = BIT2; + Status = SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1); + if (EFI_ERROR (Status)) { + return Status; + } + } + + HostCtrl2 = (UINT8) ~0x7; + Status = SdPeimHcAndMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + HostCtrl2 = AccessMode; + Status = SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = SdPeimHcClockSupply (Slot->SdHcBase, ClockFreq * 1000); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdPeimSetBusMode: SdPeimHcClockSupply %r\n", Status)); + return Status; + } + + if ((AccessMode == 3) || ((AccessMode == 2) && (Capability.TuningSDR50 != 0))) { + Status = SdPeimTuningClock (Slot); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdPeimSetBusMode: SdPeimTuningClock fails with %r\n", Status)); + return Status; + } + } + + DEBUG ((DEBUG_INFO, "SdPeimSetBusMode: SdPeimSetBusMode %r\n", Status)); + + return Status; +} + +/** + Execute SD device identification procedure. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 3.6 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + + @retval EFI_SUCCESS There is a SD card. + @retval Others There is not a SD card. + +**/ +EFI_STATUS +SdPeimIdentification ( + IN SD_PEIM_HC_SLOT *Slot + ) +{ + EFI_STATUS Status; + UINT32 Ocr; + UINT16 Rca; + BOOLEAN Xpc; + BOOLEAN S18r; + UINT64 MaxCurrent; + UINT64 Current; + UINT16 ControllerVer; + UINT8 PowerCtrl; + UINT32 PresentState; + UINT8 HostCtrl2; + SD_HC_SLOT_CAP Capability; + UINTN Retry; + + // + // 1. Send Cmd0 to the device + // + Status = SdPeimReset (Slot); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdPeimIdentification: Executing Cmd0 fails with %r\n", Status)); + return Status; + } + + // + // 2. Send Cmd8 to the device + // + Status = SdPeimVoltageCheck (Slot, 0x1, 0xFF); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdPeimIdentification: Executing Cmd8 fails with %r\n", Status)); + return Status; + } + + // + // 3. Send SDIO Cmd5 to the device to the SDIO device OCR register. + // + Status = SdioSendOpCond (Slot, 0, FALSE); + if (!EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdPeimIdentification: Found SDIO device, ignore it as we don't support\n")); + return EFI_DEVICE_ERROR; + } + + // + // 4. Send Acmd41 with voltage window 0 to the device + // + Status = SdPeimSendOpCond (Slot, 0, 0, FALSE, FALSE, FALSE, &Ocr); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdPeimIdentification: Executing SdPeimSendOpCond fails with %r\n", Status)); + return EFI_DEVICE_ERROR; + } + + Status = SdPeimHcGetCapability (Slot->SdHcBase, &Capability); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_MAX_CURRENT_CAP, TRUE, sizeof (Current), &Current); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Capability.Voltage33 != 0) { + // + // Support 3.3V + // + MaxCurrent = ((UINT32)Current & 0xFF) * 4; + } else if (Capability.Voltage30 != 0) { + // + // Support 3.0V + // + MaxCurrent = (((UINT32)Current >> 8) & 0xFF) * 4; + } else if (Capability.Voltage18 != 0) { + // + // Support 1.8V + // + MaxCurrent = (((UINT32)Current >> 16) & 0xFF) * 4; + } else { + ASSERT (FALSE); + return EFI_DEVICE_ERROR; + } + + if (MaxCurrent >= 150) { + Xpc = TRUE; + } else { + Xpc = FALSE; + } + + Status = SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((ControllerVer & 0xFF) == 2) { + S18r = TRUE; + } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) { + S18r = FALSE; + } else { + ASSERT (FALSE); + return EFI_UNSUPPORTED; + } + + // + // 5. Repeatly send Acmd41 with supply voltage window to the device. + // Note here we only support the cards complied with SD physical + // layer simplified spec version 2.0 and version 3.0 and above. + // + Ocr = 0; + Retry = 0; + do { + Status = SdPeimSendOpCond (Slot, 0, Ocr, S18r, Xpc, TRUE, &Ocr); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdPeimIdentification: SdPeimSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n", Status, Ocr, S18r, Xpc)); + return EFI_DEVICE_ERROR; + } + + if (Retry++ == 100) { + DEBUG ((DEBUG_ERROR, "SdPeimIdentification: SdPeimSendOpCond fails too many times\n")); + return EFI_DEVICE_ERROR; + } + + MicroSecondDelay (10 * 1000); + } while ((Ocr & BIT31) == 0); + + // + // 6. If the S18a bit is set and the Host Controller supports 1.8V signaling + // (One of support bits is set to 1: SDR50, SDR104 or DDR50 in the + // Capabilities register), switch its voltage to 1.8V. + // + if (((Capability.Sdr50 != 0) || + (Capability.Sdr104 != 0) || + (Capability.Ddr50 != 0)) && + ((Ocr & BIT24) != 0)) + { + Status = SdPeimVoltageSwitch (Slot); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdPeimIdentification: Executing SdPeimVoltageSwitch fails with %r\n", Status)); + Status = EFI_DEVICE_ERROR; + goto Error; + } else { + Status = SdPeimHcStopClock (Slot->SdHcBase); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Error; + } + + SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState); + if (((PresentState >> 20) & 0xF) != 0) { + DEBUG ((DEBUG_ERROR, "SdPeimIdentification: SwitchVoltage fails with PresentState = 0x%x\n", PresentState)); + Status = EFI_DEVICE_ERROR; + goto Error; + } + + HostCtrl2 = BIT3; + SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2); + + MicroSecondDelay (5000); + + SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2); + if ((HostCtrl2 & BIT3) == 0) { + DEBUG ((DEBUG_ERROR, "SdPeimIdentification: SwitchVoltage fails with HostCtrl2 = 0x%x\n", HostCtrl2)); + Status = EFI_DEVICE_ERROR; + goto Error; + } + + SdPeimHcInitClockFreq (Slot->SdHcBase); + + MicroSecondDelay (1000); + + SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState); + if (((PresentState >> 20) & 0xF) != 0xF) { + DEBUG ((DEBUG_ERROR, "SdPeimIdentification: SwitchVoltage fails with PresentState = 0x%x, It should be 0xF\n", PresentState)); + Status = EFI_DEVICE_ERROR; + goto Error; + } + } + + DEBUG ((DEBUG_INFO, "SdPeimIdentification: Switch to 1.8v signal voltage success\n")); + } + + Status = SdPeimAllSendCid (Slot); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdPeimIdentification: Executing SdPeimAllSendCid fails with %r\n", Status)); + return Status; + } + + Status = SdPeimSetRca (Slot, &Rca); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SdPeimIdentification: Executing SdPeimSetRca fails with %r\n", Status)); + return Status; + } + + // + // Enter Data Tranfer Mode. + // + DEBUG ((DEBUG_INFO, "Found a SD device at slot [%d]\n", Slot)); + + Status = SdPeimSetBusMode (Slot, Rca, ((Ocr & BIT24) != 0)); + + return Status; + +Error: + // + // Set SD Bus Power = 0 + // + PowerCtrl = (UINT8) ~BIT0; + Status = SdPeimHcAndMmio (Slot->SdHcBase + SD_HC_POWER_CTRL, sizeof (PowerCtrl), &PowerCtrl); + return EFI_DEVICE_ERROR; +} diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h index 5619e2e473..ceaecee419 100644 --- a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h +++ b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h @@ -1,349 +1,349 @@ -/** @file
-
- Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _SD_HCI_H_
-#define _SD_HCI_H_
-
-//
-// SD Host Controller MMIO Register Offset
-//
-#define SD_HC_SDMA_ADDR 0x00
-#define SD_HC_ARG2 0x00
-#define SD_HC_BLK_SIZE 0x04
-#define SD_HC_BLK_COUNT 0x06
-#define SD_HC_ARG1 0x08
-#define SD_HC_TRANS_MOD 0x0C
-#define SD_HC_COMMAND 0x0E
-#define SD_HC_RESPONSE 0x10
-#define SD_HC_BUF_DAT_PORT 0x20
-#define SD_HC_PRESENT_STATE 0x24
-#define SD_HC_HOST_CTRL1 0x28
-#define SD_HC_POWER_CTRL 0x29
-#define SD_HC_BLK_GAP_CTRL 0x2A
-#define SD_HC_WAKEUP_CTRL 0x2B
-#define SD_HC_CLOCK_CTRL 0x2C
-#define SD_HC_TIMEOUT_CTRL 0x2E
-#define SD_HC_SW_RST 0x2F
-#define SD_HC_NOR_INT_STS 0x30
-#define SD_HC_ERR_INT_STS 0x32
-#define SD_HC_NOR_INT_STS_EN 0x34
-#define SD_HC_ERR_INT_STS_EN 0x36
-#define SD_HC_NOR_INT_SIG_EN 0x38
-#define SD_HC_ERR_INT_SIG_EN 0x3A
-#define SD_HC_AUTO_CMD_ERR_STS 0x3C
-#define SD_HC_HOST_CTRL2 0x3E
-#define SD_HC_CAP 0x40
-#define SD_HC_MAX_CURRENT_CAP 0x48
-#define SD_HC_FORCE_EVT_AUTO_CMD 0x50
-#define SD_HC_FORCE_EVT_ERR_INT 0x52
-#define SD_HC_ADMA_ERR_STS 0x54
-#define SD_HC_ADMA_SYS_ADDR 0x58
-#define SD_HC_PRESET_VAL 0x60
-#define SD_HC_SHARED_BUS_CTRL 0xE0
-#define SD_HC_SLOT_INT_STS 0xFC
-#define SD_HC_CTRL_VER 0xFE
-
-//
-// The transfer modes supported by SD Host Controller
-// Simplified Spec 3.0 Table 1-2
-//
-typedef enum {
- SdNoData,
- SdPioMode,
- SdSdmaMode,
- SdAdmaMode
-} SD_HC_TRANSFER_MODE;
-
-//
-// The maximum data length of each descriptor line
-//
-#define ADMA_MAX_DATA_PER_LINE 0x10000
-#define SD_SDMA_BOUNDARY 512 * 1024
-#define SD_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1))
-
-typedef enum {
- SdCommandTypeBc, // Broadcast commands, no response
- SdCommandTypeBcr, // Broadcast commands with response
- SdCommandTypeAc, // Addressed(point-to-point) commands
- SdCommandTypeAdtc // Addressed(point-to-point) data transfer commands
-} SD_COMMAND_TYPE;
-
-typedef enum {
- SdResponseTypeR1,
- SdResponseTypeR1b,
- SdResponseTypeR2,
- SdResponseTypeR3,
- SdResponseTypeR4,
- SdResponseTypeR5,
- SdResponseTypeR5b,
- SdResponseTypeR6,
- SdResponseTypeR7
-} SD_RESPONSE_TYPE;
-
-typedef struct _SD_COMMAND_BLOCK {
- UINT16 CommandIndex;
- UINT32 CommandArgument;
- UINT32 CommandType; // One of the SD_COMMAND_TYPE values
- UINT32 ResponseType; // One of the SD_RESPONSE_TYPE values
-} SD_COMMAND_BLOCK;
-
-typedef struct _SD_STATUS_BLOCK {
- UINT32 Resp0;
- UINT32 Resp1;
- UINT32 Resp2;
- UINT32 Resp3;
-} SD_STATUS_BLOCK;
-
-typedef struct _SD_COMMAND_PACKET {
- UINT64 Timeout;
- SD_COMMAND_BLOCK *SdCmdBlk;
- SD_STATUS_BLOCK *SdStatusBlk;
- VOID *InDataBuffer;
- VOID *OutDataBuffer;
- UINT32 InTransferLength;
- UINT32 OutTransferLength;
-} SD_COMMAND_PACKET;
-
-#pragma pack(1)
-
-typedef struct {
- UINT32 Valid : 1;
- UINT32 End : 1;
- UINT32 Int : 1;
- UINT32 Reserved : 1;
- UINT32 Act : 2;
- UINT32 Reserved1 : 10;
- UINT32 Length : 16;
- UINT32 Address;
-} SD_HC_ADMA_DESC_LINE;
-
-typedef struct {
- UINT32 TimeoutFreq : 6; // bit 0:5
- UINT32 Reserved : 1; // bit 6
- UINT32 TimeoutUnit : 1; // bit 7
- UINT32 BaseClkFreq : 8; // bit 8:15
- UINT32 MaxBlkLen : 2; // bit 16:17
- UINT32 BusWidth8 : 1; // bit 18
- UINT32 Adma2 : 1; // bit 19
- UINT32 Reserved2 : 1; // bit 20
- UINT32 HighSpeed : 1; // bit 21
- UINT32 Sdma : 1; // bit 22
- UINT32 SuspRes : 1; // bit 23
- UINT32 Voltage33 : 1; // bit 24
- UINT32 Voltage30 : 1; // bit 25
- UINT32 Voltage18 : 1; // bit 26
- UINT32 Reserved3 : 1; // bit 27
- UINT32 SysBus64 : 1; // bit 28
- UINT32 AsyncInt : 1; // bit 29
- UINT32 SlotType : 2; // bit 30:31
- UINT32 Sdr50 : 1; // bit 32
- UINT32 Sdr104 : 1; // bit 33
- UINT32 Ddr50 : 1; // bit 34
- UINT32 Reserved4 : 1; // bit 35
- UINT32 DriverTypeA : 1; // bit 36
- UINT32 DriverTypeC : 1; // bit 37
- UINT32 DriverTypeD : 1; // bit 38
- UINT32 DriverType4 : 1; // bit 39
- UINT32 TimerCount : 4; // bit 40:43
- UINT32 Reserved5 : 1; // bit 44
- UINT32 TuningSDR50 : 1; // bit 45
- UINT32 RetuningMod : 2; // bit 46:47
- UINT32 ClkMultiplier : 8; // bit 48:55
- UINT32 Reserved6 : 7; // bit 56:62
- UINT32 Hs400 : 1; // bit 63
-} SD_HC_SLOT_CAP;
-
-#pragma pack()
-
-/**
- Software reset the specified SD host controller and enable all interrupts.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The software reset executes successfully.
- @retval Others The software reset fails.
-
-**/
-EFI_STATUS
-SdPeimHcReset (
- IN UINTN Bar
- );
-
-/**
- Set all interrupt status bits in Normal and Error Interrupt Status Enable
- register.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The operation executes successfully.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimHcEnableInterrupt (
- IN UINTN Bar
- );
-
-/**
- Get the capability data from the specified slot.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
- @param[out] Capability The buffer to store the capability data.
-
- @retval EFI_SUCCESS The operation executes successfully.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimHcGetCapability (
- IN UINTN Bar,
- OUT SD_HC_SLOT_CAP *Capability
- );
-
-/**
- Detect whether there is a SD card attached at the specified SD host controller
- slot.
-
- Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS There is a SD card attached.
- @retval EFI_NO_MEDIA There is not a SD card attached.
- @retval Others The detection fails.
-
-**/
-EFI_STATUS
-SdPeimHcCardDetect (
- IN UINTN Bar
- );
-
-/**
- Initial SD host controller with lowest clock frequency, max power and max timeout value
- at initialization.
-
- @param[in] Bar The mmio base address of the slot to be accessed.
-
- @retval EFI_SUCCESS The host controller is initialized successfully.
- @retval Others The host controller isn't initialized successfully.
-
-**/
-EFI_STATUS
-SdPeimHcInitHost (
- IN UINTN Bar
- );
-
-/**
- Send command SWITCH_FUNC to the SD device to check switchable function or switch card function.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
- @param[in] AccessMode The value for access mode group.
- @param[in] CommandSystem The value for command set group.
- @param[in] DriveStrength The value for drive length group.
- @param[in] PowerLimit The value for power limit group.
- @param[in] Mode Switch or check function.
- @param[out] SwitchResp The return switch function status.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimSwitch (
- IN SD_PEIM_HC_SLOT *Slot,
- IN UINT8 AccessMode,
- IN UINT8 CommandSystem,
- IN UINT8 DriveStrength,
- IN UINT8 PowerLimit,
- IN BOOLEAN Mode,
- OUT UINT8 *SwitchResp
- );
-
-/**
- Send command READ_SINGLE_BLOCK/WRITE_SINGLE_BLOCK to the addressed SD device
- to read/write the specified number of blocks.
-
- Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
-
- @param[in] Slot The slot number of the SD card to send the command to.
- @param[in] Lba The logical block address of starting access.
- @param[in] BlockSize The block size of specified SD device partition.
- @param[in] Buffer The pointer to the transfer buffer.
- @param[in] BufferSize The size of transfer buffer.
- @param[in] IsRead Boolean to show the operation direction.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimRwSingleBlock (
- IN SD_PEIM_HC_SLOT *Slot,
- IN EFI_LBA Lba,
- IN UINT32 BlockSize,
- IN VOID *Buffer,
- IN UINTN BufferSize,
- IN BOOLEAN IsRead
- );
-
-/**
- Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed SD device
- to read/write the specified number of blocks.
-
- Refer to SD Electrical Standard Spec 5.1 Section 6.10.4 for details.
-
- @param[in] Slot The slot number of the Sd card to send the command to.
- @param[in] Lba The logical block address of starting access.
- @param[in] BlockSize The block size of specified SD device partition.
- @param[in] Buffer The pointer to the transfer buffer.
- @param[in] BufferSize The size of transfer buffer.
- @param[in] IsRead Boolean to show the operation direction.
-
- @retval EFI_SUCCESS The operation is done correctly.
- @retval Others The operation fails.
-
-**/
-EFI_STATUS
-SdPeimRwMultiBlocks (
- IN SD_PEIM_HC_SLOT *Slot,
- IN EFI_LBA Lba,
- IN UINT32 BlockSize,
- IN VOID *Buffer,
- IN UINTN BufferSize,
- IN BOOLEAN IsRead
- );
-
-/**
- Execute SD device identification procedure.
-
- Refer to SD Electrical Standard Spec 5.1 Section 6.4 for details.
-
- @param[in] Slot The slot number of the Sd card to send the command to.
-
- @retval EFI_SUCCESS There is a SD card.
- @retval Others There is not a SD card.
-
-**/
-EFI_STATUS
-SdPeimIdentification (
- IN SD_PEIM_HC_SLOT *Slot
- );
-
-/**
- Free the resource used by the TRB.
-
- @param[in] Trb The pointer to the SD_TRB instance.
-
-**/
-VOID
-SdPeimFreeTrb (
- IN SD_TRB *Trb
- );
-
-#endif
+/** @file + + Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SD_HCI_H_ +#define _SD_HCI_H_ + +// +// SD Host Controller MMIO Register Offset +// +#define SD_HC_SDMA_ADDR 0x00 +#define SD_HC_ARG2 0x00 +#define SD_HC_BLK_SIZE 0x04 +#define SD_HC_BLK_COUNT 0x06 +#define SD_HC_ARG1 0x08 +#define SD_HC_TRANS_MOD 0x0C +#define SD_HC_COMMAND 0x0E +#define SD_HC_RESPONSE 0x10 +#define SD_HC_BUF_DAT_PORT 0x20 +#define SD_HC_PRESENT_STATE 0x24 +#define SD_HC_HOST_CTRL1 0x28 +#define SD_HC_POWER_CTRL 0x29 +#define SD_HC_BLK_GAP_CTRL 0x2A +#define SD_HC_WAKEUP_CTRL 0x2B +#define SD_HC_CLOCK_CTRL 0x2C +#define SD_HC_TIMEOUT_CTRL 0x2E +#define SD_HC_SW_RST 0x2F +#define SD_HC_NOR_INT_STS 0x30 +#define SD_HC_ERR_INT_STS 0x32 +#define SD_HC_NOR_INT_STS_EN 0x34 +#define SD_HC_ERR_INT_STS_EN 0x36 +#define SD_HC_NOR_INT_SIG_EN 0x38 +#define SD_HC_ERR_INT_SIG_EN 0x3A +#define SD_HC_AUTO_CMD_ERR_STS 0x3C +#define SD_HC_HOST_CTRL2 0x3E +#define SD_HC_CAP 0x40 +#define SD_HC_MAX_CURRENT_CAP 0x48 +#define SD_HC_FORCE_EVT_AUTO_CMD 0x50 +#define SD_HC_FORCE_EVT_ERR_INT 0x52 +#define SD_HC_ADMA_ERR_STS 0x54 +#define SD_HC_ADMA_SYS_ADDR 0x58 +#define SD_HC_PRESET_VAL 0x60 +#define SD_HC_SHARED_BUS_CTRL 0xE0 +#define SD_HC_SLOT_INT_STS 0xFC +#define SD_HC_CTRL_VER 0xFE + +// +// The transfer modes supported by SD Host Controller +// Simplified Spec 3.0 Table 1-2 +// +typedef enum { + SdNoData, + SdPioMode, + SdSdmaMode, + SdAdmaMode +} SD_HC_TRANSFER_MODE; + +// +// The maximum data length of each descriptor line +// +#define ADMA_MAX_DATA_PER_LINE 0x10000 +#define SD_SDMA_BOUNDARY 512 * 1024 +#define SD_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1)) + +typedef enum { + SdCommandTypeBc, // Broadcast commands, no response + SdCommandTypeBcr, // Broadcast commands with response + SdCommandTypeAc, // Addressed(point-to-point) commands + SdCommandTypeAdtc // Addressed(point-to-point) data transfer commands +} SD_COMMAND_TYPE; + +typedef enum { + SdResponseTypeR1, + SdResponseTypeR1b, + SdResponseTypeR2, + SdResponseTypeR3, + SdResponseTypeR4, + SdResponseTypeR5, + SdResponseTypeR5b, + SdResponseTypeR6, + SdResponseTypeR7 +} SD_RESPONSE_TYPE; + +typedef struct _SD_COMMAND_BLOCK { + UINT16 CommandIndex; + UINT32 CommandArgument; + UINT32 CommandType; // One of the SD_COMMAND_TYPE values + UINT32 ResponseType; // One of the SD_RESPONSE_TYPE values +} SD_COMMAND_BLOCK; + +typedef struct _SD_STATUS_BLOCK { + UINT32 Resp0; + UINT32 Resp1; + UINT32 Resp2; + UINT32 Resp3; +} SD_STATUS_BLOCK; + +typedef struct _SD_COMMAND_PACKET { + UINT64 Timeout; + SD_COMMAND_BLOCK *SdCmdBlk; + SD_STATUS_BLOCK *SdStatusBlk; + VOID *InDataBuffer; + VOID *OutDataBuffer; + UINT32 InTransferLength; + UINT32 OutTransferLength; +} SD_COMMAND_PACKET; + +#pragma pack(1) + +typedef struct { + UINT32 Valid : 1; + UINT32 End : 1; + UINT32 Int : 1; + UINT32 Reserved : 1; + UINT32 Act : 2; + UINT32 Reserved1 : 10; + UINT32 Length : 16; + UINT32 Address; +} SD_HC_ADMA_DESC_LINE; + +typedef struct { + UINT32 TimeoutFreq : 6; // bit 0:5 + UINT32 Reserved : 1; // bit 6 + UINT32 TimeoutUnit : 1; // bit 7 + UINT32 BaseClkFreq : 8; // bit 8:15 + UINT32 MaxBlkLen : 2; // bit 16:17 + UINT32 BusWidth8 : 1; // bit 18 + UINT32 Adma2 : 1; // bit 19 + UINT32 Reserved2 : 1; // bit 20 + UINT32 HighSpeed : 1; // bit 21 + UINT32 Sdma : 1; // bit 22 + UINT32 SuspRes : 1; // bit 23 + UINT32 Voltage33 : 1; // bit 24 + UINT32 Voltage30 : 1; // bit 25 + UINT32 Voltage18 : 1; // bit 26 + UINT32 Reserved3 : 1; // bit 27 + UINT32 SysBus64 : 1; // bit 28 + UINT32 AsyncInt : 1; // bit 29 + UINT32 SlotType : 2; // bit 30:31 + UINT32 Sdr50 : 1; // bit 32 + UINT32 Sdr104 : 1; // bit 33 + UINT32 Ddr50 : 1; // bit 34 + UINT32 Reserved4 : 1; // bit 35 + UINT32 DriverTypeA : 1; // bit 36 + UINT32 DriverTypeC : 1; // bit 37 + UINT32 DriverTypeD : 1; // bit 38 + UINT32 DriverType4 : 1; // bit 39 + UINT32 TimerCount : 4; // bit 40:43 + UINT32 Reserved5 : 1; // bit 44 + UINT32 TuningSDR50 : 1; // bit 45 + UINT32 RetuningMod : 2; // bit 46:47 + UINT32 ClkMultiplier : 8; // bit 48:55 + UINT32 Reserved6 : 7; // bit 56:62 + UINT32 Hs400 : 1; // bit 63 +} SD_HC_SLOT_CAP; + +#pragma pack() + +/** + Software reset the specified SD host controller and enable all interrupts. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The software reset executes successfully. + @retval Others The software reset fails. + +**/ +EFI_STATUS +SdPeimHcReset ( + IN UINTN Bar + ); + +/** + Set all interrupt status bits in Normal and Error Interrupt Status Enable + register. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimHcEnableInterrupt ( + IN UINTN Bar + ); + +/** + Get the capability data from the specified slot. + + @param[in] Bar The mmio base address of the slot to be accessed. + @param[out] Capability The buffer to store the capability data. + + @retval EFI_SUCCESS The operation executes successfully. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimHcGetCapability ( + IN UINTN Bar, + OUT SD_HC_SLOT_CAP *Capability + ); + +/** + Detect whether there is a SD card attached at the specified SD host controller + slot. + + Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS There is a SD card attached. + @retval EFI_NO_MEDIA There is not a SD card attached. + @retval Others The detection fails. + +**/ +EFI_STATUS +SdPeimHcCardDetect ( + IN UINTN Bar + ); + +/** + Initial SD host controller with lowest clock frequency, max power and max timeout value + at initialization. + + @param[in] Bar The mmio base address of the slot to be accessed. + + @retval EFI_SUCCESS The host controller is initialized successfully. + @retval Others The host controller isn't initialized successfully. + +**/ +EFI_STATUS +SdPeimHcInitHost ( + IN UINTN Bar + ); + +/** + Send command SWITCH_FUNC to the SD device to check switchable function or switch card function. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] AccessMode The value for access mode group. + @param[in] CommandSystem The value for command set group. + @param[in] DriveStrength The value for drive length group. + @param[in] PowerLimit The value for power limit group. + @param[in] Mode Switch or check function. + @param[out] SwitchResp The return switch function status. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimSwitch ( + IN SD_PEIM_HC_SLOT *Slot, + IN UINT8 AccessMode, + IN UINT8 CommandSystem, + IN UINT8 DriveStrength, + IN UINT8 PowerLimit, + IN BOOLEAN Mode, + OUT UINT8 *SwitchResp + ); + +/** + Send command READ_SINGLE_BLOCK/WRITE_SINGLE_BLOCK to the addressed SD device + to read/write the specified number of blocks. + + Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details. + + @param[in] Slot The slot number of the SD card to send the command to. + @param[in] Lba The logical block address of starting access. + @param[in] BlockSize The block size of specified SD device partition. + @param[in] Buffer The pointer to the transfer buffer. + @param[in] BufferSize The size of transfer buffer. + @param[in] IsRead Boolean to show the operation direction. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimRwSingleBlock ( + IN SD_PEIM_HC_SLOT *Slot, + IN EFI_LBA Lba, + IN UINT32 BlockSize, + IN VOID *Buffer, + IN UINTN BufferSize, + IN BOOLEAN IsRead + ); + +/** + Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed SD device + to read/write the specified number of blocks. + + Refer to SD Electrical Standard Spec 5.1 Section 6.10.4 for details. + + @param[in] Slot The slot number of the Sd card to send the command to. + @param[in] Lba The logical block address of starting access. + @param[in] BlockSize The block size of specified SD device partition. + @param[in] Buffer The pointer to the transfer buffer. + @param[in] BufferSize The size of transfer buffer. + @param[in] IsRead Boolean to show the operation direction. + + @retval EFI_SUCCESS The operation is done correctly. + @retval Others The operation fails. + +**/ +EFI_STATUS +SdPeimRwMultiBlocks ( + IN SD_PEIM_HC_SLOT *Slot, + IN EFI_LBA Lba, + IN UINT32 BlockSize, + IN VOID *Buffer, + IN UINTN BufferSize, + IN BOOLEAN IsRead + ); + +/** + Execute SD device identification procedure. + + Refer to SD Electrical Standard Spec 5.1 Section 6.4 for details. + + @param[in] Slot The slot number of the Sd card to send the command to. + + @retval EFI_SUCCESS There is a SD card. + @retval Others There is not a SD card. + +**/ +EFI_STATUS +SdPeimIdentification ( + IN SD_PEIM_HC_SLOT *Slot + ); + +/** + Free the resource used by the TRB. + + @param[in] Trb The pointer to the SD_TRB instance. + +**/ +VOID +SdPeimFreeTrb ( + IN SD_TRB *Trb + ); + +#endif diff --git a/MdeModulePkg/Bus/Sd/SdDxe/ComponentName.c b/MdeModulePkg/Bus/Sd/SdDxe/ComponentName.c index 405a3d3ffe..c15fae1bde 100644 --- a/MdeModulePkg/Bus/Sd/SdDxe/ComponentName.c +++ b/MdeModulePkg/Bus/Sd/SdDxe/ComponentName.c @@ -1,233 +1,233 @@ -/** @file
- UEFI Component Name(2) protocol implementation for SdDxe driver.
-
- Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "SdDxe.h"
-
-//
-// Driver name table
-//
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdDxeDriverNameTable[] = {
- { "eng;en", L"Edkii Sd Memory Card Device Driver" },
- { NULL, NULL }
-};
-
-//
-// Controller name table
-//
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdDxeControllerNameTable[] = {
- { "eng;en", L"Edkii Sd Host Controller" },
- { NULL, NULL }
-};
-
-//
-// EFI Component Name Protocol
-//
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSdDxeComponentName = {
- SdDxeComponentNameGetDriverName,
- SdDxeComponentNameGetControllerName,
- "eng"
-};
-
-//
-// EFI Component Name 2 Protocol
-//
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSdDxeComponentName2 = {
- (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)SdDxeComponentNameGetDriverName,
- (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)SdDxeComponentNameGetControllerName,
- "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
-SdDxeComponentNameGetDriverName (
- IN EFI_COMPONENT_NAME_PROTOCOL *This,
- IN CHAR8 *Language,
- OUT CHAR16 **DriverName
- )
-{
- return LookupUnicodeString2 (
- Language,
- This->SupportedLanguages,
- mSdDxeDriverNameTable,
- DriverName,
- (BOOLEAN)(This == &gSdDxeComponentName)
- );
-}
-
-/**
- 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
-SdDxeComponentNameGetControllerName (
- 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;
- SD_DEVICE *Device;
- EFI_UNICODE_STRING_TABLE *ControllerNameTable;
-
- //
- // Make sure this driver is currently managing ControllHandle
- //
- Status = EfiTestManagedDevice (
- ControllerHandle,
- gSdDxeDriverBinding.DriverBindingHandle,
- &gEfiSdMmcPassThruProtocolGuid
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- ControllerNameTable = mSdDxeControllerNameTable;
- 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,
- gSdDxeDriverBinding.DriverBindingHandle,
- ChildHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- return EFI_UNSUPPORTED;
- }
-
- Device = SD_DEVICE_DATA_FROM_BLKIO (BlockIo);
- ControllerNameTable = Device->ControllerNameTable;
- }
-
- return LookupUnicodeString2 (
- Language,
- This->SupportedLanguages,
- ControllerNameTable,
- ControllerName,
- (BOOLEAN)(This == &gSdDxeComponentName)
- );
-}
+/** @file + UEFI Component Name(2) protocol implementation for SdDxe driver. + + Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SdDxe.h" + +// +// Driver name table +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdDxeDriverNameTable[] = { + { "eng;en", L"Edkii Sd Memory Card Device Driver" }, + { NULL, NULL } +}; + +// +// Controller name table +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdDxeControllerNameTable[] = { + { "eng;en", L"Edkii Sd Host Controller" }, + { NULL, NULL } +}; + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSdDxeComponentName = { + SdDxeComponentNameGetDriverName, + SdDxeComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSdDxeComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)SdDxeComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)SdDxeComponentNameGetControllerName, + "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 +SdDxeComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mSdDxeDriverNameTable, + DriverName, + (BOOLEAN)(This == &gSdDxeComponentName) + ); +} + +/** + 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 +SdDxeComponentNameGetControllerName ( + 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; + SD_DEVICE *Device; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + + // + // Make sure this driver is currently managing ControllHandle + // + Status = EfiTestManagedDevice ( + ControllerHandle, + gSdDxeDriverBinding.DriverBindingHandle, + &gEfiSdMmcPassThruProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + ControllerNameTable = mSdDxeControllerNameTable; + 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, + gSdDxeDriverBinding.DriverBindingHandle, + ChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Device = SD_DEVICE_DATA_FROM_BLKIO (BlockIo); + ControllerNameTable = Device->ControllerNameTable; + } + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + ControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gSdDxeComponentName) + ); +} diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c b/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c index 45df48ff72..5309c74c16 100644 --- a/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c +++ b/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c @@ -1,1402 +1,1402 @@ -/** @file
- The helper functions for BlockIo and BlockIo2 protocol.
-
- Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "SdDxe.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
- )
-{
- SD_REQUEST *Request;
-
- gBS->CloseEvent (Event);
-
- Request = (SD_REQUEST *)Context;
-
- DEBUG_CODE_BEGIN ();
- DEBUG ((
- DEBUG_INFO,
- "Sd 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 SET_RELATIVE_ADDRESS to the device to set the device address.
-
- @param[in] Device A pointer to the SD_DEVICE instance.
- @param[out] Rca The relative device address to assign.
-
- @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
-SdSetRca (
- IN SD_DEVICE *Device,
- OUT 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 = SD_GENERIC_TIMEOUT;
-
- SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;
- SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
- SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;
-
- Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
- if (!EFI_ERROR (Status)) {
- DEBUG ((DEBUG_INFO, "Set RCA succeeds with Resp0 = 0x%x\n", SdMmcStatusBlk.Resp0));
- *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);
- }
-
- return Status;
-}
-
-/**
- Send command SELECT to the device to select/deselect the device.
-
- @param[in] Device A pointer to the SD_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
-SdSelect (
- IN SD_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 = SD_GENERIC_TIMEOUT;
-
- SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;
- SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
- if (Rca != 0) {
- SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
- }
-
- SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
-
- Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
-
- return Status;
-}
-
-/**
- Send command SEND_STATUS to the device to get device status.
-
- @param[in] Device A pointer to the SD_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
-SdSendStatus (
- IN SD_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 = SD_GENERIC_TIMEOUT;
-
- SdMmcCmdBlk.CommandIndex = SD_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 SD_DEVICE instance.
- @param[in] Rca The relative device address to use.
- @param[out] Csd The buffer to store the SD_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
-SdGetCsd (
- IN SD_DEVICE *Device,
- IN UINT16 Rca,
- OUT SD_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 (SD_CSD));
-
- Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
- Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
- Packet.Timeout = SD_GENERIC_TIMEOUT;
-
- SdMmcCmdBlk.CommandIndex = SD_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 (SD_CSD) - 1);
- }
-
- return Status;
-}
-
-/**
- Send command SEND_CID to the device to get the CID register data.
-
- @param[in] Device A pointer to the SD_DEVICE instance.
- @param[in] Rca The relative device address to use.
- @param[out] Cid The buffer to store the SD_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
-SdGetCid (
- IN SD_DEVICE *Device,
- IN UINT16 Rca,
- OUT SD_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 (SD_CID));
-
- Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
- Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
- Packet.Timeout = SD_GENERIC_TIMEOUT;
-
- SdMmcCmdBlk.CommandIndex = SD_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 (SD_CID) - 1);
- }
-
- return Status;
-}
-
-/**
- Read/write single block through sync or async I/O request.
-
- @param[in] Device A pointer to the SD_DEVICE 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
-SdRwSingleBlock (
- IN SD_DEVICE *Device,
- 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;
- EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
- SD_REQUEST *RwSingleBlkReq;
- EFI_TPL OldTpl;
-
- RwSingleBlkReq = NULL;
- PassThru = Device->Private->PassThru;
-
- RwSingleBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));
- if (RwSingleBlkReq == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Error;
- }
-
- RwSingleBlkReq->Signature = SD_REQUEST_SIGNATURE;
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- InsertTailList (&Device->Queue, &RwSingleBlkReq->Link);
- gBS->RestoreTPL (OldTpl);
- RwSingleBlkReq->Packet.SdMmcCmdBlk = &RwSingleBlkReq->SdMmcCmdBlk;
- RwSingleBlkReq->Packet.SdMmcStatusBlk = &RwSingleBlkReq->SdMmcStatusBlk;
- //
- // Calculate timeout value through the below formula.
- // Timeout = (transfer size) / (2MB/s).
- // Taking 2MB/s as divisor as it's the lowest transfer speed
- // above class 2.
- // Refer to SD Physical Layer Simplified spec section 3.4 for details.
- //
- RwSingleBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
-
- if (IsRead) {
- RwSingleBlkReq->Packet.InDataBuffer = Buffer;
- RwSingleBlkReq->Packet.InTransferLength = (UINT32)BufferSize;
-
- RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_SINGLE_BLOCK;
- RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
- RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
- } else {
- RwSingleBlkReq->Packet.OutDataBuffer = Buffer;
- RwSingleBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
-
- RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_SINGLE_BLOCK;
- RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
- RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
- }
-
- if (Device->SectorAddressing) {
- RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
- } else {
- RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);
- }
-
- RwSingleBlkReq->IsEnd = IsEnd;
- RwSingleBlkReq->Token = Token;
-
- if ((Token != NULL) && (Token->Event != NULL)) {
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- AsyncIoCallback,
- RwSingleBlkReq,
- &RwSingleBlkReq->Event
- );
- if (EFI_ERROR (Status)) {
- goto Error;
- }
- } else {
- RwSingleBlkReq->Event = NULL;
- }
-
- Status = PassThru->PassThru (PassThru, Device->Slot, &RwSingleBlkReq->Packet, RwSingleBlkReq->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) && (RwSingleBlkReq != NULL)) {
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- RemoveEntryList (&RwSingleBlkReq->Link);
- gBS->RestoreTPL (OldTpl);
- if (RwSingleBlkReq->Event != NULL) {
- gBS->CloseEvent (RwSingleBlkReq->Event);
- }
-
- FreePool (RwSingleBlkReq);
- }
- } else {
- //
- // For synchronous operation, free request whatever the execution result is.
- //
- if (RwSingleBlkReq != NULL) {
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- RemoveEntryList (&RwSingleBlkReq->Link);
- gBS->RestoreTPL (OldTpl);
- FreePool (RwSingleBlkReq);
- }
- }
-
- return Status;
-}
-
-/**
- Read/write multiple blocks through sync or async I/O request.
-
- @param[in] Device A pointer to the SD_DEVICE 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
-SdRwMultiBlocks (
- IN SD_DEVICE *Device,
- 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;
- SD_REQUEST *RwMultiBlkReq;
- EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
- EFI_TPL OldTpl;
-
- RwMultiBlkReq = NULL;
-
- PassThru = Device->Private->PassThru;
-
- RwMultiBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));
- if (RwMultiBlkReq == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Error;
- }
-
- RwMultiBlkReq->Signature = SD_REQUEST_SIGNATURE;
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- InsertTailList (&Device->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 as it's the lowest transfer speed
- // above class 2.
- // Refer to SD Physical Layer Simplified spec section 3.4 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 = SD_READ_MULTIPLE_BLOCK;
- RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
- RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
- } else {
- RwMultiBlkReq->Packet.OutDataBuffer = Buffer;
- RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
-
- RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK;
- RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
- RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
- }
-
- if (Device->SectorAddressing) {
- RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
- } else {
- RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->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 the sd memory card device.
-
- @param[in] Device A pointer to the SD_DEVICE 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
-SdReadWrite (
- IN SD_DEVICE *Device,
- 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;
- EFI_BLOCK_IO_MEDIA *Media;
- UINTN BlockSize;
- UINTN BlockNum;
- UINTN IoAlign;
- UINTN Remaining;
- UINT32 MaxBlock;
- BOOLEAN LastRw;
-
- Status = EFI_SUCCESS;
- Media = &Device->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;
- }
-
- //
- // 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;
- }
-
- BufferSize = BlockNum * BlockSize;
- if (BlockNum == 1) {
- Status = SdRwSingleBlock (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
- } else {
- Status = SdRwMultiBlocks (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
- }
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- DEBUG ((
- DEBUG_BLKIO,
- "Sd%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
- IsRead ? "Read" : "Write",
- 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
-SdReset (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- IN BOOLEAN ExtendedVerification
- )
-{
- EFI_STATUS Status;
- SD_DEVICE *Device;
- EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
-
- Device = SD_DEVICE_DATA_FROM_BLKIO (This);
-
- PassThru = Device->Private->PassThru;
- Status = PassThru->ResetDevice (PassThru, 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
-SdReadBlocks (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- IN UINT32 MediaId,
- IN EFI_LBA Lba,
- IN UINTN BufferSize,
- OUT VOID *Buffer
- )
-{
- EFI_STATUS Status;
- SD_DEVICE *Device;
-
- Device = SD_DEVICE_DATA_FROM_BLKIO (This);
-
- Status = SdReadWrite (Device, 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
-SdWriteBlocks (
- IN EFI_BLOCK_IO_PROTOCOL *This,
- IN UINT32 MediaId,
- IN EFI_LBA Lba,
- IN UINTN BufferSize,
- IN VOID *Buffer
- )
-{
- EFI_STATUS Status;
- SD_DEVICE *Device;
-
- Device = SD_DEVICE_DATA_FROM_BLKIO (This);
-
- Status = SdReadWrite (Device, 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
-SdFlushBlocks (
- 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
-SdResetEx (
- IN EFI_BLOCK_IO2_PROTOCOL *This,
- IN BOOLEAN ExtendedVerification
- )
-{
- SD_DEVICE *Device;
- LIST_ENTRY *Link;
- LIST_ENTRY *NextLink;
- SD_REQUEST *Request;
- EFI_TPL OldTpl;
-
- Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
-
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- for (Link = GetFirstNode (&Device->Queue);
- !IsNull (&Device->Queue, Link);
- Link = NextLink)
- {
- NextLink = GetNextNode (&Device->Queue, Link);
- RemoveEntryList (Link);
-
- Request = SD_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
-SdReadBlocksEx (
- 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;
- SD_DEVICE *Device;
-
- Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
-
- Status = SdReadWrite (Device, 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
-SdWriteBlocksEx (
- 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;
- SD_DEVICE *Device;
-
- Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
-
- Status = SdReadWrite (Device, 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
-SdFlushBlocksEx (
- 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;
-}
-
-/**
- Set the erase start address through sync or async I/O request.
-
- @param[in] Device A pointer to the SD_DEVICE 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
-SdEraseBlockStart (
- IN SD_DEVICE *Device,
- IN EFI_LBA StartLba,
- IN EFI_BLOCK_IO2_TOKEN *Token,
- IN BOOLEAN IsEnd
- )
-{
- EFI_STATUS Status;
- EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
- SD_REQUEST *EraseBlockStart;
- EFI_TPL OldTpl;
-
- EraseBlockStart = NULL;
- PassThru = Device->Private->PassThru;
-
- EraseBlockStart = AllocateZeroPool (sizeof (SD_REQUEST));
- if (EraseBlockStart == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Error;
- }
-
- EraseBlockStart->Signature = SD_REQUEST_SIGNATURE;
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- InsertTailList (&Device->Queue, &EraseBlockStart->Link);
- gBS->RestoreTPL (OldTpl);
- EraseBlockStart->Packet.SdMmcCmdBlk = &EraseBlockStart->SdMmcCmdBlk;
- EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;
- EraseBlockStart->Packet.Timeout = SD_GENERIC_TIMEOUT;
-
- EraseBlockStart->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_START;
- EraseBlockStart->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
- EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
-
- if (Device->SectorAddressing) {
- EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;
- } else {
- EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (StartLba, Device->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] Device A pointer to the SD_DEVICE 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
-SdEraseBlockEnd (
- IN SD_DEVICE *Device,
- IN EFI_LBA EndLba,
- IN EFI_BLOCK_IO2_TOKEN *Token,
- IN BOOLEAN IsEnd
- )
-{
- EFI_STATUS Status;
- EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
- SD_REQUEST *EraseBlockEnd;
- EFI_TPL OldTpl;
-
- EraseBlockEnd = NULL;
- PassThru = Device->Private->PassThru;
-
- EraseBlockEnd = AllocateZeroPool (sizeof (SD_REQUEST));
- if (EraseBlockEnd == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Error;
- }
-
- EraseBlockEnd->Signature = SD_REQUEST_SIGNATURE;
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- InsertTailList (&Device->Queue, &EraseBlockEnd->Link);
- gBS->RestoreTPL (OldTpl);
- EraseBlockEnd->Packet.SdMmcCmdBlk = &EraseBlockEnd->SdMmcCmdBlk;
- EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;
- EraseBlockEnd->Packet.Timeout = SD_GENERIC_TIMEOUT;
-
- EraseBlockEnd->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_END;
- EraseBlockEnd->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
- EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
-
- if (Device->SectorAddressing) {
- EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;
- } else {
- EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, Device->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] Device A pointer to the SD_DEVICE 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
-SdEraseBlock (
- IN SD_DEVICE *Device,
- IN EFI_BLOCK_IO2_TOKEN *Token,
- IN BOOLEAN IsEnd
- )
-{
- EFI_STATUS Status;
- EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
- SD_REQUEST *EraseBlock;
- EFI_TPL OldTpl;
-
- EraseBlock = NULL;
- PassThru = Device->Private->PassThru;
-
- EraseBlock = AllocateZeroPool (sizeof (SD_REQUEST));
- if (EraseBlock == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Error;
- }
-
- EraseBlock->Signature = SD_REQUEST_SIGNATURE;
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- InsertTailList (&Device->Queue, &EraseBlock->Link);
- gBS->RestoreTPL (OldTpl);
- EraseBlock->Packet.SdMmcCmdBlk = &EraseBlock->SdMmcCmdBlk;
- EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;
- EraseBlock->Packet.Timeout = SD_GENERIC_TIMEOUT;
-
- EraseBlock->SdMmcCmdBlk.CommandIndex = SD_ERASE;
- EraseBlock->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
- EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
-
- 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;
-}
-
-/**
- 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
-SdEraseBlocks (
- 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 LastLba;
- SD_DEVICE *Device;
-
- Status = EFI_SUCCESS;
- Device = SD_DEVICE_DATA_FROM_ERASEBLK (This);
- Media = &Device->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;
- }
-
- LastLba = Lba + BlockNum - 1;
-
- Status = SdEraseBlockStart (Device, Lba, (EFI_BLOCK_IO2_TOKEN *)Token, FALSE);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = SdEraseBlockEnd (Device, LastLba, (EFI_BLOCK_IO2_TOKEN *)Token, FALSE);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = SdEraseBlock (Device, (EFI_BLOCK_IO2_TOKEN *)Token, TRUE);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- DEBUG ((
- DEBUG_INFO,
- "SdEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
- Lba,
- BlockNum,
- (Token != NULL) ? Token->Event : NULL,
- Status
- ));
-
- return Status;
-}
+/** @file + The helper functions for BlockIo and BlockIo2 protocol. + + Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SdDxe.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 + ) +{ + SD_REQUEST *Request; + + gBS->CloseEvent (Event); + + Request = (SD_REQUEST *)Context; + + DEBUG_CODE_BEGIN (); + DEBUG (( + DEBUG_INFO, + "Sd 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 SET_RELATIVE_ADDRESS to the device to set the device address. + + @param[in] Device A pointer to the SD_DEVICE instance. + @param[out] Rca The relative device address to assign. + + @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 +SdSetRca ( + IN SD_DEVICE *Device, + OUT 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 = SD_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6; + + Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL); + if (!EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "Set RCA succeeds with Resp0 = 0x%x\n", SdMmcStatusBlk.Resp0)); + *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16); + } + + return Status; +} + +/** + Send command SELECT to the device to select/deselect the device. + + @param[in] Device A pointer to the SD_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 +SdSelect ( + IN SD_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 = SD_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + if (Rca != 0) { + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b; + } + + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL); + + return Status; +} + +/** + Send command SEND_STATUS to the device to get device status. + + @param[in] Device A pointer to the SD_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 +SdSendStatus ( + IN SD_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 = SD_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_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 SD_DEVICE instance. + @param[in] Rca The relative device address to use. + @param[out] Csd The buffer to store the SD_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 +SdGetCsd ( + IN SD_DEVICE *Device, + IN UINT16 Rca, + OUT SD_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 (SD_CSD)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_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 (SD_CSD) - 1); + } + + return Status; +} + +/** + Send command SEND_CID to the device to get the CID register data. + + @param[in] Device A pointer to the SD_DEVICE instance. + @param[in] Rca The relative device address to use. + @param[out] Cid The buffer to store the SD_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 +SdGetCid ( + IN SD_DEVICE *Device, + IN UINT16 Rca, + OUT SD_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 (SD_CID)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_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 (SD_CID) - 1); + } + + return Status; +} + +/** + Read/write single block through sync or async I/O request. + + @param[in] Device A pointer to the SD_DEVICE 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 +SdRwSingleBlock ( + IN SD_DEVICE *Device, + 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; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + SD_REQUEST *RwSingleBlkReq; + EFI_TPL OldTpl; + + RwSingleBlkReq = NULL; + PassThru = Device->Private->PassThru; + + RwSingleBlkReq = AllocateZeroPool (sizeof (SD_REQUEST)); + if (RwSingleBlkReq == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + RwSingleBlkReq->Signature = SD_REQUEST_SIGNATURE; + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + InsertTailList (&Device->Queue, &RwSingleBlkReq->Link); + gBS->RestoreTPL (OldTpl); + RwSingleBlkReq->Packet.SdMmcCmdBlk = &RwSingleBlkReq->SdMmcCmdBlk; + RwSingleBlkReq->Packet.SdMmcStatusBlk = &RwSingleBlkReq->SdMmcStatusBlk; + // + // Calculate timeout value through the below formula. + // Timeout = (transfer size) / (2MB/s). + // Taking 2MB/s as divisor as it's the lowest transfer speed + // above class 2. + // Refer to SD Physical Layer Simplified spec section 3.4 for details. + // + RwSingleBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000; + + if (IsRead) { + RwSingleBlkReq->Packet.InDataBuffer = Buffer; + RwSingleBlkReq->Packet.InTransferLength = (UINT32)BufferSize; + + RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_SINGLE_BLOCK; + RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + } else { + RwSingleBlkReq->Packet.OutDataBuffer = Buffer; + RwSingleBlkReq->Packet.OutTransferLength = (UINT32)BufferSize; + + RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_SINGLE_BLOCK; + RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + } + + if (Device->SectorAddressing) { + RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba; + } else { + RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize); + } + + RwSingleBlkReq->IsEnd = IsEnd; + RwSingleBlkReq->Token = Token; + + if ((Token != NULL) && (Token->Event != NULL)) { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + AsyncIoCallback, + RwSingleBlkReq, + &RwSingleBlkReq->Event + ); + if (EFI_ERROR (Status)) { + goto Error; + } + } else { + RwSingleBlkReq->Event = NULL; + } + + Status = PassThru->PassThru (PassThru, Device->Slot, &RwSingleBlkReq->Packet, RwSingleBlkReq->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) && (RwSingleBlkReq != NULL)) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + RemoveEntryList (&RwSingleBlkReq->Link); + gBS->RestoreTPL (OldTpl); + if (RwSingleBlkReq->Event != NULL) { + gBS->CloseEvent (RwSingleBlkReq->Event); + } + + FreePool (RwSingleBlkReq); + } + } else { + // + // For synchronous operation, free request whatever the execution result is. + // + if (RwSingleBlkReq != NULL) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + RemoveEntryList (&RwSingleBlkReq->Link); + gBS->RestoreTPL (OldTpl); + FreePool (RwSingleBlkReq); + } + } + + return Status; +} + +/** + Read/write multiple blocks through sync or async I/O request. + + @param[in] Device A pointer to the SD_DEVICE 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 +SdRwMultiBlocks ( + IN SD_DEVICE *Device, + 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; + SD_REQUEST *RwMultiBlkReq; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + EFI_TPL OldTpl; + + RwMultiBlkReq = NULL; + + PassThru = Device->Private->PassThru; + + RwMultiBlkReq = AllocateZeroPool (sizeof (SD_REQUEST)); + if (RwMultiBlkReq == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + RwMultiBlkReq->Signature = SD_REQUEST_SIGNATURE; + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + InsertTailList (&Device->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 as it's the lowest transfer speed + // above class 2. + // Refer to SD Physical Layer Simplified spec section 3.4 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 = SD_READ_MULTIPLE_BLOCK; + RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + } else { + RwMultiBlkReq->Packet.OutDataBuffer = Buffer; + RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize; + + RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK; + RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + } + + if (Device->SectorAddressing) { + RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba; + } else { + RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->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 the sd memory card device. + + @param[in] Device A pointer to the SD_DEVICE 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 +SdReadWrite ( + IN SD_DEVICE *Device, + 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; + EFI_BLOCK_IO_MEDIA *Media; + UINTN BlockSize; + UINTN BlockNum; + UINTN IoAlign; + UINTN Remaining; + UINT32 MaxBlock; + BOOLEAN LastRw; + + Status = EFI_SUCCESS; + Media = &Device->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; + } + + // + // 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; + } + + BufferSize = BlockNum * BlockSize; + if (BlockNum == 1) { + Status = SdRwSingleBlock (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw); + } else { + Status = SdRwMultiBlocks (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + DEBUG (( + DEBUG_BLKIO, + "Sd%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", + IsRead ? "Read" : "Write", + 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 +SdReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + EFI_STATUS Status; + SD_DEVICE *Device; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + + Device = SD_DEVICE_DATA_FROM_BLKIO (This); + + PassThru = Device->Private->PassThru; + Status = PassThru->ResetDevice (PassThru, 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 +SdReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + SD_DEVICE *Device; + + Device = SD_DEVICE_DATA_FROM_BLKIO (This); + + Status = SdReadWrite (Device, 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 +SdWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + SD_DEVICE *Device; + + Device = SD_DEVICE_DATA_FROM_BLKIO (This); + + Status = SdReadWrite (Device, 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 +SdFlushBlocks ( + 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 +SdResetEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + SD_DEVICE *Device; + LIST_ENTRY *Link; + LIST_ENTRY *NextLink; + SD_REQUEST *Request; + EFI_TPL OldTpl; + + Device = SD_DEVICE_DATA_FROM_BLKIO2 (This); + + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + for (Link = GetFirstNode (&Device->Queue); + !IsNull (&Device->Queue, Link); + Link = NextLink) + { + NextLink = GetNextNode (&Device->Queue, Link); + RemoveEntryList (Link); + + Request = SD_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 +SdReadBlocksEx ( + 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; + SD_DEVICE *Device; + + Device = SD_DEVICE_DATA_FROM_BLKIO2 (This); + + Status = SdReadWrite (Device, 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 +SdWriteBlocksEx ( + 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; + SD_DEVICE *Device; + + Device = SD_DEVICE_DATA_FROM_BLKIO2 (This); + + Status = SdReadWrite (Device, 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 +SdFlushBlocksEx ( + 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; +} + +/** + Set the erase start address through sync or async I/O request. + + @param[in] Device A pointer to the SD_DEVICE 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 +SdEraseBlockStart ( + IN SD_DEVICE *Device, + IN EFI_LBA StartLba, + IN EFI_BLOCK_IO2_TOKEN *Token, + IN BOOLEAN IsEnd + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + SD_REQUEST *EraseBlockStart; + EFI_TPL OldTpl; + + EraseBlockStart = NULL; + PassThru = Device->Private->PassThru; + + EraseBlockStart = AllocateZeroPool (sizeof (SD_REQUEST)); + if (EraseBlockStart == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + EraseBlockStart->Signature = SD_REQUEST_SIGNATURE; + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + InsertTailList (&Device->Queue, &EraseBlockStart->Link); + gBS->RestoreTPL (OldTpl); + EraseBlockStart->Packet.SdMmcCmdBlk = &EraseBlockStart->SdMmcCmdBlk; + EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk; + EraseBlockStart->Packet.Timeout = SD_GENERIC_TIMEOUT; + + EraseBlockStart->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_START; + EraseBlockStart->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + + if (Device->SectorAddressing) { + EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba; + } else { + EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (StartLba, Device->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] Device A pointer to the SD_DEVICE 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 +SdEraseBlockEnd ( + IN SD_DEVICE *Device, + IN EFI_LBA EndLba, + IN EFI_BLOCK_IO2_TOKEN *Token, + IN BOOLEAN IsEnd + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + SD_REQUEST *EraseBlockEnd; + EFI_TPL OldTpl; + + EraseBlockEnd = NULL; + PassThru = Device->Private->PassThru; + + EraseBlockEnd = AllocateZeroPool (sizeof (SD_REQUEST)); + if (EraseBlockEnd == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + EraseBlockEnd->Signature = SD_REQUEST_SIGNATURE; + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + InsertTailList (&Device->Queue, &EraseBlockEnd->Link); + gBS->RestoreTPL (OldTpl); + EraseBlockEnd->Packet.SdMmcCmdBlk = &EraseBlockEnd->SdMmcCmdBlk; + EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk; + EraseBlockEnd->Packet.Timeout = SD_GENERIC_TIMEOUT; + + EraseBlockEnd->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_END; + EraseBlockEnd->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + + if (Device->SectorAddressing) { + EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba; + } else { + EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, Device->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] Device A pointer to the SD_DEVICE 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 +SdEraseBlock ( + IN SD_DEVICE *Device, + IN EFI_BLOCK_IO2_TOKEN *Token, + IN BOOLEAN IsEnd + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + SD_REQUEST *EraseBlock; + EFI_TPL OldTpl; + + EraseBlock = NULL; + PassThru = Device->Private->PassThru; + + EraseBlock = AllocateZeroPool (sizeof (SD_REQUEST)); + if (EraseBlock == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + EraseBlock->Signature = SD_REQUEST_SIGNATURE; + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + InsertTailList (&Device->Queue, &EraseBlock->Link); + gBS->RestoreTPL (OldTpl); + EraseBlock->Packet.SdMmcCmdBlk = &EraseBlock->SdMmcCmdBlk; + EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk; + EraseBlock->Packet.Timeout = SD_GENERIC_TIMEOUT; + + EraseBlock->SdMmcCmdBlk.CommandIndex = SD_ERASE; + EraseBlock->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b; + + 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; +} + +/** + 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 +SdEraseBlocks ( + 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 LastLba; + SD_DEVICE *Device; + + Status = EFI_SUCCESS; + Device = SD_DEVICE_DATA_FROM_ERASEBLK (This); + Media = &Device->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; + } + + LastLba = Lba + BlockNum - 1; + + Status = SdEraseBlockStart (Device, Lba, (EFI_BLOCK_IO2_TOKEN *)Token, FALSE); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = SdEraseBlockEnd (Device, LastLba, (EFI_BLOCK_IO2_TOKEN *)Token, FALSE); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = SdEraseBlock (Device, (EFI_BLOCK_IO2_TOKEN *)Token, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + + DEBUG (( + DEBUG_INFO, + "SdEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", + Lba, + BlockNum, + (Token != NULL) ? Token->Event : NULL, + Status + )); + + return Status; +} diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.h b/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.h index b456ea31e8..919bf789e8 100644 --- a/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.h +++ b/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.h @@ -1,251 +1,251 @@ -/** @file
- Header file for SdDxe 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 _SD_BLOCK_IO_H_
-#define _SD_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
-SdReset (
- 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
-SdReadBlocks (
- 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
-SdWriteBlocks (
- 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
-SdFlushBlocks (
- 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
-SdResetEx (
- 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
-SdReadBlocksEx (
- 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
-SdWriteBlocksEx (
- 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
-SdFlushBlocksEx (
- IN EFI_BLOCK_IO2_PROTOCOL *This,
- IN OUT EFI_BLOCK_IO2_TOKEN *Token
- );
-
-/**
- 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
-SdEraseBlocks (
- IN EFI_ERASE_BLOCK_PROTOCOL *This,
- IN UINT32 MediaId,
- IN EFI_LBA Lba,
- IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
- IN UINTN Size
- );
-
-#endif
+/** @file + Header file for SdDxe 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 _SD_BLOCK_IO_H_ +#define _SD_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 +SdReset ( + 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 +SdReadBlocks ( + 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 +SdWriteBlocks ( + 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 +SdFlushBlocks ( + 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 +SdResetEx ( + 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 +SdReadBlocksEx ( + 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 +SdWriteBlocksEx ( + 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 +SdFlushBlocksEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN OUT EFI_BLOCK_IO2_TOKEN *Token + ); + +/** + 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 +SdEraseBlocks ( + 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/MdeModulePkg/Bus/Sd/SdDxe/SdDiskInfo.c b/MdeModulePkg/Bus/Sd/SdDxe/SdDiskInfo.c index 8bc82b9be7..62ba418d64 100644 --- a/MdeModulePkg/Bus/Sd/SdDxe/SdDiskInfo.c +++ b/MdeModulePkg/Bus/Sd/SdDxe/SdDiskInfo.c @@ -1,132 +1,132 @@ -/** @file
- Implement the EFI_DISK_INFO_PROTOCOL interface on SD memory card devices.
-
- Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "SdDxe.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
-SdDiskInfoInquiry (
- IN EFI_DISK_INFO_PROTOCOL *This,
- IN OUT VOID *InquiryData,
- IN OUT UINT32 *InquiryDataSize
- )
-{
- EFI_STATUS Status;
- SD_DEVICE *Device;
-
- Device = SD_DEVICE_DATA_FROM_DISKINFO (This);
-
- 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
-SdDiskInfoIdentify (
- 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
-SdDiskInfoSenseData (
- 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
-SdDiskInfoWhichIde (
- IN EFI_DISK_INFO_PROTOCOL *This,
- OUT UINT32 *IdeChannel,
- OUT UINT32 *IdeDevice
- )
-{
- return EFI_UNSUPPORTED;
-}
+/** @file + Implement the EFI_DISK_INFO_PROTOCOL interface on SD memory card devices. + + Copyright (c) 2017, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SdDxe.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 +SdDiskInfoInquiry ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *InquiryData, + IN OUT UINT32 *InquiryDataSize + ) +{ + EFI_STATUS Status; + SD_DEVICE *Device; + + Device = SD_DEVICE_DATA_FROM_DISKINFO (This); + + 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 +SdDiskInfoIdentify ( + 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 +SdDiskInfoSenseData ( + 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 +SdDiskInfoWhichIde ( + IN EFI_DISK_INFO_PROTOCOL *This, + OUT UINT32 *IdeChannel, + OUT UINT32 *IdeDevice + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdDiskInfo.h b/MdeModulePkg/Bus/Sd/SdDxe/SdDiskInfo.h index 64e2f77c94..b5c41785b4 100644 --- a/MdeModulePkg/Bus/Sd/SdDxe/SdDiskInfo.h +++ b/MdeModulePkg/Bus/Sd/SdDxe/SdDiskInfo.h @@ -1,109 +1,109 @@ -/** @file
- Header file for EFI_DISK_INFO_PROTOCOL interface on SD memory card devices.
-
- Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _SD_DISKINFO_H_
-#define _SD_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
-SdDiskInfoInquiry (
- 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
-SdDiskInfoIdentify (
- 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
-SdDiskInfoSenseData (
- 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
-SdDiskInfoWhichIde (
- IN EFI_DISK_INFO_PROTOCOL *This,
- OUT UINT32 *IdeChannel,
- OUT UINT32 *IdeDevice
- );
-
-#endif
+/** @file + Header file for EFI_DISK_INFO_PROTOCOL interface on SD memory card devices. + + Copyright (c) 2017, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SD_DISKINFO_H_ +#define _SD_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 +SdDiskInfoInquiry ( + 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 +SdDiskInfoIdentify ( + 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 +SdDiskInfoSenseData ( + 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 +SdDiskInfoWhichIde ( + IN EFI_DISK_INFO_PROTOCOL *This, + OUT UINT32 *IdeChannel, + OUT UINT32 *IdeDevice + ); + +#endif diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c index a7b2515b14..bbf6102b40 100644 --- a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c +++ b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c @@ -1,913 +1,913 @@ -/** @file
- The SdDxe driver is used to manage the SD memory card device.
-
- It produces BlockIo and BlockIo2 protocols to allow upper layer
- access the SD memory card device.
-
- Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "SdDxe.h"
-
-//
-// SdDxe Driver Binding Protocol Instance
-//
-EFI_DRIVER_BINDING_PROTOCOL gSdDxeDriverBinding = {
- SdDxeDriverBindingSupported,
- SdDxeDriverBindingStart,
- SdDxeDriverBindingStop,
- 0x10,
- NULL,
- NULL
-};
-
-//
-// Template for SD_DEVICE data structure.
-//
-SD_DEVICE mSdDeviceTemplate = {
- SD_DEVICE_SIGNATURE, // Signature
- NULL, // Handle
- NULL, // DevicePath
- 0xFF, // Slot
- FALSE, // SectorAddressing
- { // BlockIo
- EFI_BLOCK_IO_PROTOCOL_REVISION,
- NULL,
- SdReset,
- SdReadBlocks,
- SdWriteBlocks,
- SdFlushBlocks
- },
- { // BlockIo2
- NULL,
- SdResetEx,
- SdReadBlocksEx,
- SdWriteBlocksEx,
- SdFlushBlocksEx
- },
- { // BlockMedia
- 0, // MediaId
- FALSE, // RemovableMedia
- TRUE, // MediaPresent
- FALSE, // LogicPartition
- FALSE, // ReadOnly
- FALSE, // WritingCache
- 0x200, // BlockSize
- 0, // IoAlign
- 0 // LastBlock
- },
- { // EraseBlock
- EFI_ERASE_BLOCK_PROTOCOL_REVISION,
- 1,
- SdEraseBlocks
- },
- { // DiskInfo
- EFI_DISK_INFO_SD_MMC_INTERFACE_GUID,
- SdDiskInfoInquiry,
- SdDiskInfoIdentify,
- SdDiskInfoSenseData,
- SdDiskInfoWhichIde
- },
- { // Queue
- NULL,
- NULL
- },
- { // Csd
- 0,
- },
- { // Cid
- 0,
- },
- NULL, // ControllerNameTable
- { // ModelName
- 0,
- },
- NULL // Private
-};
-
-/**
- Decode and print SD CSD Register content.
-
- @param[in] Csd Pointer to SD_CSD data structure.
-
- @retval EFI_SUCCESS The function completed successfully
-**/
-EFI_STATUS
-DumpCsd (
- IN SD_CSD *Csd
- )
-{
- SD_CSD2 *Csd2;
-
- DEBUG ((DEBUG_INFO, "== Dump Sd Csd Register==\n"));
- DEBUG ((DEBUG_INFO, " CSD structure 0x%x\n", Csd->CsdStructure));
- 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));
- if (Csd->CsdStructure == 0) {
- 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));
- } else {
- Csd2 = (SD_CSD2 *)(VOID *)Csd;
- DEBUG ((DEBUG_INFO, " Device size 0x%x\n", Csd2->CSizeLow | (Csd->CSizeHigh << 16)));
- }
-
- DEBUG ((DEBUG_INFO, " Erase sector size 0x%x\n", Csd->SectorSize));
- DEBUG ((DEBUG_INFO, " Erase single block enable 0x%x\n", Csd->EraseBlkEn));
- 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, " 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, " 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));
-
- return EFI_SUCCESS;
-}
-
-/**
- Get SD device model name.
-
- @param[in, out] Device The pointer to the SD_DEVICE data structure.
- @param[in] Cid Pointer to SD_CID data structure.
-
- @retval EFI_SUCCESS The function completed successfully
-
-**/
-EFI_STATUS
-GetSdModelName (
- IN OUT SD_DEVICE *Device,
- IN SD_CID *Cid
- )
-{
- CHAR8 String[SD_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 user area partition in the SD device.
-
- @param[in] Device The pointer to the SD_DEVICE data structure.
-
- @retval EFI_SUCCESS The user area partition in the SD device is successfully identified.
- @return Others Some error occurs when identifying the user area.
-
-**/
-EFI_STATUS
-DiscoverUserArea (
- IN SD_DEVICE *Device
- )
-{
- EFI_STATUS Status;
- SD_CSD *Csd;
- SD_CSD2 *Csd2;
- SD_CID *Cid;
- UINT64 Capacity;
- UINT32 DevStatus;
- UINT16 Rca;
- UINT32 CSize;
- UINT32 CSizeMul;
- UINT32 ReadBlLen;
-
- //
- // Deselect the device to force it enter stby mode.
- // Note here we don't judge return status as some SD devices return
- // error but the state has been stby.
- //
- SdSelect (Device, 0);
-
- Status = SdSetRca (Device, &Rca);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "DiscoverUserArea(): Assign new Rca = 0x%x fails with %r\n", Rca, Status));
- return Status;
- }
-
- Csd = &Device->Csd;
- Status = SdGetCsd (Device, Rca, Csd);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- DumpCsd (Csd);
-
- Cid = &Device->Cid;
- Status = SdGetCid (Device, Rca, Cid);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- GetSdModelName (Device, Cid);
-
- Status = SdSelect (Device, Rca);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "DiscoverUserArea(): Reselect the device 0x%x fails with %r\n", Rca, Status));
- return Status;
- }
-
- Status = SdSendStatus (Device, Rca, &DevStatus);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Csd->CsdStructure == 0) {
- Device->SectorAddressing = FALSE;
- CSize = (Csd->CSizeHigh << 2 | Csd->CSizeLow) + 1;
- CSizeMul = (1 << (Csd->CSizeMul + 2));
- ReadBlLen = (1 << (Csd->ReadBlLen));
- Capacity = MultU64x32 (MultU64x32 ((UINT64)CSize, CSizeMul), ReadBlLen);
- } else {
- Device->SectorAddressing = TRUE;
- Csd2 = (SD_CSD2 *)(VOID *)Csd;
- CSize = (Csd2->CSizeHigh << 16 | Csd2->CSizeLow) + 1;
- Capacity = MultU64x32 ((UINT64)CSize, SIZE_512KB);
- }
-
- Device->BlockIo.Media = &Device->BlockMedia;
- Device->BlockIo2.Media = &Device->BlockMedia;
- Device->BlockMedia.IoAlign = Device->Private->PassThru->IoAlign;
- Device->BlockMedia.BlockSize = 0x200;
- Device->BlockMedia.LastBlock = 0x00;
- Device->BlockMedia.RemovableMedia = TRUE;
- Device->BlockMedia.MediaPresent = TRUE;
- Device->BlockMedia.LogicalPartition = FALSE;
- Device->BlockMedia.LastBlock = DivU64x32 (Capacity, Device->BlockMedia.BlockSize) - 1;
-
- if (Csd->EraseBlkEn) {
- Device->EraseBlock.EraseLengthGranularity = 1;
- } else {
- Device->EraseBlock.EraseLengthGranularity = (Csd->SectorSize + 1) * (1 << (Csd->WriteBlLen - 9));
- }
-
- return Status;
-}
-
-/**
- Scan SD Bus to discover the device.
-
- @param[in] Private The SD driver private data structure.
- @param[in] Slot The slot number to check device present.
-
- @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
-DiscoverSdDevice (
- IN SD_DRIVER_PRIVATE_DATA *Private,
- IN UINT8 Slot
- )
-{
- EFI_STATUS Status;
- SD_DEVICE *Device;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
- EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
- EFI_HANDLE DeviceHandle;
- EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
-
- Device = NULL;
- DevicePath = NULL;
- NewDevicePath = NULL;
- RemainingDevicePath = NULL;
- PassThru = Private->PassThru;
-
- //
- // Build Device Path
- //
- Status = PassThru->BuildDevicePath (
- PassThru,
- Slot,
- &DevicePath
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (DevicePath->SubType != MSG_SD_DP) {
- Status = EFI_UNSUPPORTED;
- goto Error;
- }
-
- NewDevicePath = AppendDevicePathNode (
- Private->ParentDevicePath,
- DevicePath
- );
-
- if (NewDevicePath == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Error;
- }
-
- DeviceHandle = NULL;
- RemainingDevicePath = NewDevicePath;
- Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);
- if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd (RemainingDevicePath)) {
- //
- // The device has been started, directly return to fast boot.
- //
- Status = EFI_ALREADY_STARTED;
- goto Error;
- }
-
- //
- // Allocate buffer to store SD_DEVICE private data.
- //
- Device = AllocateCopyPool (sizeof (SD_DEVICE), &mSdDeviceTemplate);
- if (Device == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Error;
- }
-
- Device->DevicePath = NewDevicePath;
- Device->Slot = Slot;
- Device->Private = Private;
- InitializeListHead (&Device->Queue);
-
- //
- // Expose user area in the Sd memory card to upper layer.
- //
- Status = DiscoverUserArea (Device);
- if (EFI_ERROR (Status)) {
- goto Error;
- }
-
- Device->ControllerNameTable = NULL;
- AddUnicodeString2 (
- "eng",
- gSdDxeComponentName.SupportedLanguages,
- &Device->ControllerNameTable,
- Device->ModelName,
- TRUE
- );
- AddUnicodeString2 (
- "en",
- gSdDxeComponentName2.SupportedLanguages,
- &Device->ControllerNameTable,
- Device->ModelName,
- FALSE
- );
-
- Status = gBS->InstallMultipleProtocolInterfaces (
- &Device->Handle,
- &gEfiDevicePathProtocolGuid,
- Device->DevicePath,
- &gEfiBlockIoProtocolGuid,
- &Device->BlockIo,
- &gEfiBlockIo2ProtocolGuid,
- &Device->BlockIo2,
- &gEfiEraseBlockProtocolGuid,
- &Device->EraseBlock,
- &gEfiDiskInfoProtocolGuid,
- &Device->DiskInfo,
- NULL
- );
-
- if (!EFI_ERROR (Status)) {
- gBS->OpenProtocol (
- Private->Controller,
- &gEfiSdMmcPassThruProtocolGuid,
- (VOID **)&(Private->PassThru),
- Private->DriverBindingHandle,
- Device->Handle,
- EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
- );
- }
-
-Error:
- FreePool (DevicePath);
-
- if (EFI_ERROR (Status) && (NewDevicePath != NULL)) {
- FreePool (NewDevicePath);
- }
-
- if (EFI_ERROR (Status) && (Device != NULL)) {
- FreePool (Device);
- }
-
- 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
-SdDxeDriverBindingSupported (
- 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
-SdDxeDriverBindingStart (
- 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;
- SD_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 SD_DRIVER_PRIVATE_DATA.
- //
- if (Status != EFI_ALREADY_STARTED) {
- Private = AllocateZeroPool (sizeof (SD_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 = DiscoverSdDevice (Private, Slot);
- if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
- break;
- }
- }
- } else if (!IsDevicePathEnd (RemainingDevicePath)) {
- Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);
- if (!EFI_ERROR (Status)) {
- Status = DiscoverSdDevice (Private, Slot);
- }
- }
-
-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
-SdDxeDriverBindingStop (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE Controller,
- IN UINTN NumberOfChildren,
- IN EFI_HANDLE *ChildHandleBuffer
- )
-{
- EFI_STATUS Status;
- BOOLEAN AllChildrenStopped;
- UINTN Index;
- SD_DRIVER_PRIVATE_DATA *Private;
- SD_DEVICE *Device;
- EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
- EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
- EFI_BLOCK_IO_PROTOCOL *BlockIo;
- LIST_ENTRY *Link;
- LIST_ENTRY *NextLink;
- SD_REQUEST *Request;
- EFI_TPL OldTpl;
-
- 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;
- }
-
- 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++) {
- BlockIo = NULL;
- BlockIo2 = NULL;
- 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) {
- Device = SD_DEVICE_DATA_FROM_BLKIO (BlockIo);
- } else {
- ASSERT (BlockIo2 != NULL);
- Device = SD_DEVICE_DATA_FROM_BLKIO2 (BlockIo2);
- }
-
- //
- // Free all on-going async tasks.
- //
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
- for (Link = GetFirstNode (&Device->Queue);
- !IsNull (&Device->Queue, Link);
- Link = NextLink)
- {
- NextLink = GetNextNode (&Device->Queue, Link);
- RemoveEntryList (Link);
-
- Request = SD_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);
-
- //
- // Close the child handle
- //
- Status = gBS->CloseProtocol (
- Controller,
- &gEfiSdMmcPassThruProtocolGuid,
- This->DriverBindingHandle,
- ChildHandleBuffer[Index]
- );
-
- Status = gBS->UninstallMultipleProtocolInterfaces (
- ChildHandleBuffer[Index],
- &gEfiDevicePathProtocolGuid,
- Device->DevicePath,
- &gEfiBlockIoProtocolGuid,
- &Device->BlockIo,
- &gEfiBlockIo2ProtocolGuid,
- &Device->BlockIo2,
- &gEfiEraseBlockProtocolGuid,
- &Device->EraseBlock,
- &gEfiDiskInfoProtocolGuid,
- &Device->DiskInfo,
- NULL
- );
- if (EFI_ERROR (Status)) {
- AllChildrenStopped = FALSE;
- gBS->OpenProtocol (
- Controller,
- &gEfiSdMmcPassThruProtocolGuid,
- (VOID **)&PassThru,
- This->DriverBindingHandle,
- ChildHandleBuffer[Index],
- EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
- );
- } else {
- FreePool (Device->DevicePath);
- FreeUnicodeStringTable (Device->ControllerNameTable);
- FreePool (Device);
- }
- }
-
- if (!AllChildrenStopped) {
- return EFI_DEVICE_ERROR;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- The user Entry Point for module SdDxe. 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
-InitializeSdDxe (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
-
- //
- // Install driver model protocol(s).
- //
- Status = EfiLibInstallDriverBindingComponentName2 (
- ImageHandle,
- SystemTable,
- &gSdDxeDriverBinding,
- ImageHandle,
- &gSdDxeComponentName,
- &gSdDxeComponentName2
- );
- ASSERT_EFI_ERROR (Status);
-
- return Status;
-}
+/** @file + The SdDxe driver is used to manage the SD memory card device. + + It produces BlockIo and BlockIo2 protocols to allow upper layer + access the SD memory card device. + + Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SdDxe.h" + +// +// SdDxe Driver Binding Protocol Instance +// +EFI_DRIVER_BINDING_PROTOCOL gSdDxeDriverBinding = { + SdDxeDriverBindingSupported, + SdDxeDriverBindingStart, + SdDxeDriverBindingStop, + 0x10, + NULL, + NULL +}; + +// +// Template for SD_DEVICE data structure. +// +SD_DEVICE mSdDeviceTemplate = { + SD_DEVICE_SIGNATURE, // Signature + NULL, // Handle + NULL, // DevicePath + 0xFF, // Slot + FALSE, // SectorAddressing + { // BlockIo + EFI_BLOCK_IO_PROTOCOL_REVISION, + NULL, + SdReset, + SdReadBlocks, + SdWriteBlocks, + SdFlushBlocks + }, + { // BlockIo2 + NULL, + SdResetEx, + SdReadBlocksEx, + SdWriteBlocksEx, + SdFlushBlocksEx + }, + { // BlockMedia + 0, // MediaId + FALSE, // RemovableMedia + TRUE, // MediaPresent + FALSE, // LogicPartition + FALSE, // ReadOnly + FALSE, // WritingCache + 0x200, // BlockSize + 0, // IoAlign + 0 // LastBlock + }, + { // EraseBlock + EFI_ERASE_BLOCK_PROTOCOL_REVISION, + 1, + SdEraseBlocks + }, + { // DiskInfo + EFI_DISK_INFO_SD_MMC_INTERFACE_GUID, + SdDiskInfoInquiry, + SdDiskInfoIdentify, + SdDiskInfoSenseData, + SdDiskInfoWhichIde + }, + { // Queue + NULL, + NULL + }, + { // Csd + 0, + }, + { // Cid + 0, + }, + NULL, // ControllerNameTable + { // ModelName + 0, + }, + NULL // Private +}; + +/** + Decode and print SD CSD Register content. + + @param[in] Csd Pointer to SD_CSD data structure. + + @retval EFI_SUCCESS The function completed successfully +**/ +EFI_STATUS +DumpCsd ( + IN SD_CSD *Csd + ) +{ + SD_CSD2 *Csd2; + + DEBUG ((DEBUG_INFO, "== Dump Sd Csd Register==\n")); + DEBUG ((DEBUG_INFO, " CSD structure 0x%x\n", Csd->CsdStructure)); + 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)); + if (Csd->CsdStructure == 0) { + 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)); + } else { + Csd2 = (SD_CSD2 *)(VOID *)Csd; + DEBUG ((DEBUG_INFO, " Device size 0x%x\n", Csd2->CSizeLow | (Csd->CSizeHigh << 16))); + } + + DEBUG ((DEBUG_INFO, " Erase sector size 0x%x\n", Csd->SectorSize)); + DEBUG ((DEBUG_INFO, " Erase single block enable 0x%x\n", Csd->EraseBlkEn)); + 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, " 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, " 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)); + + return EFI_SUCCESS; +} + +/** + Get SD device model name. + + @param[in, out] Device The pointer to the SD_DEVICE data structure. + @param[in] Cid Pointer to SD_CID data structure. + + @retval EFI_SUCCESS The function completed successfully + +**/ +EFI_STATUS +GetSdModelName ( + IN OUT SD_DEVICE *Device, + IN SD_CID *Cid + ) +{ + CHAR8 String[SD_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 user area partition in the SD device. + + @param[in] Device The pointer to the SD_DEVICE data structure. + + @retval EFI_SUCCESS The user area partition in the SD device is successfully identified. + @return Others Some error occurs when identifying the user area. + +**/ +EFI_STATUS +DiscoverUserArea ( + IN SD_DEVICE *Device + ) +{ + EFI_STATUS Status; + SD_CSD *Csd; + SD_CSD2 *Csd2; + SD_CID *Cid; + UINT64 Capacity; + UINT32 DevStatus; + UINT16 Rca; + UINT32 CSize; + UINT32 CSizeMul; + UINT32 ReadBlLen; + + // + // Deselect the device to force it enter stby mode. + // Note here we don't judge return status as some SD devices return + // error but the state has been stby. + // + SdSelect (Device, 0); + + Status = SdSetRca (Device, &Rca); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "DiscoverUserArea(): Assign new Rca = 0x%x fails with %r\n", Rca, Status)); + return Status; + } + + Csd = &Device->Csd; + Status = SdGetCsd (Device, Rca, Csd); + if (EFI_ERROR (Status)) { + return Status; + } + + DumpCsd (Csd); + + Cid = &Device->Cid; + Status = SdGetCid (Device, Rca, Cid); + if (EFI_ERROR (Status)) { + return Status; + } + + GetSdModelName (Device, Cid); + + Status = SdSelect (Device, Rca); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "DiscoverUserArea(): Reselect the device 0x%x fails with %r\n", Rca, Status)); + return Status; + } + + Status = SdSendStatus (Device, Rca, &DevStatus); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Csd->CsdStructure == 0) { + Device->SectorAddressing = FALSE; + CSize = (Csd->CSizeHigh << 2 | Csd->CSizeLow) + 1; + CSizeMul = (1 << (Csd->CSizeMul + 2)); + ReadBlLen = (1 << (Csd->ReadBlLen)); + Capacity = MultU64x32 (MultU64x32 ((UINT64)CSize, CSizeMul), ReadBlLen); + } else { + Device->SectorAddressing = TRUE; + Csd2 = (SD_CSD2 *)(VOID *)Csd; + CSize = (Csd2->CSizeHigh << 16 | Csd2->CSizeLow) + 1; + Capacity = MultU64x32 ((UINT64)CSize, SIZE_512KB); + } + + Device->BlockIo.Media = &Device->BlockMedia; + Device->BlockIo2.Media = &Device->BlockMedia; + Device->BlockMedia.IoAlign = Device->Private->PassThru->IoAlign; + Device->BlockMedia.BlockSize = 0x200; + Device->BlockMedia.LastBlock = 0x00; + Device->BlockMedia.RemovableMedia = TRUE; + Device->BlockMedia.MediaPresent = TRUE; + Device->BlockMedia.LogicalPartition = FALSE; + Device->BlockMedia.LastBlock = DivU64x32 (Capacity, Device->BlockMedia.BlockSize) - 1; + + if (Csd->EraseBlkEn) { + Device->EraseBlock.EraseLengthGranularity = 1; + } else { + Device->EraseBlock.EraseLengthGranularity = (Csd->SectorSize + 1) * (1 << (Csd->WriteBlLen - 9)); + } + + return Status; +} + +/** + Scan SD Bus to discover the device. + + @param[in] Private The SD driver private data structure. + @param[in] Slot The slot number to check device present. + + @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 +DiscoverSdDevice ( + IN SD_DRIVER_PRIVATE_DATA *Private, + IN UINT8 Slot + ) +{ + EFI_STATUS Status; + SD_DEVICE *Device; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; + EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath; + EFI_HANDLE DeviceHandle; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + + Device = NULL; + DevicePath = NULL; + NewDevicePath = NULL; + RemainingDevicePath = NULL; + PassThru = Private->PassThru; + + // + // Build Device Path + // + Status = PassThru->BuildDevicePath ( + PassThru, + Slot, + &DevicePath + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (DevicePath->SubType != MSG_SD_DP) { + Status = EFI_UNSUPPORTED; + goto Error; + } + + NewDevicePath = AppendDevicePathNode ( + Private->ParentDevicePath, + DevicePath + ); + + if (NewDevicePath == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + DeviceHandle = NULL; + RemainingDevicePath = NewDevicePath; + Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle); + if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd (RemainingDevicePath)) { + // + // The device has been started, directly return to fast boot. + // + Status = EFI_ALREADY_STARTED; + goto Error; + } + + // + // Allocate buffer to store SD_DEVICE private data. + // + Device = AllocateCopyPool (sizeof (SD_DEVICE), &mSdDeviceTemplate); + if (Device == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + Device->DevicePath = NewDevicePath; + Device->Slot = Slot; + Device->Private = Private; + InitializeListHead (&Device->Queue); + + // + // Expose user area in the Sd memory card to upper layer. + // + Status = DiscoverUserArea (Device); + if (EFI_ERROR (Status)) { + goto Error; + } + + Device->ControllerNameTable = NULL; + AddUnicodeString2 ( + "eng", + gSdDxeComponentName.SupportedLanguages, + &Device->ControllerNameTable, + Device->ModelName, + TRUE + ); + AddUnicodeString2 ( + "en", + gSdDxeComponentName2.SupportedLanguages, + &Device->ControllerNameTable, + Device->ModelName, + FALSE + ); + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Device->Handle, + &gEfiDevicePathProtocolGuid, + Device->DevicePath, + &gEfiBlockIoProtocolGuid, + &Device->BlockIo, + &gEfiBlockIo2ProtocolGuid, + &Device->BlockIo2, + &gEfiEraseBlockProtocolGuid, + &Device->EraseBlock, + &gEfiDiskInfoProtocolGuid, + &Device->DiskInfo, + NULL + ); + + if (!EFI_ERROR (Status)) { + gBS->OpenProtocol ( + Private->Controller, + &gEfiSdMmcPassThruProtocolGuid, + (VOID **)&(Private->PassThru), + Private->DriverBindingHandle, + Device->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + } + +Error: + FreePool (DevicePath); + + if (EFI_ERROR (Status) && (NewDevicePath != NULL)) { + FreePool (NewDevicePath); + } + + if (EFI_ERROR (Status) && (Device != NULL)) { + FreePool (Device); + } + + 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 +SdDxeDriverBindingSupported ( + 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 +SdDxeDriverBindingStart ( + 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; + SD_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 SD_DRIVER_PRIVATE_DATA. + // + if (Status != EFI_ALREADY_STARTED) { + Private = AllocateZeroPool (sizeof (SD_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 = DiscoverSdDevice (Private, Slot); + if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) { + break; + } + } + } else if (!IsDevicePathEnd (RemainingDevicePath)) { + Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot); + if (!EFI_ERROR (Status)) { + Status = DiscoverSdDevice (Private, Slot); + } + } + +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 +SdDxeDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + BOOLEAN AllChildrenStopped; + UINTN Index; + SD_DRIVER_PRIVATE_DATA *Private; + SD_DEVICE *Device; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + EFI_BLOCK_IO2_PROTOCOL *BlockIo2; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + LIST_ENTRY *Link; + LIST_ENTRY *NextLink; + SD_REQUEST *Request; + EFI_TPL OldTpl; + + 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; + } + + 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++) { + BlockIo = NULL; + BlockIo2 = NULL; + 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) { + Device = SD_DEVICE_DATA_FROM_BLKIO (BlockIo); + } else { + ASSERT (BlockIo2 != NULL); + Device = SD_DEVICE_DATA_FROM_BLKIO2 (BlockIo2); + } + + // + // Free all on-going async tasks. + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + for (Link = GetFirstNode (&Device->Queue); + !IsNull (&Device->Queue, Link); + Link = NextLink) + { + NextLink = GetNextNode (&Device->Queue, Link); + RemoveEntryList (Link); + + Request = SD_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); + + // + // Close the child handle + // + Status = gBS->CloseProtocol ( + Controller, + &gEfiSdMmcPassThruProtocolGuid, + This->DriverBindingHandle, + ChildHandleBuffer[Index] + ); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gEfiDevicePathProtocolGuid, + Device->DevicePath, + &gEfiBlockIoProtocolGuid, + &Device->BlockIo, + &gEfiBlockIo2ProtocolGuid, + &Device->BlockIo2, + &gEfiEraseBlockProtocolGuid, + &Device->EraseBlock, + &gEfiDiskInfoProtocolGuid, + &Device->DiskInfo, + NULL + ); + if (EFI_ERROR (Status)) { + AllChildrenStopped = FALSE; + gBS->OpenProtocol ( + Controller, + &gEfiSdMmcPassThruProtocolGuid, + (VOID **)&PassThru, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + } else { + FreePool (Device->DevicePath); + FreeUnicodeStringTable (Device->ControllerNameTable); + FreePool (Device); + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + The user Entry Point for module SdDxe. 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 +InitializeSdDxe ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Install driver model protocol(s). + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gSdDxeDriverBinding, + ImageHandle, + &gSdDxeComponentName, + &gSdDxeComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h index 8d95f278cd..78f46a4867 100644 --- a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h +++ b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h @@ -1,474 +1,474 @@ -/** @file
- Header file for SdDxe 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 _SD_DXE_H_
-#define _SD_DXE_H_
-
-#include <Uefi.h>
-#include <IndustryStandard/Sd.h>
-
-#include <Protocol/SdMmcPassThru.h>
-#include <Protocol/BlockIo.h>
-#include <Protocol/BlockIo2.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 "SdBlockIo.h"
-#include "SdDiskInfo.h"
-
-//
-// Global Variables
-//
-extern EFI_DRIVER_BINDING_PROTOCOL gSdDxeDriverBinding;
-extern EFI_COMPONENT_NAME_PROTOCOL gSdDxeComponentName;
-extern EFI_COMPONENT_NAME2_PROTOCOL gSdDxeComponentName2;
-
-#define SD_DEVICE_SIGNATURE SIGNATURE_32 ('S', 'D', 't', 'f')
-
-#define SD_DEVICE_DATA_FROM_BLKIO(a) \
- CR(a, SD_DEVICE, BlockIo, SD_DEVICE_SIGNATURE)
-
-#define SD_DEVICE_DATA_FROM_BLKIO2(a) \
- CR(a, SD_DEVICE, BlockIo2, SD_DEVICE_SIGNATURE)
-
-#define SD_DEVICE_DATA_FROM_ERASEBLK(a) \
- CR(a, SD_DEVICE, EraseBlock, SD_DEVICE_SIGNATURE)
-
-#define SD_DEVICE_DATA_FROM_DISKINFO(a) \
- CR(a, SD_DEVICE, DiskInfo, SD_DEVICE_SIGNATURE)
-
-//
-// Take 2.5 seconds as generic time out value, 1 microsecond as unit.
-//
-#define SD_GENERIC_TIMEOUT 2500 * 1000
-
-#define SD_REQUEST_SIGNATURE SIGNATURE_32 ('S', 'D', 'R', 'E')
-
-#define SD_MODEL_NAME_MAX_LEN 32
-
-typedef struct _SD_DEVICE SD_DEVICE;
-typedef struct _SD_DRIVER_PRIVATE_DATA SD_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;
-} SD_REQUEST;
-
-#define SD_REQUEST_FROM_LINK(a) \
- CR(a, SD_REQUEST, Link, SD_REQUEST_SIGNATURE)
-
-struct _SD_DEVICE {
- UINT32 Signature;
- EFI_HANDLE Handle;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- UINT8 Slot;
- BOOLEAN SectorAddressing;
- EFI_BLOCK_IO_PROTOCOL BlockIo;
- EFI_BLOCK_IO2_PROTOCOL BlockIo2;
- EFI_BLOCK_IO_MEDIA BlockMedia;
- EFI_ERASE_BLOCK_PROTOCOL EraseBlock;
- EFI_DISK_INFO_PROTOCOL DiskInfo;
-
- LIST_ENTRY Queue;
-
- SD_CSD Csd;
- SD_CID Cid;
- 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[SD_MODEL_NAME_MAX_LEN];
- SD_DRIVER_PRIVATE_DATA *Private;
-};
-
-//
-// SD DXE driver private data structure
-//
-struct _SD_DRIVER_PRIVATE_DATA {
- EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
- EFI_HANDLE Controller;
- EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
- EFI_HANDLE DriverBindingHandle;
-};
-
-/**
- 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
-SdDxeDriverBindingSupported (
- 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
-SdDxeDriverBindingStart (
- 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
-SdDxeDriverBindingStop (
- 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
-SdDxeComponentNameGetDriverName (
- 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
-SdDxeComponentNameGetControllerName (
- IN EFI_COMPONENT_NAME_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_HANDLE ChildHandle OPTIONAL,
- IN CHAR8 *Language,
- OUT CHAR16 **ControllerName
- );
-
-/**
- Send command SET_RELATIVE_ADDRESS to the device to set the device address.
-
- @param[in] Device A pointer to the SD_DEVICE instance.
- @param[out] Rca The relative device address to assign.
-
- @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
-SdSetRca (
- IN SD_DEVICE *Device,
- OUT UINT16 *Rca
- );
-
-/**
- Send command SELECT to the device to select/deselect the device.
-
- @param[in] Device A pointer to the SD_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
-SdSelect (
- IN SD_DEVICE *Device,
- IN UINT16 Rca
- );
-
-/**
- Send command SEND_STATUS to the device to get device status.
-
- @param[in] Device A pointer to the SD_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
-SdSendStatus (
- IN SD_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 SD_DEVICE instance.
- @param[in] Rca The relative device address to use.
- @param[out] Csd The buffer to store the SD_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
-SdGetCsd (
- IN SD_DEVICE *Device,
- IN UINT16 Rca,
- OUT SD_CSD *Csd
- );
-
-/**
- Send command SEND_CID to the device to get the CID register data.
-
- @param[in] Device A pointer to the SD_DEVICE instance.
- @param[in] Rca The relative device address to use.
- @param[out] Cid The buffer to store the SD_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
-SdGetCid (
- IN SD_DEVICE *Device,
- IN UINT16 Rca,
- OUT SD_CID *Cid
- );
-
-#endif
+/** @file + Header file for SdDxe 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 _SD_DXE_H_ +#define _SD_DXE_H_ + +#include <Uefi.h> +#include <IndustryStandard/Sd.h> + +#include <Protocol/SdMmcPassThru.h> +#include <Protocol/BlockIo.h> +#include <Protocol/BlockIo2.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 "SdBlockIo.h" +#include "SdDiskInfo.h" + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gSdDxeDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gSdDxeComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gSdDxeComponentName2; + +#define SD_DEVICE_SIGNATURE SIGNATURE_32 ('S', 'D', 't', 'f') + +#define SD_DEVICE_DATA_FROM_BLKIO(a) \ + CR(a, SD_DEVICE, BlockIo, SD_DEVICE_SIGNATURE) + +#define SD_DEVICE_DATA_FROM_BLKIO2(a) \ + CR(a, SD_DEVICE, BlockIo2, SD_DEVICE_SIGNATURE) + +#define SD_DEVICE_DATA_FROM_ERASEBLK(a) \ + CR(a, SD_DEVICE, EraseBlock, SD_DEVICE_SIGNATURE) + +#define SD_DEVICE_DATA_FROM_DISKINFO(a) \ + CR(a, SD_DEVICE, DiskInfo, SD_DEVICE_SIGNATURE) + +// +// Take 2.5 seconds as generic time out value, 1 microsecond as unit. +// +#define SD_GENERIC_TIMEOUT 2500 * 1000 + +#define SD_REQUEST_SIGNATURE SIGNATURE_32 ('S', 'D', 'R', 'E') + +#define SD_MODEL_NAME_MAX_LEN 32 + +typedef struct _SD_DEVICE SD_DEVICE; +typedef struct _SD_DRIVER_PRIVATE_DATA SD_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; +} SD_REQUEST; + +#define SD_REQUEST_FROM_LINK(a) \ + CR(a, SD_REQUEST, Link, SD_REQUEST_SIGNATURE) + +struct _SD_DEVICE { + UINT32 Signature; + EFI_HANDLE Handle; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINT8 Slot; + BOOLEAN SectorAddressing; + EFI_BLOCK_IO_PROTOCOL BlockIo; + EFI_BLOCK_IO2_PROTOCOL BlockIo2; + EFI_BLOCK_IO_MEDIA BlockMedia; + EFI_ERASE_BLOCK_PROTOCOL EraseBlock; + EFI_DISK_INFO_PROTOCOL DiskInfo; + + LIST_ENTRY Queue; + + SD_CSD Csd; + SD_CID Cid; + 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[SD_MODEL_NAME_MAX_LEN]; + SD_DRIVER_PRIVATE_DATA *Private; +}; + +// +// SD DXE driver private data structure +// +struct _SD_DRIVER_PRIVATE_DATA { + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + EFI_HANDLE Controller; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_HANDLE DriverBindingHandle; +}; + +/** + 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 +SdDxeDriverBindingSupported ( + 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 +SdDxeDriverBindingStart ( + 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 +SdDxeDriverBindingStop ( + 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 +SdDxeComponentNameGetDriverName ( + 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 +SdDxeComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +/** + Send command SET_RELATIVE_ADDRESS to the device to set the device address. + + @param[in] Device A pointer to the SD_DEVICE instance. + @param[out] Rca The relative device address to assign. + + @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 +SdSetRca ( + IN SD_DEVICE *Device, + OUT UINT16 *Rca + ); + +/** + Send command SELECT to the device to select/deselect the device. + + @param[in] Device A pointer to the SD_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 +SdSelect ( + IN SD_DEVICE *Device, + IN UINT16 Rca + ); + +/** + Send command SEND_STATUS to the device to get device status. + + @param[in] Device A pointer to the SD_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 +SdSendStatus ( + IN SD_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 SD_DEVICE instance. + @param[in] Rca The relative device address to use. + @param[out] Csd The buffer to store the SD_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 +SdGetCsd ( + IN SD_DEVICE *Device, + IN UINT16 Rca, + OUT SD_CSD *Csd + ); + +/** + Send command SEND_CID to the device to get the CID register data. + + @param[in] Device A pointer to the SD_DEVICE instance. + @param[in] Rca The relative device address to use. + @param[out] Cid The buffer to store the SD_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 +SdGetCid ( + IN SD_DEVICE *Device, + IN UINT16 Rca, + OUT SD_CID *Cid + ); + +#endif diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf index d620e83004..00c4743600 100644 --- a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf +++ b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf @@ -1,66 +1,66 @@ -## @file
-# SdDxe driver is used to manage the SD memory card device.
-#
-# It produces BlockIo and BlockIo2 protocols to allow upper layer
-# access the SD memory card device.
-#
-# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = SdDxe
- MODULE_UNI_FILE = SdDxe.uni
- FILE_GUID = 430AC2F7-EEC6-4093-94F7-9F825A7C1C40
- MODULE_TYPE = UEFI_DRIVER
- VERSION_STRING = 1.0
- ENTRY_POINT = InitializeSdDxe
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64 EBC
-#
-# DRIVER_BINDING = gSdDxeDriverBinding
-# COMPONENT_NAME = gSdDxeComponentName
-# COMPONENT_NAME2 = gSdDxeComponentName2
-#
-
-[Sources.common]
- ComponentName.c
- SdDxe.c
- SdDxe.h
- SdBlockIo.c
- SdBlockIo.h
- SdDiskInfo.c
- SdDiskInfo.h
-
-[Packages]
- MdePkg/MdePkg.dec
-
-[LibraryClasses]
- DevicePathLib
- UefiBootServicesTableLib
- MemoryAllocationLib
- BaseMemoryLib
- UefiLib
- BaseLib
- UefiDriverEntryPoint
- DebugLib
-
-[Protocols]
- gEfiSdMmcPassThruProtocolGuid ## TO_START
- gEfiBlockIoProtocolGuid ## BY_START
- gEfiBlockIo2ProtocolGuid ## BY_START
- gEfiEraseBlockProtocolGuid ## BY_START
- gEfiDiskInfoProtocolGuid ## BY_START
- ## TO_START
- ## BY_START
- gEfiDevicePathProtocolGuid
-
-[UserExtensions.TianoCore."ExtraFiles"]
- SdDxeExtra.uni
+## @file +# SdDxe driver is used to manage the SD memory card device. +# +# It produces BlockIo and BlockIo2 protocols to allow upper layer +# access the SD memory card device. +# +# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SdDxe + MODULE_UNI_FILE = SdDxe.uni + FILE_GUID = 430AC2F7-EEC6-4093-94F7-9F825A7C1C40 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeSdDxe + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# +# DRIVER_BINDING = gSdDxeDriverBinding +# COMPONENT_NAME = gSdDxeComponentName +# COMPONENT_NAME2 = gSdDxeComponentName2 +# + +[Sources.common] + ComponentName.c + SdDxe.c + SdDxe.h + SdBlockIo.c + SdBlockIo.h + SdDiskInfo.c + SdDiskInfo.h + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + DevicePathLib + UefiBootServicesTableLib + MemoryAllocationLib + BaseMemoryLib + UefiLib + BaseLib + UefiDriverEntryPoint + DebugLib + +[Protocols] + gEfiSdMmcPassThruProtocolGuid ## TO_START + gEfiBlockIoProtocolGuid ## BY_START + gEfiBlockIo2ProtocolGuid ## BY_START + gEfiEraseBlockProtocolGuid ## BY_START + gEfiDiskInfoProtocolGuid ## BY_START + ## TO_START + ## BY_START + gEfiDevicePathProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + SdDxeExtra.uni diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.uni b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.uni index eb8ebd5a35..a78392eb43 100644 --- a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.uni +++ b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.uni @@ -1,15 +1,15 @@ -// /** @file
-// SD memory card device driver to manage the SD memory card 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 "SD device driver to manage the SD memory card 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 and BlockIo2 protocols on the SD device."
-
+// /** @file +// SD memory card device driver to manage the SD memory card 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 "SD device driver to manage the SD memory card 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 and BlockIo2 protocols on the SD device." + diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdDxeExtra.uni b/MdeModulePkg/Bus/Sd/SdDxe/SdDxeExtra.uni index 4651ac4203..41ecac1781 100644 --- a/MdeModulePkg/Bus/Sd/SdDxe/SdDxeExtra.uni +++ b/MdeModulePkg/Bus/Sd/SdDxe/SdDxeExtra.uni @@ -1,14 +1,14 @@ -// /** @file
-// SdDxe Localized Strings and Content
-//
-// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-#string STR_PROPERTIES_MODULE_NAME
-#language en-US
-"SD Device Driver"
-
-
+// /** @file +// SdDxe Localized Strings and Content +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"SD Device Driver" + + |
