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:
Feng Tian
2016-03-23 10:47:05 +08:00
parent 627373d7e7
commit 48555339be
52 changed files with 24405 additions and 0 deletions

View 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;
}

View 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

View 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

View 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."

View 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"

View 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 ;
}

View 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

File diff suppressed because it is too large Load Diff

View 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