MdeModulePkg/SdMmc: Add EDKII SD/MMC stack
This stack includes: 1. Dxe phase support by: 1) SdMmcPciHcDxe driver to consume PciIo and produce SdMmcPassThru. 2) SdDxe driver to consume SdMmcPassThru to produce BlkIo1/BlkIo2. 3) EmmcDxe driver to consume SdMmcPassThru to produce BlkIo1/BlkIo2/SSP. 2. Pei phase support 1) SdBlockIoPei driver to consume SdMmcHostController Ppi and produce VirutalBlkIo1&2. 2) EmmcBlockIoPei driver to consume SdMmcHostController Ppi and produce VirutalBlkIo1&2. 3) SdMmcPciHcPei driver to produce SdMmcHostController Ppi. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Feng Tian <feng.tian@intel.com> Reviewed-by: Hao Wu <hao.a.wu@intel.com>
This commit is contained in:
617
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c
Normal file
617
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c
Normal file
@@ -0,0 +1,617 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include "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
|
||||
},
|
||||
{ // 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)) {
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
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;
|
||||
}
|
||||
|
||||
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 ((EFI_D_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);
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
377
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.h
Normal file
377
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.h
Normal file
@@ -0,0 +1,377 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#ifndef _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 <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;
|
||||
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)
|
||||
|
||||
struct _SD_TRB {
|
||||
SD_PEIM_HC_SLOT *Slot;
|
||||
UINT16 BlockSize;
|
||||
|
||||
SD_COMMAND_PACKET *Packet;
|
||||
VOID *Data;
|
||||
UINT32 DataLen;
|
||||
BOOLEAN Read;
|
||||
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
|
||||
);
|
||||
|
||||
/**
|
||||
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
|
||||
);
|
||||
|
||||
#endif
|
62
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.inf
Normal file
62
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.inf
Normal file
@@ -0,0 +1,62 @@
|
||||
## @file
|
||||
# Description file for the SD memory card Peim driver.
|
||||
#
|
||||
# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
|
||||
#
|
||||
# This program and the accompanying materials
|
||||
# are licensed and made available under the terms and conditions of the BSD License
|
||||
# which accompanies this distribution. The full text of the license may be found at
|
||||
# http://opensource.org/licenses/bsd-license.php
|
||||
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 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 IPF EBC
|
||||
#
|
||||
|
||||
[Sources]
|
||||
SdBlockIoPei.c
|
||||
SdBlockIoPei.h
|
||||
SdHci.c
|
||||
SdHci.h
|
||||
SdHcMem.c
|
||||
SdHcMem.h
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
IoLib
|
||||
TimerLib
|
||||
BaseMemoryLib
|
||||
PeimEntryPoint
|
||||
PeiServicesLib
|
||||
DebugLib
|
||||
|
||||
[Ppis]
|
||||
gEfiPeiVirtualBlockIoPpiGuid ## PRODUCES
|
||||
gEfiPeiVirtualBlockIo2PpiGuid ## PRODUCES
|
||||
gEdkiiPeiSdMmcHostControllerPpiGuid ## CONSUMES
|
||||
|
||||
[Depex]
|
||||
gEfiPeiMemoryDiscoveredPpiGuid AND gEdkiiPeiSdMmcHostControllerPpiGuid
|
||||
|
||||
[UserExtensions.TianoCore."ExtraFiles"]
|
||||
SdBlockIoPeiExtra.uni
|
||||
|
21
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.uni
Normal file
21
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.uni
Normal file
@@ -0,0 +1,21 @@
|
||||
// /** @file
|
||||
// The SdBlockIoPei driver is used to support recovery from SD memory card device.
|
||||
//
|
||||
// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
|
||||
//
|
||||
// This program and the accompanying materials
|
||||
// are licensed and made available under the terms and conditions
|
||||
// of the BSD License which accompanies this distribution. The
|
||||
// full text of the license may be found at
|
||||
// http://opensource.org/licenses/bsd-license.php
|
||||
//
|
||||
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
//
|
||||
// **/
|
||||
|
||||
|
||||
#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."
|
||||
|
21
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPeiExtra.uni
Normal file
21
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPeiExtra.uni
Normal file
@@ -0,0 +1,21 @@
|
||||
// /** @file
|
||||
// SdBlockIoPei Localized Strings and Content
|
||||
//
|
||||
// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
|
||||
//
|
||||
// This program and the accompanying materials
|
||||
// are licensed and made available under the terms and conditions
|
||||
// of the BSD License which accompanies this distribution. The
|
||||
// full text of the license may be found at
|
||||
// http://opensource.org/licenses/bsd-license.php
|
||||
//
|
||||
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
//
|
||||
// **/
|
||||
|
||||
#string STR_PROPERTIES_MODULE_NAME
|
||||
#language en-US
|
||||
"SD BlockIo Peim for Recovery"
|
||||
|
||||
|
455
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.c
Normal file
455
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.c
Normal file
@@ -0,0 +1,455 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions
|
||||
of the BSD License which accompanies this distribution. The
|
||||
full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include "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;
|
||||
EFI_STATUS Status;
|
||||
VOID *TempPtr;
|
||||
EFI_PHYSICAL_ADDRESS Address;
|
||||
|
||||
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 = PeiServicesAllocatePages (
|
||||
EfiBootServicesCode,
|
||||
Pages,
|
||||
&Address
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ZeroMem ((VOID*)(UINTN)Address, EFI_PAGES_TO_SIZE (Pages));
|
||||
|
||||
Block->Buf = (UINT8*)((UINTN)Address);
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
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 consective 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;
|
||||
}
|
||||
|
||||
/**
|
||||
Unlink the memory block from the pool's list.
|
||||
|
||||
@param Head The block list head of the memory's pool.
|
||||
@param BlockToUnlink The memory block to unlink.
|
||||
|
||||
**/
|
||||
VOID
|
||||
SdPeimUnlinkMemBlock (
|
||||
IN SD_PEIM_MEM_BLOCK *Head,
|
||||
IN SD_PEIM_MEM_BLOCK *BlockToUnlink
|
||||
)
|
||||
{
|
||||
SD_PEIM_MEM_BLOCK *Block;
|
||||
|
||||
ASSERT ((Head != NULL) && (BlockToUnlink != NULL));
|
||||
|
||||
for (Block = Head; Block != NULL; Block = Block->Next) {
|
||||
if (Block->Next == BlockToUnlink) {
|
||||
Block->Next = BlockToUnlink->Next;
|
||||
BlockToUnlink->Next = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
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.
|
||||
// SdPeimUnlinkMemBlock can't be used to unlink and free the
|
||||
// first block.
|
||||
//
|
||||
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 arry
|
||||
//
|
||||
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 ;
|
||||
}
|
61
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.h
Normal file
61
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions
|
||||
of the BSD License which accompanies this distribution. The
|
||||
full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#ifndef _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;
|
||||
UINTN BufLen; // Memory size in bytes
|
||||
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
|
||||
|
2874
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c
Normal file
2874
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c
Normal file
File diff suppressed because it is too large
Load Diff
354
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h
Normal file
354
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h
Normal file
@@ -0,0 +1,354 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php.
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#ifndef _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.
|
||||
|
||||
@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
|
||||
);
|
||||
|
||||
/**
|
||||
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
|
||||
|
Reference in New Issue
Block a user