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,211 @@
/** @file
UEFI Component Name(2) protocol implementation for SD/MMC host controller 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.
**/
#include "SdMmcPciHcDxe.h"
//
// EFI Component Name Protocol
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSdMmcPciHcComponentName = {
SdMmcPciHcComponentNameGetDriverName,
SdMmcPciHcComponentNameGetControllerName,
"eng"
};
//
// EFI Component Name 2 Protocol
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSdMmcPciHcComponentName2 = {
(EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SdMmcPciHcComponentNameGetDriverName,
(EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SdMmcPciHcComponentNameGetControllerName,
"en"
};
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdMmcPciHcDriverNameTable[] = {
{ "eng;en", L"Edkii Sd/Mmc Host Controller Driver" },
{ NULL , NULL }
};
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdMmcPciHcControllerNameTable[] = {
{ "eng;en", L"Edkii Sd/Mmc Host Controller" },
{ NULL , NULL }
};
/**
Retrieves a Unicode string that is the user readable name of the driver.
This function retrieves the user readable name of a driver in the form of a
Unicode string. If the driver specified by This has a user readable name in
the language specified by Language, then a pointer to the driver name is
returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
by This does not support the language specified by Language,
then EFI_UNSUPPORTED is returned.
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param Language[in] A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified
in RFC 4646 or ISO 639-2 language code format.
@param DriverName[out] A pointer to the Unicode string to return.
This Unicode string is the name of the
driver specified by This in the language
specified by Language.
@retval EFI_SUCCESS The Unicode string for the Driver specified by
This and the language specified by Language was
returned in DriverName.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER DriverName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
SdMmcPciHcComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
{
return LookupUnicodeString2 (
Language,
This->SupportedLanguages,
mSdMmcPciHcDriverNameTable,
DriverName,
(BOOLEAN)(This == &gSdMmcPciHcComponentName)
);
}
/**
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by a driver.
This function retrieves the user readable name of the controller specified by
ControllerHandle and ChildHandle in the form of a Unicode string. If the
driver specified by This has a user readable name in the language specified by
Language, then a pointer to the controller name is returned in ControllerName,
and EFI_SUCCESS is returned. If the driver specified by This is not currently
managing the controller specified by ControllerHandle and ChildHandle,
then EFI_UNSUPPORTED is returned. If the driver specified by This does not
support the language specified by Language, then EFI_UNSUPPORTED is returned.
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param ControllerHandle[in] The handle of a controller that the driver
specified by This is managing. This handle
specifies the controller whose name is to be
returned.
@param ChildHandle[in] The handle of the child controller to retrieve
the name of. This is an optional parameter that
may be NULL. It will be NULL for device
drivers. It will also be NULL for a bus drivers
that wish to retrieve the name of the bus
controller. It will not be NULL for a bus
driver that wishes to retrieve the name of a
child controller.
@param Language[in] A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified in
RFC 4646 or ISO 639-2 language code format.
@param ControllerName[out] A pointer to the Unicode string to return.
This Unicode string is the name of the
controller specified by ControllerHandle and
ChildHandle in the language specified by
Language from the point of view of the driver
specified by This.
@retval EFI_SUCCESS The Unicode string for the user readable name in
the language specified by Language for the
driver specified by This was returned in
DriverName.
@retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
EFI_HANDLE.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This is not currently
managing the controller specified by
ControllerHandle and ChildHandle.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
SdMmcPciHcComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle, OPTIONAL
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
{
EFI_STATUS Status;
if (Language == NULL || ControllerName == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// This is a device driver, so ChildHandle must be NULL.
//
if (ChildHandle != NULL) {
return EFI_UNSUPPORTED;
}
//
// Make sure this driver is currently managing ControllerHandle
//
Status = EfiTestManagedDevice (
ControllerHandle,
gSdMmcPciHcDriverBinding.DriverBindingHandle,
&gEfiPciIoProtocolGuid
);
if (EFI_ERROR (Status)) {
return Status;
}
return LookupUnicodeString2 (
Language,
This->SupportedLanguages,
mSdMmcPciHcControllerNameTable,
ControllerName,
(BOOLEAN)(This == &gSdMmcPciHcComponentName)
);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,784 @@
/** @file
Provides some data structure definitions used by the SD/MMC host controller 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.
**/
#ifndef _SD_MMC_PCI_HC_DXE_H_
#define _SD_MMC_PCI_HC_DXE_H_
#include <Uefi.h>
#include <IndustryStandard/Pci.h>
#include <IndustryStandard/Emmc.h>
#include <IndustryStandard/Sd.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiLib.h>
#include <Library/DevicePathLib.h>
#include <Protocol/DevicePath.h>
#include <Protocol/PciIo.h>
#include <Protocol/DriverBinding.h>
#include <Protocol/ComponentName.h>
#include <Protocol/ComponentName2.h>
#include <Protocol/SdMmcPassThru.h>
#include "SdMmcPciHci.h"
extern EFI_COMPONENT_NAME_PROTOCOL gSdMmcPciHcComponentName;
extern EFI_COMPONENT_NAME2_PROTOCOL gSdMmcPciHcComponentName2;
extern EFI_DRIVER_BINDING_PROTOCOL gSdMmcPciHcDriverBinding;
#define SD_MMC_HC_PRIVATE_SIGNATURE SIGNATURE_32 ('s', 'd', 't', 'f')
#define SD_MMC_HC_PRIVATE_FROM_THIS(a) \
CR(a, SD_MMC_HC_PRIVATE_DATA, PassThru, SD_MMC_HC_PRIVATE_SIGNATURE)
//
// Generic time out value, 1 microsecond as unit.
//
#define SD_MMC_HC_GENERIC_TIMEOUT 1 * 1000 * 1000
//
// SD/MMC async transfer timer interval, set by experience.
// The unit is 100us, takes 1ms as interval.
//
#define SD_MMC_HC_ASYNC_TIMER EFI_TIMER_PERIOD_MILLISECONDS(1)
//
// SD/MMC removable device enumeration timer interval, set by experience.
// The unit is 100us, takes 100ms as interval.
//
#define SD_MMC_HC_ENUM_TIMER EFI_TIMER_PERIOD_MILLISECONDS(100)
typedef enum {
UnknownCardType,
SdCardType,
SdioCardType,
MmcCardType,
EmmcCardType
} SD_MMC_CARD_TYPE;
typedef enum {
RemovableSlot,
EmbeddedSlot,
SharedBusSlot,
UnknownSlot
} EFI_SD_MMC_SLOT_TYPE;
typedef struct {
BOOLEAN Enable;
EFI_SD_MMC_SLOT_TYPE SlotType;
BOOLEAN MediaPresent;
SD_MMC_CARD_TYPE CardType;
} SD_MMC_HC_SLOT;
typedef struct {
UINTN Signature;
EFI_HANDLE ControllerHandle;
EFI_PCI_IO_PROTOCOL *PciIo;
EFI_SD_MMC_PASS_THRU_PROTOCOL PassThru;
UINT64 PciAttributes;
//
// The field is used to record the previous slot in GetNextSlot().
//
UINT8 PreviousSlot;
//
// For Non-blocking operation.
//
EFI_EVENT TimerEvent;
//
// For Sd removable device enumeration.
//
EFI_EVENT ConnectEvent;
LIST_ENTRY Queue;
SD_MMC_HC_SLOT Slot[SD_MMC_HC_MAX_SLOT];
SD_MMC_HC_SLOT_CAP Capability[SD_MMC_HC_MAX_SLOT];
UINT64 MaxCurrent[SD_MMC_HC_MAX_SLOT];
UINT32 ControllerVersion;
} SD_MMC_HC_PRIVATE_DATA;
#define SD_MMC_HC_TRB_SIG SIGNATURE_32 ('T', 'R', 'B', 'T')
//
// TRB (Transfer Request Block) contains information for the cmd request.
//
typedef struct {
UINT32 Signature;
LIST_ENTRY TrbList;
UINT8 Slot;
UINT16 BlockSize;
EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
VOID *Data;
UINT32 DataLen;
BOOLEAN Read;
EFI_PHYSICAL_ADDRESS DataPhy;
VOID *DataMap;
SD_MMC_HC_TRANSFER_MODE Mode;
EFI_EVENT Event;
BOOLEAN Started;
UINT64 Timeout;
SD_MMC_HC_ADMA_DESC_LINE *AdmaDesc;
EFI_PHYSICAL_ADDRESS AdmaDescPhy;
VOID *AdmaMap;
UINT32 AdmaPages;
SD_MMC_HC_PRIVATE_DATA *Private;
} SD_MMC_HC_TRB;
#define SD_MMC_HC_TRB_FROM_THIS(a) \
CR(a, SD_MMC_HC_TRB, TrbList, SD_MMC_HC_TRB_SIG)
//
// Task for Non-blocking mode.
//
typedef struct {
UINT32 Signature;
LIST_ENTRY Link;
UINT8 Slot;
EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
BOOLEAN IsStart;
EFI_EVENT Event;
UINT64 RetryTimes;
BOOLEAN InfiniteWait;
VOID *Map;
VOID *MapAddress;
} SD_MMC_HC_QUEUE;
//
// Prototypes
//
/**
Execute card identification procedure.
@param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
@param[in] Slot The slot number of the SD card to send the command to.
@retval EFI_SUCCESS The card is identified correctly.
@retval Others The card can't be identified.
**/
typedef
EFI_STATUS
(*CARD_TYPE_DETECT_ROUTINE) (
IN SD_MMC_HC_PRIVATE_DATA *Private,
IN UINT8 Slot
);
/**
Sends SD command to an SD card that is attached to the SD controller.
The PassThru() function sends the SD command specified by Packet to the SD card
specified by Slot.
If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.
If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.
If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER
is returned.
If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,
EFI_INVALID_PARAMETER is returned.
@param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
@param[in] Slot The slot number of the SD card to send the command to.
@param[in,out] Packet A pointer to the SD command data structure.
@param[in] Event If Event is NULL, blocking I/O is performed. If Event is
not NULL, then nonblocking I/O is performed, and Event
will be signaled when the Packet completes.
@retval EFI_SUCCESS The SD Command Packet was sent by the host.
@retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SD
command Packet.
@retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.
@retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and
OutDataBuffer are NULL.
@retval EFI_NO_MEDIA SD Device not present in the Slot.
@retval EFI_UNSUPPORTED The command described by the SD Command Packet is not
supported by the host controller.
@retval EFI_BAD_BUFFER_SIZE The InTransferLength or OutTransferLength exceeds the
limit supported by SD card ( i.e. if the number of bytes
exceed the Last LBA).
**/
EFI_STATUS
EFIAPI
SdMmcPassThruPassThru (
IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
IN UINT8 Slot,
IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
IN EFI_EVENT Event OPTIONAL
);
/**
Used to retrieve next slot numbers supported by the SD controller. The function
returns information about all available slots (populated or not-populated).
The GetNextSlot() function retrieves the next slot number on an SD controller.
If on input Slot is 0xFF, then the slot number of the first slot on the SD controller
is returned.
If Slot is a slot number that was returned on a previous call to GetNextSlot(), then
the slot number of the next slot on the SD controller is returned.
If Slot is not 0xFF and Slot was not returned on a previous call to GetNextSlot(),
EFI_INVALID_PARAMETER is returned.
If Slot is the slot number of the last slot on the SD controller, then EFI_NOT_FOUND
is returned.
@param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.
@param[in,out] Slot On input, a pointer to a slot number on the SD controller.
On output, a pointer to the next slot number on the SD controller.
An input value of 0xFF retrieves the first slot number on the SD
controller.
@retval EFI_SUCCESS The next slot number on the SD controller was returned in Slot.
@retval EFI_NOT_FOUND There are no more slots on this SD controller.
@retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a previous call
to GetNextSlot().
**/
EFI_STATUS
EFIAPI
SdMmcPassThruGetNextSlot (
IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
IN OUT UINT8 *Slot
);
/**
Used to allocate and build a device path node for an SD card on the SD controller.
The BuildDevicePath() function allocates and builds a single device node for the SD
card specified by Slot.
If the SD card specified by Slot is not present on the SD controller, then EFI_NOT_FOUND
is returned.
If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.
If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES
is returned.
Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of
DevicePath are initialized to describe the SD card specified by Slot, and EFI_SUCCESS is
returned.
@param[in] This A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.
@param[in] Slot Specifies the slot number of the SD card for which a device
path node is to be allocated and built.
@param[in,out] DevicePath A pointer to a single device path node that describes the SD
card specified by Slot. This function is responsible for
allocating the buffer DevicePath with the boot service
AllocatePool(). It is the caller's responsibility to free
DevicePath when the caller is finished with DevicePath.
@retval EFI_SUCCESS The device path node that describes the SD card specified by
Slot was allocated and returned in DevicePath.
@retval EFI_NOT_FOUND The SD card specified by Slot does not exist on the SD controller.
@retval EFI_INVALID_PARAMETER DevicePath is NULL.
@retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate DevicePath.
**/
EFI_STATUS
EFIAPI
SdMmcPassThruBuildDevicePath (
IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
IN UINT8 Slot,
IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
);
/**
This function retrieves an SD card slot number based on the input device path.
The GetSlotNumber() function retrieves slot number for the SD card specified by
the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is returned.
If DevicePath is not a device path node type that the SD Pass Thru driver supports,
EFI_UNSUPPORTED is returned.
@param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
@param[in] DevicePath A pointer to the device path node that describes a SD
card on the SD controller.
@param[out] Slot On return, points to the slot number of an SD card on
the SD controller.
@retval EFI_SUCCESS SD card slot number is returned in Slot.
@retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.
@retval EFI_UNSUPPORTED DevicePath is not a device path node type that the SD
Pass Thru driver supports.
**/
EFI_STATUS
EFIAPI
SdMmcPassThruGetSlotNumber (
IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
OUT UINT8 *Slot
);
/**
Resets an SD card that is connected to the SD controller.
The ResetDevice() function resets the SD card specified by Slot.
If this SD controller does not support a device reset operation, EFI_UNSUPPORTED is
returned.
If Slot is not in a valid slot number for this SD controller, EFI_INVALID_PARAMETER
is returned.
If the device reset operation is completed, EFI_SUCCESS is returned.
@param[in] This A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
@param[in] Slot Specifies the slot number of the SD card to be reset.
@retval EFI_SUCCESS The SD card specified by Slot was reset.
@retval EFI_UNSUPPORTED The SD controller does not support a device reset operation.
@retval EFI_INVALID_PARAMETER Slot number is invalid.
@retval EFI_NO_MEDIA SD Device not present in the Slot.
@retval EFI_DEVICE_ERROR The reset command failed due to a device error
**/
EFI_STATUS
EFIAPI
SdMmcPassThruResetDevice (
IN EFI_SD_MMC_PASS_THRU_PROTOCOL *This,
IN UINT8 Slot
);
//
// Driver model protocol interfaces
//
/**
Tests to see if this driver supports a given controller. If a child device is provided,
it further tests to see if this driver supports creating a handle for the specified child device.
This function checks to see if the driver specified by This supports the device specified by
ControllerHandle. Drivers will typically use the device path attached to
ControllerHandle and/or the services from the bus I/O abstraction attached to
ControllerHandle to determine if the driver supports ControllerHandle. This function
may be called many times during platform initialization. In order to reduce boot times, the tests
performed by this function must be very small, and take as little time as possible to execute. This
function must not change the state of any hardware devices, and this function must be aware that the
device specified by ControllerHandle may already be managed by the same driver or a
different driver. This function must match its calls to AllocatePages() with FreePages(),
AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
Since ControllerHandle may have been previously started by the same driver, if a protocol is
already in the opened state, then it must not be closed with CloseProtocol(). This is required
to guarantee the state of ControllerHandle is not modified by this function.
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param[in] ControllerHandle The handle of the controller to test. This handle
must support a protocol interface that supplies
an I/O abstraction to the driver.
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
parameter is ignored by device drivers, and is optional for bus
drivers. For bus drivers, if this parameter is not NULL, then
the bus driver must determine if the bus controller specified
by ControllerHandle and the child controller specified
by RemainingDevicePath are both supported by this
bus driver.
@retval EFI_SUCCESS The device specified by ControllerHandle and
RemainingDevicePath is supported by the driver specified by This.
@retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
RemainingDevicePath is already being managed by the driver
specified by This.
@retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
RemainingDevicePath is already being managed by a different
driver or an application that requires exclusive access.
Currently not implemented.
@retval EFI_UNSUPPORTED The device specified by ControllerHandle and
RemainingDevicePath is not supported by the driver specified by This.
**/
EFI_STATUS
EFIAPI
SdMmcPciHcDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
);
/**
Starts a device controller or a bus controller.
The Start() function is designed to be invoked from the EFI boot service ConnectController().
As a result, much of the error checking on the parameters to Start() has been moved into this
common boot service. It is legal to call Start() from other locations,
but the following calling restrictions must be followed or the system behavior will not be deterministic.
1. ControllerHandle must be a valid EFI_HANDLE.
2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
EFI_DEVICE_PATH_PROTOCOL.
3. Prior to calling Start(), the Supported() function for the driver specified by This must
have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param[in] ControllerHandle The handle of the controller to start. This handle
must support a protocol interface that supplies
an I/O abstraction to the driver.
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
parameter is ignored by device drivers, and is optional for bus
drivers. For a bus driver, if this parameter is NULL, then handles
for all the children of Controller are created by this driver.
If this parameter is not NULL and the first Device Path Node is
not the End of Device Path Node, then only the handle for the
child device specified by the first Device Path Node of
RemainingDevicePath is created by this driver.
If the first Device Path Node of RemainingDevicePath is
the End of Device Path Node, no child handle is created by this
driver.
@retval EFI_SUCCESS The device was started.
@retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
@retval Others The driver failded to start the device.
**/
EFI_STATUS
EFIAPI
SdMmcPciHcDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
);
/**
Stops a device controller or a bus controller.
The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
As a result, much of the error checking on the parameters to Stop() has been moved
into this common boot service. It is legal to call Stop() from other locations,
but the following calling restrictions must be followed or the system behavior will not be deterministic.
1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
same driver's Start() function.
2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
EFI_HANDLE. In addition, all of these handles must have been created in this driver's
Start() function, and the Start() function must have called OpenProtocol() on
ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param[in] ControllerHandle A handle to the device being stopped. The handle must
support a bus specific I/O protocol for the driver
to use to stop the device.
@param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
@param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
if NumberOfChildren is 0.
@retval EFI_SUCCESS The device was stopped.
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
**/
EFI_STATUS
EFIAPI
SdMmcPciHcDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
);
//
// EFI Component Name Functions
//
/**
Retrieves a Unicode string that is the user readable name of the driver.
This function retrieves the user readable name of a driver in the form of a
Unicode string. If the driver specified by This has a user readable name in
the language specified by Language, then a pointer to the driver name is
returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
by This does not support the language specified by Language,
then EFI_UNSUPPORTED is returned.
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param Language[in] A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified
in RFC 4646 or ISO 639-2 language code format.
@param DriverName[out] A pointer to the Unicode string to return.
This Unicode string is the name of the
driver specified by This in the language
specified by Language.
@retval EFI_SUCCESS The Unicode string for the Driver specified by
This and the language specified by Language was
returned in DriverName.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER DriverName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
SdMmcPciHcComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
);
/**
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by a driver.
This function retrieves the user readable name of the controller specified by
ControllerHandle and ChildHandle in the form of a Unicode string. If the
driver specified by This has a user readable name in the language specified by
Language, then a pointer to the controller name is returned in ControllerName,
and EFI_SUCCESS is returned. If the driver specified by This is not currently
managing the controller specified by ControllerHandle and ChildHandle,
then EFI_UNSUPPORTED is returned. If the driver specified by This does not
support the language specified by Language, then EFI_UNSUPPORTED is returned.
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param ControllerHandle[in] The handle of a controller that the driver
specified by This is managing. This handle
specifies the controller whose name is to be
returned.
@param ChildHandle[in] The handle of the child controller to retrieve
the name of. This is an optional parameter that
may be NULL. It will be NULL for device
drivers. It will also be NULL for a bus drivers
that wish to retrieve the name of the bus
controller. It will not be NULL for a bus
driver that wishes to retrieve the name of a
child controller.
@param Language[in] A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified in
RFC 4646 or ISO 639-2 language code format.
@param ControllerName[out] A pointer to the Unicode string to return.
This Unicode string is the name of the
controller specified by ControllerHandle and
ChildHandle in the language specified by
Language from the point of view of the driver
specified by This.
@retval EFI_SUCCESS The Unicode string for the user readable name in
the language specified by Language for the
driver specified by This was returned in
DriverName.
@retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
EFI_HANDLE.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This is not currently
managing the controller specified by
ControllerHandle and ChildHandle.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
SdMmcPciHcComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle, OPTIONAL
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
);
/**
Create a new TRB for the SD/MMC cmd request.
@param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
@param[in] Slot The slot number of the SD card to send the command to.
@param[in] Packet A pointer to the SD command data structure.
@param[in] Event If Event is NULL, blocking I/O is performed. If Event is
not NULL, then nonblocking I/O is performed, and Event
will be signaled when the Packet completes.
@return Created Trb or NULL.
**/
SD_MMC_HC_TRB *
SdMmcCreateTrb (
IN SD_MMC_HC_PRIVATE_DATA *Private,
IN UINT8 Slot,
IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
IN EFI_EVENT Event
);
/**
Free the resource used by the TRB.
@param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
**/
VOID
SdMmcFreeTrb (
IN SD_MMC_HC_TRB *Trb
);
/**
Check if the env is ready for execute specified TRB.
@param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
@param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
@retval EFI_SUCCESS The env is ready for TRB execution.
@retval EFI_NOT_READY The env is not ready for TRB execution.
@retval Others Some erros happen.
**/
EFI_STATUS
SdMmcCheckTrbEnv (
IN SD_MMC_HC_PRIVATE_DATA *Private,
IN SD_MMC_HC_TRB *Trb
);
/**
Wait for the env to be ready for execute specified TRB.
@param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
@param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
@retval EFI_SUCCESS The env is ready for TRB execution.
@retval EFI_TIMEOUT The env is not ready for TRB execution in time.
@retval Others Some erros happen.
**/
EFI_STATUS
SdMmcWaitTrbEnv (
IN SD_MMC_HC_PRIVATE_DATA *Private,
IN SD_MMC_HC_TRB *Trb
);
/**
Execute the specified TRB.
@param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
@param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
@retval EFI_SUCCESS The TRB is sent to host controller successfully.
@retval Others Some erros happen when sending this request to the host controller.
**/
EFI_STATUS
SdMmcExecTrb (
IN SD_MMC_HC_PRIVATE_DATA *Private,
IN SD_MMC_HC_TRB *Trb
);
/**
Check the TRB execution result.
@param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
@param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
@retval EFI_SUCCESS The TRB is executed successfully.
@retval EFI_NOT_READY The TRB is not completed for execution.
@retval Others Some erros happen when executing this request.
**/
EFI_STATUS
SdMmcCheckTrbResult (
IN SD_MMC_HC_PRIVATE_DATA *Private,
IN SD_MMC_HC_TRB *Trb
);
/**
Wait for the TRB execution result.
@param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
@param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
@retval EFI_SUCCESS The TRB is executed successfully.
@retval Others Some erros happen when executing this request.
**/
EFI_STATUS
SdMmcWaitTrbResult (
IN SD_MMC_HC_PRIVATE_DATA *Private,
IN SD_MMC_HC_TRB *Trb
);
/**
Execute EMMC device identification procedure.
Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
@param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
@param[in] Slot The slot number of the SD card to send the command to.
@retval EFI_SUCCESS There is a EMMC card.
@retval Others There is not a EMMC card.
**/
EFI_STATUS
EmmcIdentification (
IN SD_MMC_HC_PRIVATE_DATA *Private,
IN UINT8 Slot
);
/**
Execute EMMC device identification procedure.
Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
@param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
@param[in] Slot The slot number of the SD card to send the command to.
@retval EFI_SUCCESS There is a EMMC card.
@retval Others There is not a EMMC card.
**/
EFI_STATUS
SdCardIdentification (
IN SD_MMC_HC_PRIVATE_DATA *Private,
IN UINT8 Slot
);
#endif

View File

@ -0,0 +1,72 @@
## @file
# SdMmcPciHcDxe driver is used to manage those host controllers which comply with SD
# Host Controller Simplified Specifiction version 3.0.
#
# It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC/eMMC cmds
# to specified devices from upper layer.
#
# 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 = SdMmcPciHcDxe
MODULE_UNI_FILE = SdMmcPciHcDxe.uni
FILE_GUID = 8E325979-3FE1-4927-AAE2-8F5C4BD2AF0D
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = InitializeSdMmcPciHcDxe
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
# DRIVER_BINDING = gSdMmcPciHcDxeDriverBinding
# COMPONENT_NAME = gSdMmcPciHcDxeComponentName
# COMPONENT_NAME2 = gSdMmcPciHcDxeComponentName2
#
#
[Sources]
SdMmcPciHcDxe.h
SdMmcPciHcDxe.c
EmmcDevice.c
SdDevice.c
SdMmcPciHci.h
SdMmcPciHci.c
ComponentName.c
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
DevicePathLib
UefiBootServicesTableLib
UefiRuntimeServicesTableLib
MemoryAllocationLib
BaseMemoryLib
UefiLib
BaseLib
UefiDriverEntryPoint
DebugLib
[Protocols]
gEfiDevicePathProtocolGuid ## TO_START
gEfiPciIoProtocolGuid ## TO_START
gEfiSdMmcPassThruProtocolGuid ## BY_START
# [Event]
# EVENT_TYPE_PERIODIC_TIMER ## SOMETIMES_CONSUMES
[UserExtensions.TianoCore."ExtraFiles"]
SdMmcPciHcDxeExtra.uni

View File

@ -0,0 +1,23 @@
// /** @file
// SdMmcPciHcDxe driver is used to manage those host controllers which comply with SD
// Host Controller Simplified Specifiction version 3.0.
//
// It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC/eMMC cmds
// to specified devices from upper layer.
//
// 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 "SD/MMC Pci Host Controller driver to manage SD/MMC host controllers"
#string STR_MODULE_DESCRIPTION #language en-US "This driver follows the UEFI driver model and produces SD/MMC Pass Thru protocol for upper layer bus driver."

View File

@ -0,0 +1,19 @@
// /** @file
// SdMmcPciHcDxe 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/MMC Pci Host Controller Driver"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,546 @@
/** @file
Provides some data structure definitions used by the SD/MMC host controller 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.
**/
#ifndef _SD_MMC_PCI_HCI_H_
#define _SD_MMC_PCI_HCI_H_
//
// SD Host Controller SlotInfo Register Offset
//
#define SD_MMC_HC_SLOT_OFFSET 0x40
#define SD_MMC_HC_MAX_SLOT 6
//
// SD Host Controller MMIO Register Offset
//
#define SD_MMC_HC_SDMA_ADDR 0x00
#define SD_MMC_HC_ARG2 0x00
#define SD_MMC_HC_BLK_SIZE 0x04
#define SD_MMC_HC_BLK_COUNT 0x06
#define SD_MMC_HC_ARG1 0x08
#define SD_MMC_HC_TRANS_MOD 0x0C
#define SD_MMC_HC_COMMAND 0x0E
#define SD_MMC_HC_RESPONSE 0x10
#define SD_MMC_HC_BUF_DAT_PORT 0x20
#define SD_MMC_HC_PRESENT_STATE 0x24
#define SD_MMC_HC_HOST_CTRL1 0x28
#define SD_MMC_HC_POWER_CTRL 0x29
#define SD_MMC_HC_BLK_GAP_CTRL 0x2A
#define SD_MMC_HC_WAKEUP_CTRL 0x2B
#define SD_MMC_HC_CLOCK_CTRL 0x2C
#define SD_MMC_HC_TIMEOUT_CTRL 0x2E
#define SD_MMC_HC_SW_RST 0x2F
#define SD_MMC_HC_NOR_INT_STS 0x30
#define SD_MMC_HC_ERR_INT_STS 0x32
#define SD_MMC_HC_NOR_INT_STS_EN 0x34
#define SD_MMC_HC_ERR_INT_STS_EN 0x36
#define SD_MMC_HC_NOR_INT_SIG_EN 0x38
#define SD_MMC_HC_ERR_INT_SIG_EN 0x3A
#define SD_MMC_HC_AUTO_CMD_ERR_STS 0x3C
#define SD_MMC_HC_HOST_CTRL2 0x3E
#define SD_MMC_HC_CAP 0x40
#define SD_MMC_HC_MAX_CURRENT_CAP 0x48
#define SD_MMC_HC_FORCE_EVT_AUTO_CMD 0x50
#define SD_MMC_HC_FORCE_EVT_ERR_INT 0x52
#define SD_MMC_HC_ADMA_ERR_STS 0x54
#define SD_MMC_HC_ADMA_SYS_ADDR 0x58
#define SD_MMC_HC_PRESET_VAL 0x60
#define SD_MMC_HC_SHARED_BUS_CTRL 0xE0
#define SD_MMC_HC_SLOT_INT_STS 0xFC
#define SD_MMC_HC_CTRL_VER 0xFE
//
// The transfer modes supported by SD Host Controller
// Simplified Spec 3.0 Table 1-2
//
typedef enum {
SdMmcNoData,
SdMmcPioMode,
SdMmcSdmaMode,
SdMmcAdmaMode
} SD_MMC_HC_TRANSFER_MODE;
//
// The maximum data length of each descriptor line
//
#define ADMA_MAX_DATA_PER_LINE 0x10000
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_MMC_HC_ADMA_DESC_LINE;
#define SD_MMC_SDMA_BOUNDARY 512 * 1024
#define SD_MMC_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1))
typedef struct {
UINT8 FirstBar:3; // bit 0:2
UINT8 Reserved:1; // bit 3
UINT8 SlotNum:3; // bit 4:6
UINT8 Reserved1:1; // bit 7
} SD_MMC_HC_SLOT_INFO;
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_MMC_HC_SLOT_CAP;
/**
Dump the content of SD/MMC host controller's Capability Register.
@param[in] Slot The slot number of the SD card to send the command to.
@param[in] Capability The buffer to store the capability data.
**/
VOID
DumpCapabilityReg (
IN UINT8 Slot,
IN SD_MMC_HC_SLOT_CAP *Capability
);
/**
Read SlotInfo register from SD/MMC host controller pci config space.
@param[in] PciIo The PCI IO protocol instance.
@param[out] FirstBar The buffer to store the first BAR value.
@param[out] SlotNum The buffer to store the supported slot number.
@retval EFI_SUCCESS The operation succeeds.
@retval Others The operation fails.
**/
EFI_STATUS
EFIAPI
SdMmcHcGetSlotInfo (
IN EFI_PCI_IO_PROTOCOL *PciIo,
OUT UINT8 *FirstBar,
OUT UINT8 *SlotNum
);
/**
Read/Write specified SD/MMC host controller mmio register.
@param[in] PciIo The PCI IO protocol instance.
@param[in] BarIndex The BAR index of the standard PCI Configuration
header to use as the base address for the memory
operation to perform.
@param[in] Offset The offset within the selected BAR to start the
memory operation.
@param[in] Read A boolean to indicate it's read or write operation.
@param[in] Count The width of the mmio register in bytes.
Must be 1, 2 , 4 or 8 bytes.
@param[in, out] Data For read operations, the destination buffer to store
the results. For write operations, the source buffer
to write data from. The caller is responsible for
having ownership of the data buffer and ensuring its
size not less than Count bytes.
@retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid.
@retval EFI_SUCCESS The read/write operation succeeds.
@retval Others The read/write operation fails.
**/
EFI_STATUS
EFIAPI
SdMmcHcRwMmio (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 BarIndex,
IN UINT32 Offset,
IN BOOLEAN Read,
IN UINT8 Count,
IN OUT VOID *Data
);
/**
Do OR operation with the value of the specified SD/MMC host controller mmio register.
@param[in] PciIo The PCI IO protocol instance.
@param[in] BarIndex The BAR index of the standard PCI Configuration
header to use as the base address for the memory
operation to perform.
@param[in] Offset The offset within the selected BAR to start the
memory operation.
@param[in] Count The width of the mmio register in bytes.
Must be 1, 2 , 4 or 8 bytes.
@param[in] OrData The pointer to the data used to do OR operation.
The caller is responsible for having ownership of
the data buffer and ensuring its size not less than
Count bytes.
@retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid.
@retval EFI_SUCCESS The OR operation succeeds.
@retval Others The OR operation fails.
**/
EFI_STATUS
EFIAPI
SdMmcHcOrMmio (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 BarIndex,
IN UINT32 Offset,
IN UINT8 Count,
IN VOID *OrData
);
/**
Do AND operation with the value of the specified SD/MMC host controller mmio register.
@param[in] PciIo The PCI IO protocol instance.
@param[in] BarIndex The BAR index of the standard PCI Configuration
header to use as the base address for the memory
operation to perform.
@param[in] Offset The offset within the selected BAR to start the
memory operation.
@param[in] Count The width of the mmio register in bytes.
Must be 1, 2 , 4 or 8 bytes.
@param[in] AndData The pointer to the data used to do AND operation.
The caller is responsible for having ownership of
the data buffer and ensuring its size not less than
Count bytes.
@retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid.
@retval EFI_SUCCESS The AND operation succeeds.
@retval Others The AND operation fails.
**/
EFI_STATUS
EFIAPI
SdMmcHcAndMmio (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 BarIndex,
IN UINT32 Offset,
IN UINT8 Count,
IN VOID *AndData
);
/**
Wait for the value of the specified MMIO register set to the test value.
@param[in] PciIo The PCI IO protocol instance.
@param[in] BarIndex The BAR index of the standard PCI Configuration
header to use as the base address for the memory
operation to perform.
@param[in] Offset The offset within the selected BAR to start the
memory operation.
@param[in] Count The width of the mmio register in bytes.
Must be 1, 2, 4 or 8 bytes.
@param[in] MaskValue The mask value of memory.
@param[in] TestValue The test value of memory.
@param[in] Timeout The time out value for wait memory set, uses 1
microsecond as a unit.
@retval EFI_TIMEOUT The MMIO register hasn't expected value in timeout
range.
@retval EFI_SUCCESS The MMIO register has expected value.
@retval Others The MMIO operation fails.
**/
EFI_STATUS
EFIAPI
SdMmcHcWaitMmioSet (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 BarIndex,
IN UINT32 Offset,
IN UINT8 Count,
IN UINT64 MaskValue,
IN UINT64 TestValue,
IN UINT64 Timeout
);
/**
Software reset the specified SD/MMC host controller.
@param[in] PciIo The PCI IO protocol instance.
@param[in] Slot The slot number of the SD card to send the command to.
@retval EFI_SUCCESS The software reset executes successfully.
@retval Others The software reset fails.
**/
EFI_STATUS
SdMmcHcReset (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Slot
);
/**
Set all interrupt status bits in Normal and Error Interrupt Status Enable
register.
@param[in] PciIo The PCI IO protocol instance.
@param[in] Slot The slot number of the SD card to send the command to.
@retval EFI_SUCCESS The operation executes successfully.
@retval Others The operation fails.
**/
EFI_STATUS
SdMmcHcEnableInterrupt (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Slot
);
/**
Get the capability data from the specified slot.
@param[in] PciIo The PCI IO protocol instance.
@param[in] Slot The slot number of the SD card to send the command to.
@param[out] Capability The buffer to store the capability data.
@retval EFI_SUCCESS The operation executes successfully.
@retval Others The operation fails.
**/
EFI_STATUS
SdMmcHcGetCapability (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Slot,
OUT SD_MMC_HC_SLOT_CAP *Capability
);
/**
Get the maximum current capability data from the specified slot.
@param[in] PciIo The PCI IO protocol instance.
@param[in] Slot The slot number of the SD card to send the command to.
@param[out] MaxCurrent The buffer to store the maximum current capability data.
@retval EFI_SUCCESS The operation executes successfully.
@retval Others The operation fails.
**/
EFI_STATUS
SdMmcHcGetMaxCurrent (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Slot,
OUT UINT64 *MaxCurrent
);
/**
Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller
slot.
Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
@param[in] PciIo The PCI IO protocol instance.
@param[in] Slot The slot number of the SD card to send the command to.
@param[out] MediaPresent The pointer to the media present boolean value.
@retval EFI_SUCCESS There is no media change happened.
@retval EFI_MEDIA_CHANGED There is media change happened.
@retval Others The detection fails.
**/
EFI_STATUS
SdMmcHcCardDetect (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Slot,
OUT BOOLEAN *MediaPresent
);
/**
Stop SD/MMC card clock.
Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.
@param[in] PciIo The PCI IO protocol instance.
@param[in] Slot The slot number of the SD card to send the command to.
@retval EFI_SUCCESS Succeed to stop SD/MMC clock.
@retval Others Fail to stop SD/MMC clock.
**/
EFI_STATUS
SdMmcHcStopClock (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Slot
);
/**
SD/MMC card clock supply.
Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
@param[in] PciIo The PCI IO protocol instance.
@param[in] Slot The slot number of the SD card to send the command to.
@param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
@param[in] Capability The capability of the slot.
@retval EFI_SUCCESS The clock is supplied successfully.
@retval Others The clock isn't supplied successfully.
**/
EFI_STATUS
SdMmcHcClockSupply (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Slot,
IN UINT64 ClockFreq,
IN SD_MMC_HC_SLOT_CAP Capability
);
/**
SD/MMC bus power control.
Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
@param[in] PciIo The PCI IO protocol instance.
@param[in] Slot The slot number of the SD card to send the command to.
@param[in] PowerCtrl The value setting to the power control register.
@retval TRUE There is a SD/MMC card attached.
@retval FALSE There is no a SD/MMC card attached.
**/
EFI_STATUS
SdMmcHcPowerControl (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Slot,
IN UINT8 PowerCtrl
);
/**
Set the SD/MMC bus width.
Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
@param[in] PciIo The PCI IO protocol instance.
@param[in] Slot The slot number of the SD card to send the command to.
@param[in] BusWidth The bus width used by the SD/MMC device, it must be 1, 4 or 8.
@retval EFI_SUCCESS The bus width is set successfully.
@retval Others The bus width isn't set successfully.
**/
EFI_STATUS
SdMmcHcSetBusWidth (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Slot,
IN UINT16 BusWidth
);
/**
Supply SD/MMC card with lowest clock frequency at initialization.
@param[in] PciIo The PCI IO protocol instance.
@param[in] Slot The slot number of the SD card to send the command to.
@param[in] Capability The capability of the slot.
@retval EFI_SUCCESS The clock is supplied successfully.
@retval Others The clock isn't supplied successfully.
**/
EFI_STATUS
SdMmcHcInitClockFreq (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Slot,
IN SD_MMC_HC_SLOT_CAP Capability
);
/**
Supply SD/MMC card with maximum voltage at initialization.
Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
@param[in] PciIo The PCI IO protocol instance.
@param[in] Slot The slot number of the SD card to send the command to.
@param[in] Capability The capability of the slot.
@retval EFI_SUCCESS The voltage is supplied successfully.
@retval Others The voltage isn't supplied successfully.
**/
EFI_STATUS
SdMmcHcInitPowerVoltage (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Slot,
IN SD_MMC_HC_SLOT_CAP Capability
);
/**
Initialize the Timeout Control register with most conservative value at initialization.
Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.
@param[in] PciIo The PCI IO protocol instance.
@param[in] Slot The slot number of the SD card to send the command to.
@retval EFI_SUCCESS The timeout control register is configured successfully.
@retval Others The timeout control register isn't configured successfully.
**/
EFI_STATUS
SdMmcHcInitTimeoutCtrl (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Slot
);
/**
Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value
at initialization.
@param[in] PciIo The PCI IO protocol instance.
@param[in] Slot The slot number of the SD card to send the command to.
@param[in] Capability The capability of the slot.
@retval EFI_SUCCESS The host controller is initialized successfully.
@retval Others The host controller isn't initialized successfully.
**/
EFI_STATUS
SdMmcHcInitHost (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Slot,
IN SD_MMC_HC_SLOT_CAP Capability
);
#endif

View File

@ -0,0 +1,212 @@
/** @file
SdMmcPciHcPei driver is used to provide platform-dependent info, mainly SD/MMC
host controller MMIO base, to upper layer SD/MMC drivers.
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 "SdMmcPciHcPei.h"
EDKII_SD_MMC_HOST_CONTROLLER_PPI mSdMmcHostControllerPpi = { GetSdMmcHcMmioBar };
EFI_PEI_PPI_DESCRIPTOR mPpiList = {
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gEdkiiPeiSdMmcHostControllerPpiGuid,
&mSdMmcHostControllerPpi
};
/**
Get the MMIO base address of SD/MMC host controller.
@param[in] This The protocol instance pointer.
@param[in] ControllerId The ID of the SD/MMC host controller.
@param[in,out] MmioBar The pointer to store the array of available
SD/MMC host controller slot MMIO base addresses.
The entry number of the array is specified by BarNum.
@param[out] BarNum The pointer to store the supported bar number.
@retval EFI_SUCCESS The operation succeeds.
@retval EFI_INVALID_PARAMETER The parameters are invalid.
**/
EFI_STATUS
EFIAPI
GetSdMmcHcMmioBar (
IN EDKII_SD_MMC_HOST_CONTROLLER_PPI *This,
IN UINT8 ControllerId,
IN OUT UINTN **MmioBar,
OUT UINT8 *BarNum
)
{
SD_MMC_HC_PEI_PRIVATE_DATA *Private;
if ((This == NULL) || (MmioBar == NULL) || (BarNum == NULL)) {
return EFI_INVALID_PARAMETER;
}
Private = SD_MMC_HC_PEI_PRIVATE_DATA_FROM_THIS (This);
if (ControllerId >= Private->TotalSdMmcHcs) {
return EFI_INVALID_PARAMETER;
}
*MmioBar = &Private->MmioBar[ControllerId].MmioBarAddr[0];
*BarNum = (UINT8)Private->MmioBar[ControllerId].SlotNum;
return EFI_SUCCESS;
}
/**
The user code starts with this function.
@param FileHandle Handle of the file being invoked.
@param PeiServices Describes the list of possible PEI Services.
@retval EFI_SUCCESS The driver is successfully initialized.
@retval Others Can't initialize the driver.
**/
EFI_STATUS
EFIAPI
InitializeSdMmcHcPeim (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_BOOT_MODE BootMode;
EFI_STATUS Status;
UINT16 Bus;
UINT16 Device;
UINT16 Function;
UINT32 Size;
UINT64 MmioSize;
UINT8 SubClass;
UINT8 BaseClass;
UINT8 SlotInfo;
UINT8 SlotNum;
UINT8 FirstBar;
UINT8 Index;
UINT8 Slot;
UINT32 BarAddr;
SD_MMC_HC_PEI_PRIVATE_DATA *Private;
//
// Shadow this PEIM to run from memory
//
if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
return EFI_SUCCESS;
}
Status = PeiServicesGetBootMode (&BootMode);
///
/// We do not expose this in S3 boot path, because it is only for recovery.
///
if (BootMode == BOOT_ON_S3_RESUME) {
return EFI_SUCCESS;
}
Private = (SD_MMC_HC_PEI_PRIVATE_DATA *) AllocateZeroPool (sizeof (SD_MMC_HC_PEI_PRIVATE_DATA));
if (Private == NULL) {
DEBUG ((EFI_D_ERROR, "Failed to allocate memory for SD_MMC_HC_PEI_PRIVATE_DATA! \n"));
return EFI_OUT_OF_RESOURCES;
}
Private->Signature = SD_MMC_HC_PEI_SIGNATURE;
Private->SdMmcHostControllerPpi = mSdMmcHostControllerPpi;
Private->PpiList = mPpiList;
Private->PpiList.Ppi = &Private->SdMmcHostControllerPpi;
BarAddr = PcdGet32 (PcdSdMmcPciHostControllerMmioBase);
for (Bus = 0; Bus < 256; Bus++) {
for (Device = 0; Device < 32; Device++) {
for (Function = 0; Function < 8; Function++) {
SubClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));
BaseClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));
if ((SubClass == PCI_SUBCLASS_SD_HOST_CONTROLLER) && (BaseClass == PCI_CLASS_SYSTEM_PERIPHERAL)) {
//
// Get the SD/MMC Pci host controller's Slot Info.
//
SlotInfo = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, SD_MMC_HC_PEI_SLOT_OFFSET));
FirstBar = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).FirstBar;
SlotNum = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).SlotNum + 1;
ASSERT ((FirstBar + SlotNum) < MAX_SD_MMC_SLOTS);
for (Index = 0, Slot = FirstBar; Slot < (FirstBar + SlotNum); Index++, Slot++) {
//
// Get the SD/MMC Pci host controller's MMIO region size.
//
PciAnd16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (UINT16)~(EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));
PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), 0xFFFFFFFF);
Size = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot));
switch (Size & 0x07) {
case 0x0:
//
// Memory space: anywhere in 32 bit address space
//
MmioSize = (~(Size & 0xFFFFFFF0)) + 1;
break;
case 0x4:
//
// Memory space: anywhere in 64 bit address space
//
MmioSize = Size & 0xFFFFFFF0;
PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), 0xFFFFFFFF);
Size = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4));
//
// Fix the length to support some spefic 64 bit BAR
//
Size |= ((UINT32)(-1) << HighBitSet32 (Size));
//
// Calculate the size of 64bit bar
//
MmioSize |= LShiftU64 ((UINT64) Size, 32);
MmioSize = (~(MmioSize)) + 1;
//
// Clean the high 32bits of this 64bit BAR to 0 as we only allow a 32bit BAR.
//
PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot + 4), 0);
break;
default:
//
// Unknown BAR type
//
ASSERT (FALSE);
continue;
};
//
// Assign resource to the SdMmc Pci host controller's MMIO BAR.
// Enable the SdMmc Pci host controller by setting BME and MSE bits of PCI_CMD register.
//
PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), BarAddr);
PciOr16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));
//
// Record the allocated Mmio base address.
//
Private->MmioBar[Private->TotalSdMmcHcs].SlotNum++;
Private->MmioBar[Private->TotalSdMmcHcs].MmioBarAddr[Index] = BarAddr;
BarAddr += (UINT32)MmioSize;
}
Private->TotalSdMmcHcs++;
ASSERT (Private->TotalSdMmcHcs < MAX_SD_MMC_HCS);
}
}
}
}
///
/// Install SdMmc Host Controller PPI
///
Status = PeiServicesInstallPpi (&Private->PpiList);
ASSERT_EFI_ERROR (Status);
return Status;
}

View File

@ -0,0 +1,86 @@
/** @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_MMC_PCI_HOST_CONTROLLER_PEI_H_
#define _SD_MMC_PCI_HOST_CONTROLLER_PEI_H_
#include <PiPei.h>
#include <Ppi/MasterBootMode.h>
#include <Ppi/SdMmcHostController.h>
#include <IndustryStandard/Pci.h>
#include <Library/DebugLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/PciLib.h>
#include <Library/PeiServicesLib.h>
#include <Library/MemoryAllocationLib.h>
#define SD_MMC_HC_PEI_SIGNATURE SIGNATURE_32 ('S', 'D', 'M', 'C')
#define MAX_SD_MMC_HCS 8
#define MAX_SD_MMC_SLOTS 6
//
// SD Host Controller SlotInfo Register Offset
//
#define SD_MMC_HC_PEI_SLOT_OFFSET 0x40
typedef struct {
UINT8 FirstBar:3; // bit 0:2
UINT8 Reserved:1; // bit 3
UINT8 SlotNum:3; // bit 4:6
UINT8 Reserved1:1; // bit 7
} SD_MMC_HC_PEI_SLOT_INFO;
typedef struct {
UINTN SlotNum;
UINTN MmioBarAddr[MAX_SD_MMC_SLOTS];
} SD_MMC_HC_PEI_BAR;
typedef struct {
UINTN Signature;
EDKII_SD_MMC_HOST_CONTROLLER_PPI SdMmcHostControllerPpi;
EFI_PEI_PPI_DESCRIPTOR PpiList;
UINTN TotalSdMmcHcs;
SD_MMC_HC_PEI_BAR MmioBar[MAX_SD_MMC_HCS];
} SD_MMC_HC_PEI_PRIVATE_DATA;
#define SD_MMC_HC_PEI_PRIVATE_DATA_FROM_THIS(a) CR (a, SD_MMC_HC_PEI_PRIVATE_DATA, SdMmcHostControllerPpi, SD_MMC_HC_PEI_SIGNATURE)
/**
Get the MMIO base address of SD/MMC host controller.
@param[in] This The protocol instance pointer.
@param[in] ControllerId The ID of the SD/MMC host controller.
@param[in,out] MmioBar The pointer to store the array of available
SD/MMC host controller slot MMIO base addresses.
The entry number of the array is specified by BarNum.
@param[out] BarNum The pointer to store the supported bar number.
@retval EFI_SUCCESS The operation succeeds.
@retval EFI_INVALID_PARAMETER The parameters are invalid.
**/
EFI_STATUS
EFIAPI
GetSdMmcHcMmioBar (
IN EDKII_SD_MMC_HOST_CONTROLLER_PPI *This,
IN UINT8 ControllerId,
IN OUT UINTN **MmioBar,
OUT UINT8 *BarNum
);
#endif

View File

@ -0,0 +1,56 @@
## @file
# Component Description File For SD/MMC Pci Host Controller Pei Module.
#
# 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 = SdMmcPciHcPei
MODULE_UNI_FILE = SdMmcPciHcPei.uni
FILE_GUID = 1BB737EF-427A-4144-8B3B-B76EF38515E6
MODULE_TYPE = PEIM
VERSION_STRING = 1.0
ENTRY_POINT = InitializeSdMmcHcPeim
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources]
SdMmcPciHcPei.c
SdMmcPciHcPei.h
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
PciLib
DebugLib
PeiServicesLib
MemoryAllocationLib
PeimEntryPoint
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdSdMmcPciHostControllerMmioBase ## CONSUMES
[Ppis]
gEdkiiPeiSdMmcHostControllerPpiGuid ## PRODUCES
[Depex]
gEfiPeiMasterBootModePpiGuid AND gEfiPeiMemoryDiscoveredPpiGuid
[UserExtensions.TianoCore."ExtraFiles"]
SdMmcPciHcPeiExtra.uni

View File

@ -0,0 +1,22 @@
// /** @file
// The SdMmcPciHcPei driver is used by upper layer to retrieve mmio base address
// of managed pci-based SD/MMC host controller at PEI phase.
//
// 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 "Providing interface for upper layer to retrieve mmio base address of managed pci-based SD/MMC host controller at PEI phase."
#string STR_MODULE_DESCRIPTION #language en-US "It implements the interface of getting mmio base address of managed pci-based SD/MMC host controller at PEI phase."

View File

@ -0,0 +1,21 @@
// /** @file
// SdMmcPciHcPei 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/MMC PCI-Based HC Module for Recovery"

View File

@ -0,0 +1,807 @@
/** @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 "EmmcBlockIoPei.h"
//
// Template for EMMC HC Slot Data.
//
EMMC_PEIM_HC_SLOT gEmmcHcSlotTemplate = {
EMMC_PEIM_SLOT_SIG, // Signature
{ // Media
{
MSG_EMMC_DP,
FALSE,
TRUE,
FALSE,
0x200,
0
},
{
MSG_EMMC_DP,
FALSE,
TRUE,
FALSE,
0x200,
0
},
{
MSG_EMMC_DP,
FALSE,
TRUE,
FALSE,
0x200,
0
},
{
MSG_EMMC_DP,
FALSE,
TRUE,
FALSE,
0x200,
0
},
{
MSG_EMMC_DP,
FALSE,
TRUE,
FALSE,
0x200,
0
},
{
MSG_EMMC_DP,
FALSE,
TRUE,
FALSE,
0x200,
0
},
{
MSG_EMMC_DP,
FALSE,
TRUE,
FALSE,
0x200,
0
},
{
MSG_EMMC_DP,
FALSE,
TRUE,
FALSE,
0x200,
0
}
},
0, // MediaNum
{ // PartitionType
EmmcPartitionUnknown,
EmmcPartitionUnknown,
EmmcPartitionUnknown,
EmmcPartitionUnknown,
EmmcPartitionUnknown,
EmmcPartitionUnknown,
EmmcPartitionUnknown,
EmmcPartitionUnknown
},
0, // EmmcHcBase
{ // Capability
0,
},
{ // Csd
0,
},
{ // ExtCsd
{0},
},
TRUE, // SectorAddressing
NULL // Private
};
//
// Template for EMMC HC Private Data.
//
EMMC_PEIM_HC_PRIVATE_DATA gEmmcHcPrivateTemplate = {
EMMC_PEIM_SIG, // Signature
NULL, // Pool
{ // BlkIoPpi
EmmcBlockIoPeimGetDeviceNo,
EmmcBlockIoPeimGetMediaInfo,
EmmcBlockIoPeimReadBlocks
},
{ // BlkIo2Ppi
EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,
EmmcBlockIoPeimGetDeviceNo2,
EmmcBlockIoPeimGetMediaInfo2,
EmmcBlockIoPeimReadBlocks2
},
{ // BlkIoPpiList
EFI_PEI_PPI_DESCRIPTOR_PPI,
&gEfiPeiVirtualBlockIoPpiGuid,
NULL
},
{ // BlkIo2PpiList
EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
&gEfiPeiVirtualBlockIo2PpiGuid,
NULL
},
{ // Slot
{
0,
},
{
0,
},
{
0,
},
{
0,
},
{
0,
},
{
0,
}
},
0, // SlotNum
0 // TotalBlkIoDevices
};
/**
Gets the count of block I/O devices that one specific block driver detects.
This function is used for getting the count of block I/O devices that one
specific block driver detects. To the PEI ATAPI driver, it returns the number
of all the detected ATAPI devices it detects during the enumeration process.
To the PEI legacy floppy driver, it returns the number of all the legacy
devices it finds during its enumeration process. If no device is detected,
then the function will return zero.
@param[in] PeiServices General-purpose services that are available
to every PEIM.
@param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
instance.
@param[out] NumberBlockDevices The number of block I/O devices discovered.
@retval EFI_SUCCESS The operation performed successfully.
**/
EFI_STATUS
EFIAPI
EmmcBlockIoPeimGetDeviceNo (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
OUT UINTN *NumberBlockDevices
)
{
EMMC_PEIM_HC_PRIVATE_DATA *Private;
Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
*NumberBlockDevices = Private->TotalBlkIoDevices;
return EFI_SUCCESS;
}
/**
Gets a block device's media information.
This function will provide the caller with the specified block device's media
information. If the media changes, calling this function will update the media
information accordingly.
@param[in] PeiServices General-purpose services that are available to every
PEIM
@param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
@param[in] DeviceIndex Specifies the block device to which the function wants
to talk. Because the driver that implements Block I/O
PPIs will manage multiple block devices, the PPIs that
want to talk to a single device must specify the
device index that was assigned during the enumeration
process. This index is a number from one to
NumberBlockDevices.
@param[out] MediaInfo The media information of the specified block media.
The caller is responsible for the ownership of this
data structure.
@par Note:
The MediaInfo structure describes an enumeration of possible block device
types. This enumeration exists because no device paths are actually passed
across interfaces that describe the type or class of hardware that is publishing
the block I/O interface. This enumeration will allow for policy decisions
in the Recovery PEIM, such as "Try to recover from legacy floppy first,
LS-120 second, CD-ROM third." If there are multiple partitions abstracted
by a given device type, they should be reported in ascending order; this
order also applies to nested partitions, such as legacy MBR, where the
outermost partitions would have precedence in the reporting order. The
same logic applies to systems such as IDE that have precedence relationships
like "Master/Slave" or "Primary/Secondary". The master device should be
reported first, the slave second.
@retval EFI_SUCCESS Media information about the specified block device
was obtained successfully.
@retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
error.
**/
EFI_STATUS
EFIAPI
EmmcBlockIoPeimGetMediaInfo (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
IN UINTN DeviceIndex,
OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
)
{
EMMC_PEIM_HC_PRIVATE_DATA *Private;
UINT8 SlotNum;
UINT8 MediaNum;
UINT8 Location;
BOOLEAN Found;
Found = FALSE;
Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {
return EFI_INVALID_PARAMETER;
}
Location = 0;
MediaNum = 0;
for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {
for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {
Location ++;
if (Location == DeviceIndex) {
Found = TRUE;
break;
}
}
if (Found) {
break;
}
}
MediaInfo->DeviceType = EMMC;
MediaInfo->MediaPresent = TRUE;
MediaInfo->LastBlock = (UINTN)Private->Slot[SlotNum].Media[MediaNum].LastBlock;
MediaInfo->BlockSize = Private->Slot[SlotNum].Media[MediaNum].BlockSize;
return EFI_SUCCESS;
}
/**
Reads the requested number of blocks from the specified block device.
The function reads the requested number of blocks from the device. All the
blocks are read, or an error is returned. If there is no media in the device,
the function returns EFI_NO_MEDIA.
@param[in] PeiServices General-purpose services that are available to
every PEIM.
@param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
@param[in] DeviceIndex Specifies the block device to which the function wants
to talk. Because the driver that implements Block I/O
PPIs will manage multiple block devices, PPIs that
want to talk to a single device must specify the device
index that was assigned during the enumeration process.
This index is a number from one to NumberBlockDevices.
@param[in] StartLBA The starting logical block address (LBA) to read from
on the device
@param[in] BufferSize The size of the Buffer in bytes. This number must be
a multiple of the intrinsic block size of the device.
@param[out] Buffer A pointer to the destination buffer for the data.
The caller is responsible for the ownership of the
buffer.
@retval EFI_SUCCESS The data was read correctly from the device.
@retval EFI_DEVICE_ERROR The device reported an error while attempting
to perform the read operation.
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
valid, or the buffer is not properly aligned.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
the intrinsic block size of the device.
**/
EFI_STATUS
EFIAPI
EmmcBlockIoPeimReadBlocks (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
IN UINTN DeviceIndex,
IN EFI_PEI_LBA StartLBA,
IN UINTN BufferSize,
OUT VOID *Buffer
)
{
EFI_STATUS Status;
UINT32 BlockSize;
UINTN NumberOfBlocks;
EMMC_PEIM_HC_PRIVATE_DATA *Private;
UINT8 SlotNum;
UINT8 MediaNum;
UINT8 Location;
UINT8 PartitionConfig;
UINTN Remaining;
UINT32 MaxBlock;
BOOLEAN Found;
Status = EFI_SUCCESS;
Found = FALSE;
Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
//
// Check parameters
//
if (Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
if (BufferSize == 0) {
return EFI_SUCCESS;
}
if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {
return EFI_INVALID_PARAMETER;
}
Location = 0;
MediaNum = 0;
for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {
for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {
Location ++;
if (Location == DeviceIndex) {
Found = TRUE;
break;
}
}
if (Found) {
break;
}
}
BlockSize = Private->Slot[SlotNum].Media[MediaNum].BlockSize;
if (BufferSize % BlockSize != 0) {
return EFI_BAD_BUFFER_SIZE;
}
if (StartLBA > Private->Slot[SlotNum].Media[MediaNum].LastBlock) {
return EFI_INVALID_PARAMETER;
}
NumberOfBlocks = BufferSize / BlockSize;
//
// Check if needs to switch partition access.
//
PartitionConfig = Private->Slot[SlotNum].ExtCsd.PartitionConfig;
if ((PartitionConfig & 0x7) != Private->Slot[SlotNum].PartitionType[MediaNum]) {
PartitionConfig &= (UINT8)~0x7;
PartitionConfig |= Private->Slot[SlotNum].PartitionType[MediaNum];
Status = EmmcPeimSwitch (
&Private->Slot[SlotNum],
0x3,
OFFSET_OF (EMMC_EXT_CSD, PartitionConfig),
PartitionConfig,
0x0
);
if (EFI_ERROR (Status)) {
return Status;
}
Private->Slot[SlotNum].ExtCsd.PartitionConfig = PartitionConfig;
}
//
// Start to execute data transfer. The max block number in single cmd is 65535 blocks.
//
Remaining = NumberOfBlocks;
MaxBlock = 0xFFFF;
while (Remaining > 0) {
if (Remaining <= MaxBlock) {
NumberOfBlocks = Remaining;
} else {
NumberOfBlocks = MaxBlock;
}
Status = EmmcPeimSetBlkCount (&Private->Slot[SlotNum], (UINT16)NumberOfBlocks);
if (EFI_ERROR (Status)) {
return Status;
}
BufferSize = NumberOfBlocks * BlockSize;
Status = EmmcPeimRwMultiBlocks (&Private->Slot[SlotNum], StartLBA, BlockSize, Buffer, BufferSize, TRUE);
if (EFI_ERROR (Status)) {
return Status;
}
StartLBA += NumberOfBlocks;
Buffer = (UINT8*)Buffer + BufferSize;
Remaining -= NumberOfBlocks;
}
return Status;
}
/**
Gets the count of block I/O devices that one specific block driver detects.
This function is used for getting the count of block I/O devices that one
specific block driver detects. To the PEI ATAPI driver, it returns the number
of all the detected ATAPI devices it detects during the enumeration process.
To the PEI legacy floppy driver, it returns the number of all the legacy
devices it finds during its enumeration process. If no device is detected,
then the function will return zero.
@param[in] PeiServices General-purpose services that are available
to every PEIM.
@param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
instance.
@param[out] NumberBlockDevices The number of block I/O devices discovered.
@retval EFI_SUCCESS The operation performed successfully.
**/
EFI_STATUS
EFIAPI
EmmcBlockIoPeimGetDeviceNo2 (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
OUT UINTN *NumberBlockDevices
)
{
EMMC_PEIM_HC_PRIVATE_DATA *Private;
Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
*NumberBlockDevices = Private->TotalBlkIoDevices;
return EFI_SUCCESS;
}
/**
Gets a block device's media information.
This function will provide the caller with the specified block device's media
information. If the media changes, calling this function will update the media
information accordingly.
@param[in] PeiServices General-purpose services that are available to every
PEIM
@param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
@param[in] DeviceIndex Specifies the block device to which the function wants
to talk. Because the driver that implements Block I/O
PPIs will manage multiple block devices, the PPIs that
want to talk to a single device must specify the
device index that was assigned during the enumeration
process. This index is a number from one to
NumberBlockDevices.
@param[out] MediaInfo The media information of the specified block media.
The caller is responsible for the ownership of this
data structure.
@par Note:
The MediaInfo structure describes an enumeration of possible block device
types. This enumeration exists because no device paths are actually passed
across interfaces that describe the type or class of hardware that is publishing
the block I/O interface. This enumeration will allow for policy decisions
in the Recovery PEIM, such as "Try to recover from legacy floppy first,
LS-120 second, CD-ROM third." If there are multiple partitions abstracted
by a given device type, they should be reported in ascending order; this
order also applies to nested partitions, such as legacy MBR, where the
outermost partitions would have precedence in the reporting order. The
same logic applies to systems such as IDE that have precedence relationships
like "Master/Slave" or "Primary/Secondary". The master device should be
reported first, the slave second.
@retval EFI_SUCCESS Media information about the specified block device
was obtained successfully.
@retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
error.
**/
EFI_STATUS
EFIAPI
EmmcBlockIoPeimGetMediaInfo2 (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
IN UINTN DeviceIndex,
OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
)
{
EFI_STATUS Status;
EMMC_PEIM_HC_PRIVATE_DATA *Private;
EFI_PEI_BLOCK_IO_MEDIA Media;
UINT8 SlotNum;
UINT8 MediaNum;
UINT8 Location;
BOOLEAN Found;
Found = FALSE;
Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
Status = EmmcBlockIoPeimGetMediaInfo (
PeiServices,
&Private->BlkIoPpi,
DeviceIndex,
&Media
);
if (EFI_ERROR (Status)) {
return Status;
}
Location = 0;
MediaNum = 0;
for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {
for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {
Location ++;
if (Location == DeviceIndex) {
Found = TRUE;
break;
}
}
if (Found) {
break;
}
}
CopyMem (MediaInfo, &(Private->Slot[SlotNum].Media[MediaNum]), sizeof (EFI_PEI_BLOCK_IO2_MEDIA));
return EFI_SUCCESS;
}
/**
Reads the requested number of blocks from the specified block device.
The function reads the requested number of blocks from the device. All the
blocks are read, or an error is returned. If there is no media in the device,
the function returns EFI_NO_MEDIA.
@param[in] PeiServices General-purpose services that are available to
every PEIM.
@param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
@param[in] DeviceIndex Specifies the block device to which the function wants
to talk. Because the driver that implements Block I/O
PPIs will manage multiple block devices, PPIs that
want to talk to a single device must specify the device
index that was assigned during the enumeration process.
This index is a number from one to NumberBlockDevices.
@param[in] StartLBA The starting logical block address (LBA) to read from
on the device
@param[in] BufferSize The size of the Buffer in bytes. This number must be
a multiple of the intrinsic block size of the device.
@param[out] Buffer A pointer to the destination buffer for the data.
The caller is responsible for the ownership of the
buffer.
@retval EFI_SUCCESS The data was read correctly from the device.
@retval EFI_DEVICE_ERROR The device reported an error while attempting
to perform the read operation.
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
valid, or the buffer is not properly aligned.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
the intrinsic block size of the device.
**/
EFI_STATUS
EFIAPI
EmmcBlockIoPeimReadBlocks2 (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
IN UINTN DeviceIndex,
IN EFI_PEI_LBA StartLBA,
IN UINTN BufferSize,
OUT VOID *Buffer
)
{
EFI_STATUS Status;
EMMC_PEIM_HC_PRIVATE_DATA *Private;
Status = EFI_SUCCESS;
Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
Status = EmmcBlockIoPeimReadBlocks (
PeiServices,
&Private->BlkIoPpi,
DeviceIndex,
StartLBA,
BufferSize,
Buffer
);
return Status;
}
/**
The user code starts with this function.
@param FileHandle Handle of the file being invoked.
@param PeiServices Describes the list of possible PEI Services.
@retval EFI_SUCCESS The driver is successfully initialized.
@retval Others Can't initialize the driver.
**/
EFI_STATUS
EFIAPI
InitializeEmmcBlockIoPeim (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
EMMC_PEIM_HC_PRIVATE_DATA *Private;
EDKII_SD_MMC_HOST_CONTROLLER_PPI *SdMmcHcPpi;
UINT32 Index;
UINT32 PartitionIndex;
UINTN *MmioBase;
UINT8 BarNum;
UINT8 SlotNum;
UINT8 MediaNum;
UINT8 Controller;
UINT64 Capacity;
EMMC_EXT_CSD *ExtCsd;
EMMC_HC_SLOT_CAP Capability;
EMMC_PEIM_HC_SLOT *Slot;
UINT32 SecCount;
UINT32 GpSizeMult;
//
// Shadow this PEIM to run from memory
//
if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
return EFI_SUCCESS;
}
//
// locate Emmc host controller PPI
//
Status = PeiServicesLocatePpi (
&gEdkiiPeiSdMmcHostControllerPpiGuid,
0,
NULL,
(VOID **) &SdMmcHcPpi
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
Controller = 0;
MmioBase = NULL;
while (TRUE) {
Status = SdMmcHcPpi->GetSdMmcHcMmioBar (SdMmcHcPpi, Controller, &MmioBase, &BarNum);
//
// When status is error, meant no controller is found
//
if (EFI_ERROR (Status)) {
break;
}
if (BarNum == 0) {
Controller++;
continue;
}
Private = AllocateCopyPool (sizeof (EMMC_PEIM_HC_PRIVATE_DATA), &gEmmcHcPrivateTemplate);
if (Private == NULL) {
Status = EFI_OUT_OF_RESOURCES;
break;
}
Private->BlkIoPpiList.Ppi = (VOID*)&Private->BlkIoPpi;
Private->BlkIo2PpiList.Ppi = (VOID*)&Private->BlkIo2Ppi;
//
// Initialize the memory pool which will be used in all transactions.
//
Status = EmmcPeimInitMemPool (Private);
if (EFI_ERROR (Status)) {
Status = EFI_OUT_OF_RESOURCES;
break;
}
for (Index = 0; Index < BarNum; Index++) {
Status = EmmcPeimHcGetCapability (MmioBase[Index], &Capability);
if (EFI_ERROR (Status)) {
continue;
}
if (Capability.SlotType != 0x1) {
DEBUG ((EFI_D_INFO, "The slot at 0x%x is not embedded slot type\n", MmioBase[Index]));
Status = EFI_UNSUPPORTED;
continue;
}
Status = EmmcPeimHcReset (MmioBase[Index]);
if (EFI_ERROR (Status)) {
continue;
}
Status = EmmcPeimHcCardDetect (MmioBase[Index]);
if (EFI_ERROR (Status)) {
continue;
}
Status = EmmcPeimHcInitHost (MmioBase[Index]);
if (EFI_ERROR (Status)) {
continue;
}
SlotNum = Private->SlotNum;
Slot = &Private->Slot[SlotNum];
CopyMem (Slot, &gEmmcHcSlotTemplate, sizeof (EMMC_PEIM_HC_SLOT));
Slot->Private = Private;
Slot->EmmcHcBase = MmioBase[Index];
CopyMem (&Slot->Capability, &Capability, sizeof (Capability));
Status = EmmcPeimIdentification (Slot);
if (EFI_ERROR (Status)) {
continue;
}
ExtCsd = &Slot->ExtCsd;
if (ExtCsd->ExtCsdRev < 5) {
DEBUG ((EFI_D_ERROR, "The EMMC device version is too low, we don't support!!!\n"));
Status = EFI_UNSUPPORTED;
continue;
}
if ((ExtCsd->PartitioningSupport & BIT0) != BIT0) {
DEBUG ((EFI_D_ERROR, "The EMMC device doesn't support Partition Feature!!!\n"));
Status = EFI_UNSUPPORTED;
continue;
}
for (PartitionIndex = 0; PartitionIndex < EMMC_PEIM_MAX_PARTITIONS; PartitionIndex++) {
switch (PartitionIndex) {
case EmmcPartitionUserData:
SecCount = *(UINT32*)&ExtCsd->SecCount;
Capacity = MultU64x32 ((UINT64)SecCount, 0x200);
break;
case EmmcPartitionBoot1:
case EmmcPartitionBoot2:
Capacity = ExtCsd->BootSizeMult * SIZE_128KB;
break;
case EmmcPartitionRPMB:
Capacity = ExtCsd->RpmbSizeMult * SIZE_128KB;
break;
case EmmcPartitionGP1:
GpSizeMult = (ExtCsd->GpSizeMult[0] | (ExtCsd->GpSizeMult[1] << 8) | (ExtCsd->GpSizeMult[2] << 16));
Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
break;
case EmmcPartitionGP2:
GpSizeMult = (ExtCsd->GpSizeMult[3] | (ExtCsd->GpSizeMult[4] << 8) | (ExtCsd->GpSizeMult[5] << 16));
Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
break;
case EmmcPartitionGP3:
GpSizeMult = (ExtCsd->GpSizeMult[6] | (ExtCsd->GpSizeMult[7] << 8) | (ExtCsd->GpSizeMult[8] << 16));
Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
break;
case EmmcPartitionGP4:
GpSizeMult = (ExtCsd->GpSizeMult[9] | (ExtCsd->GpSizeMult[10] << 8) | (ExtCsd->GpSizeMult[11] << 16));
Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);
break;
default:
ASSERT (FALSE);
continue;
}
MediaNum = Slot->MediaNum;
if (Capacity != 0) {
Slot->Media[MediaNum].LastBlock = DivU64x32 (Capacity, Slot->Media[MediaNum].BlockSize) - 1;
Slot->PartitionType[MediaNum] = PartitionIndex;
Private->TotalBlkIoDevices++;
Slot->MediaNum++;
}
}
Private->SlotNum++;
}
Controller++;
if (!EFI_ERROR (Status)) {
PeiServicesInstallPpi (&Private->BlkIoPpiList);
}
}
return EFI_SUCCESS;
}

View File

@ -0,0 +1,381 @@
/** @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 _EMMC_BLOCK_IO_PEI_H_
#define _EMMC_BLOCK_IO_PEI_H_
#include <PiPei.h>
#include <Ppi/SdMmcHostController.h>
#include <Ppi/BlockIo.h>
#include <Ppi/BlockIo2.h>
#include <Library/DebugLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/IoLib.h>
#include <Library/TimerLib.h>
#include <Library/PeiServicesLib.h>
#include <IndustryStandard/Emmc.h>
typedef struct _EMMC_PEIM_HC_PRIVATE_DATA EMMC_PEIM_HC_PRIVATE_DATA;
typedef struct _EMMC_PEIM_HC_SLOT EMMC_PEIM_HC_SLOT;
typedef struct _EMMC_TRB EMMC_TRB;
#include "EmmcHci.h"
#include "EmmcHcMem.h"
#define EMMC_PEIM_SIG SIGNATURE_32 ('E', 'M', 'C', 'P')
#define EMMC_PEIM_SLOT_SIG SIGNATURE_32 ('E', 'M', 'C', 'S')
#define EMMC_PEIM_MAX_SLOTS 6
#define EMMC_PEIM_MAX_PARTITIONS 8
struct _EMMC_PEIM_HC_SLOT {
UINT32 Signature;
EFI_PEI_BLOCK_IO2_MEDIA Media[EMMC_PEIM_MAX_PARTITIONS];
UINT8 MediaNum;
EMMC_PARTITION_TYPE PartitionType[EMMC_PEIM_MAX_PARTITIONS];
UINTN EmmcHcBase;
EMMC_HC_SLOT_CAP Capability;
EMMC_CSD Csd;
EMMC_EXT_CSD ExtCsd;
BOOLEAN SectorAddressing;
EMMC_PEIM_HC_PRIVATE_DATA *Private;
};
struct _EMMC_PEIM_HC_PRIVATE_DATA {
UINT32 Signature;
EMMC_PEIM_MEM_POOL *Pool;
EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi;
EFI_PEI_RECOVERY_BLOCK_IO2_PPI BlkIo2Ppi;
EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList;
EFI_PEI_PPI_DESCRIPTOR BlkIo2PpiList;
EMMC_PEIM_HC_SLOT Slot[EMMC_PEIM_MAX_SLOTS];
UINT8 SlotNum;
UINT8 TotalBlkIoDevices;
};
#define EMMC_TIMEOUT MultU64x32((UINT64)(3), 1000000)
#define GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS(a) CR (a, EMMC_PEIM_HC_PRIVATE_DATA, BlkIoPpi, EMMC_PEIM_SIG)
#define GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2(a) CR (a, EMMC_PEIM_HC_PRIVATE_DATA, BlkIo2Ppi, EMMC_PEIM_SIG)
struct _EMMC_TRB {
EMMC_PEIM_HC_SLOT *Slot;
UINT16 BlockSize;
EMMC_COMMAND_PACKET *Packet;
VOID *Data;
UINT32 DataLen;
BOOLEAN Read;
EMMC_HC_TRANSFER_MODE Mode;
UINT64 Timeout;
EMMC_HC_ADMA_DESC_LINE *AdmaDesc;
UINTN AdmaDescSize;
};
/**
Gets the count of block I/O devices that one specific block driver detects.
This function is used for getting the count of block I/O devices that one
specific block driver detects. To the PEI ATAPI driver, it returns the number
of all the detected ATAPI devices it detects during the enumeration process.
To the PEI legacy floppy driver, it returns the number of all the legacy
devices it finds during its enumeration process. If no device is detected,
then the function will return zero.
@param[in] PeiServices General-purpose services that are available
to every PEIM.
@param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
instance.
@param[out] NumberBlockDevices The number of block I/O devices discovered.
@retval EFI_SUCCESS The operation performed successfully.
**/
EFI_STATUS
EFIAPI
EmmcBlockIoPeimGetDeviceNo (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
OUT UINTN *NumberBlockDevices
);
/**
Gets a block device's media information.
This function will provide the caller with the specified block device's media
information. If the media changes, calling this function will update the media
information accordingly.
@param[in] PeiServices General-purpose services that are available to every
PEIM
@param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
@param[in] DeviceIndex Specifies the block device to which the function wants
to talk. Because the driver that implements Block I/O
PPIs will manage multiple block devices, the PPIs that
want to talk to a single device must specify the
device index that was assigned during the enumeration
process. This index is a number from one to
NumberBlockDevices.
@param[out] MediaInfo The media information of the specified block media.
The caller is responsible for the ownership of this
data structure.
@par Note:
The MediaInfo structure describes an enumeration of possible block device
types. This enumeration exists because no device paths are actually passed
across interfaces that describe the type or class of hardware that is publishing
the block I/O interface. This enumeration will allow for policy decisions
in the Recovery PEIM, such as "Try to recover from legacy floppy first,
LS-120 second, CD-ROM third." If there are multiple partitions abstracted
by a given device type, they should be reported in ascending order; this
order also applies to nested partitions, such as legacy MBR, where the
outermost partitions would have precedence in the reporting order. The
same logic applies to systems such as IDE that have precedence relationships
like "Master/Slave" or "Primary/Secondary". The master device should be
reported first, the slave second.
@retval EFI_SUCCESS Media information about the specified block device
was obtained successfully.
@retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
error.
**/
EFI_STATUS
EFIAPI
EmmcBlockIoPeimGetMediaInfo (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
IN UINTN DeviceIndex,
OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
);
/**
Reads the requested number of blocks from the specified block device.
The function reads the requested number of blocks from the device. All the
blocks are read, or an error is returned. If there is no media in the device,
the function returns EFI_NO_MEDIA.
@param[in] PeiServices General-purpose services that are available to
every PEIM.
@param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
@param[in] DeviceIndex Specifies the block device to which the function wants
to talk. Because the driver that implements Block I/O
PPIs will manage multiple block devices, PPIs that
want to talk to a single device must specify the device
index that was assigned during the enumeration process.
This index is a number from one to NumberBlockDevices.
@param[in] StartLBA The starting logical block address (LBA) to read from
on the device
@param[in] BufferSize The size of the Buffer in bytes. This number must be
a multiple of the intrinsic block size of the device.
@param[out] Buffer A pointer to the destination buffer for the data.
The caller is responsible for the ownership of the
buffer.
@retval EFI_SUCCESS The data was read correctly from the device.
@retval EFI_DEVICE_ERROR The device reported an error while attempting
to perform the read operation.
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
valid, or the buffer is not properly aligned.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
the intrinsic block size of the device.
**/
EFI_STATUS
EFIAPI
EmmcBlockIoPeimReadBlocks (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
IN UINTN DeviceIndex,
IN EFI_PEI_LBA StartLBA,
IN UINTN BufferSize,
OUT VOID *Buffer
);
/**
Gets the count of block I/O devices that one specific block driver detects.
This function is used for getting the count of block I/O devices that one
specific block driver detects. To the PEI ATAPI driver, it returns the number
of all the detected ATAPI devices it detects during the enumeration process.
To the PEI legacy floppy driver, it returns the number of all the legacy
devices it finds during its enumeration process. If no device is detected,
then the function will return zero.
@param[in] PeiServices General-purpose services that are available
to every PEIM.
@param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
instance.
@param[out] NumberBlockDevices The number of block I/O devices discovered.
@retval EFI_SUCCESS The operation performed successfully.
**/
EFI_STATUS
EFIAPI
EmmcBlockIoPeimGetDeviceNo2 (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
OUT UINTN *NumberBlockDevices
);
/**
Gets a block device's media information.
This function will provide the caller with the specified block device's media
information. If the media changes, calling this function will update the media
information accordingly.
@param[in] PeiServices General-purpose services that are available to every
PEIM
@param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
@param[in] DeviceIndex Specifies the block device to which the function wants
to talk. Because the driver that implements Block I/O
PPIs will manage multiple block devices, the PPIs that
want to talk to a single device must specify the
device index that was assigned during the enumeration
process. This index is a number from one to
NumberBlockDevices.
@param[out] MediaInfo The media information of the specified block media.
The caller is responsible for the ownership of this
data structure.
@par Note:
The MediaInfo structure describes an enumeration of possible block device
types. This enumeration exists because no device paths are actually passed
across interfaces that describe the type or class of hardware that is publishing
the block I/O interface. This enumeration will allow for policy decisions
in the Recovery PEIM, such as "Try to recover from legacy floppy first,
LS-120 second, CD-ROM third." If there are multiple partitions abstracted
by a given device type, they should be reported in ascending order; this
order also applies to nested partitions, such as legacy MBR, where the
outermost partitions would have precedence in the reporting order. The
same logic applies to systems such as IDE that have precedence relationships
like "Master/Slave" or "Primary/Secondary". The master device should be
reported first, the slave second.
@retval EFI_SUCCESS Media information about the specified block device
was obtained successfully.
@retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
error.
**/
EFI_STATUS
EFIAPI
EmmcBlockIoPeimGetMediaInfo2 (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
IN UINTN DeviceIndex,
OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
);
/**
Reads the requested number of blocks from the specified block device.
The function reads the requested number of blocks from the device. All the
blocks are read, or an error is returned. If there is no media in the device,
the function returns EFI_NO_MEDIA.
@param[in] PeiServices General-purpose services that are available to
every PEIM.
@param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
@param[in] DeviceIndex Specifies the block device to which the function wants
to talk. Because the driver that implements Block I/O
PPIs will manage multiple block devices, PPIs that
want to talk to a single device must specify the device
index that was assigned during the enumeration process.
This index is a number from one to NumberBlockDevices.
@param[in] StartLBA The starting logical block address (LBA) to read from
on the device
@param[in] BufferSize The size of the Buffer in bytes. This number must be
a multiple of the intrinsic block size of the device.
@param[out] Buffer A pointer to the destination buffer for the data.
The caller is responsible for the ownership of the
buffer.
@retval EFI_SUCCESS The data was read correctly from the device.
@retval EFI_DEVICE_ERROR The device reported an error while attempting
to perform the read operation.
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
valid, or the buffer is not properly aligned.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
the intrinsic block size of the device.
**/
EFI_STATUS
EFIAPI
EmmcBlockIoPeimReadBlocks2 (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
IN UINTN DeviceIndex,
IN EFI_PEI_LBA StartLBA,
IN UINTN BufferSize,
OUT VOID *Buffer
);
/**
Initialize the memory management pool for the host controller.
@param Private The Emmc Peim driver private data.
@retval EFI_SUCCESS The memory pool is initialized.
@retval Others Fail to init the memory pool.
**/
EFI_STATUS
EmmcPeimInitMemPool (
IN EMMC_PEIM_HC_PRIVATE_DATA *Private
);
/**
Allocate some memory from the host controller's memory pool
which can be used to communicate with host controller.
@param Pool The host controller's memory pool.
@param Size Size of the memory to allocate.
@return The allocated memory or NULL.
**/
VOID *
EmmcPeimAllocateMem (
IN EMMC_PEIM_MEM_POOL *Pool,
IN UINTN Size
);
/**
Free the allocated memory back to the memory pool.
@param Pool The memory pool of the host controller.
@param Mem The memory to free.
@param Size The size of the memory to free.
**/
VOID
EmmcPeimFreeMem (
IN EMMC_PEIM_MEM_POOL *Pool,
IN VOID *Mem,
IN UINTN Size
);
#endif

View File

@ -0,0 +1,62 @@
## @file
# Description file for the Embedded MMC (eMMC) 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 = EmmcBlockIoPei
MODULE_UNI_FILE = EmmcBlockIoPei.uni
FILE_GUID = 7F06A90F-AE0D-4887-82C0-FEC7F4F68B29
MODULE_TYPE = PEIM
VERSION_STRING = 1.0
ENTRY_POINT = InitializeEmmcBlockIoPeim
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources]
EmmcBlockIoPei.c
EmmcBlockIoPei.h
EmmcHci.c
EmmcHci.h
EmmcHcMem.c
EmmcHcMem.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"]
EmmcBlockIoPeiExtra.uni

View File

@ -0,0 +1,21 @@
// /** @file
// The EmmcBlockIoPei driver is used to support recovery from EMMC 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 EMMC devices"
#string STR_MODULE_DESCRIPTION #language en-US "The EmmcBlockIoPei driver is used to support recovery from EMMC device."

View File

@ -0,0 +1,21 @@
// /** @file
// EmmcBlockIoPei 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
"EMMC 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 "EmmcBlockIoPei.h"
/**
Allocate a block of memory to be used by the buffer pool.
@param Pages How many pages to allocate.
@return The allocated memory block or NULL if failed.
**/
EMMC_PEIM_MEM_BLOCK *
EmmcPeimAllocMemBlock (
IN UINTN Pages
)
{
EMMC_PEIM_MEM_BLOCK *Block;
EFI_STATUS Status;
VOID *TempPtr;
EFI_PHYSICAL_ADDRESS Address;
TempPtr = NULL;
Block = NULL;
Status = PeiServicesAllocatePool (sizeof(EMMC_PEIM_MEM_BLOCK), &TempPtr);
if (EFI_ERROR (Status)) {
return NULL;
}
ZeroMem ((VOID*)(UINTN)TempPtr, sizeof(EMMC_PEIM_MEM_BLOCK));
//
// each bit in the bit array represents EMMC_PEIM_MEM_UNIT
// bytes of memory in the memory block.
//
ASSERT (EMMC_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
Block = (EMMC_PEIM_MEM_BLOCK*)(UINTN)TempPtr;
Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
Block->BitsLen = Block->BufLen / (EMMC_PEIM_MEM_UNIT * 8);
Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr);
if (EFI_ERROR (Status)) {
return NULL;
}
ZeroMem ((VOID*)(UINTN)TempPtr, Block->BitsLen);
Block->Bits = (UINT8*)(UINTN)TempPtr;
Status = 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
EmmcPeimFreeMemBlock (
IN EMMC_PEIM_MEM_POOL *Pool,
IN EMMC_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 *
EmmcPeimAllocMemFromBlock (
IN EMMC_PEIM_MEM_BLOCK *Block,
IN UINTN Units
)
{
UINTN Byte;
UINT8 Bit;
UINTN StartByte;
UINT8 StartBit;
UINTN Available;
UINTN Count;
ASSERT ((Block != 0) && (Units != 0));
StartByte = 0;
StartBit = 0;
Available = 0;
for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
//
// If current bit is zero, the corresponding memory unit is
// available, otherwise we need to restart our searching.
// Available counts the consective number of zero bit.
//
if (!EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)) {
Available++;
if (Available >= Units) {
break;
}
EMMC_PEIM_NEXT_BIT (Byte, Bit);
} else {
EMMC_PEIM_NEXT_BIT (Byte, Bit);
Available = 0;
StartByte = Byte;
StartBit = Bit;
}
}
if (Available < Units) {
return NULL;
}
//
// Mark the memory as allocated
//
Byte = StartByte;
Bit = StartBit;
for (Count = 0; Count < Units; Count++) {
ASSERT (!EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));
Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) EMMC_PEIM_MEM_BIT (Bit));
EMMC_PEIM_NEXT_BIT (Byte, Bit);
}
return Block->Buf + (StartByte * 8 + StartBit) * EMMC_PEIM_MEM_UNIT;
}
/**
Insert the memory block to the pool's list of the blocks.
@param Head The head of the memory pool's block list.
@param Block The memory block to insert.
**/
VOID
EmmcPeimInsertMemBlockToPool (
IN EMMC_PEIM_MEM_BLOCK *Head,
IN EMMC_PEIM_MEM_BLOCK *Block
)
{
ASSERT ((Head != NULL) && (Block != NULL));
Block->Next = Head->Next;
Head->Next = Block;
}
/**
Is the memory block empty?
@param Block The memory block to check.
@retval TRUE The memory block is empty.
@retval FALSE The memory block isn't empty.
**/
BOOLEAN
EmmcPeimIsMemBlockEmpty (
IN EMMC_PEIM_MEM_BLOCK *Block
)
{
UINTN Index;
for (Index = 0; Index < Block->BitsLen; Index++) {
if (Block->Bits[Index] != 0) {
return FALSE;
}
}
return TRUE;
}
/**
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
EmmcPeimUnlinkMemBlock (
IN EMMC_PEIM_MEM_BLOCK *Head,
IN EMMC_PEIM_MEM_BLOCK *BlockToUnlink
)
{
EMMC_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 Emmc Peim driver private data.
@retval EFI_SUCCESS The memory pool is initialized.
@retval Others Fail to init the memory pool.
**/
EFI_STATUS
EmmcPeimInitMemPool (
IN EMMC_PEIM_HC_PRIVATE_DATA *Private
)
{
EMMC_PEIM_MEM_POOL *Pool;
EFI_STATUS Status;
VOID *TempPtr;
TempPtr = NULL;
Pool = NULL;
Status = PeiServicesAllocatePool (sizeof (EMMC_PEIM_MEM_POOL), &TempPtr);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
ZeroMem ((VOID*)(UINTN)TempPtr, sizeof (EMMC_PEIM_MEM_POOL));
Pool = (EMMC_PEIM_MEM_POOL *)((UINTN)TempPtr);
Pool->Head = EmmcPeimAllocMemBlock (EMMC_PEIM_MEM_DEFAULT_PAGES);
if (Pool->Head == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Private->Pool = Pool;
return EFI_SUCCESS;
}
/**
Release the memory management pool.
@param Pool The memory pool to free.
@retval EFI_DEVICE_ERROR Fail to free the memory pool.
@retval EFI_SUCCESS The memory pool is freed.
**/
EFI_STATUS
EmmcPeimFreeMemPool (
IN EMMC_PEIM_MEM_POOL *Pool
)
{
EMMC_PEIM_MEM_BLOCK *Block;
ASSERT (Pool->Head != NULL);
//
// Unlink all the memory blocks from the pool, then free them.
// EmmcPeimUnlinkMemBlock can't be used to unlink and free the
// first block.
//
for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
EmmcPeimFreeMemBlock (Pool, Block);
}
EmmcPeimFreeMemBlock (Pool, Pool->Head);
return EFI_SUCCESS;
}
/**
Allocate some memory from the host controller's memory pool
which can be used to communicate with host controller.
@param Pool The host controller's memory pool.
@param Size Size of the memory to allocate.
@return The allocated memory or NULL.
**/
VOID *
EmmcPeimAllocateMem (
IN EMMC_PEIM_MEM_POOL *Pool,
IN UINTN Size
)
{
EMMC_PEIM_MEM_BLOCK *Head;
EMMC_PEIM_MEM_BLOCK *Block;
EMMC_PEIM_MEM_BLOCK *NewBlock;
VOID *Mem;
UINTN AllocSize;
UINTN Pages;
Mem = NULL;
AllocSize = EMMC_PEIM_MEM_ROUND (Size);
Head = Pool->Head;
ASSERT (Head != NULL);
//
// First check whether current memory blocks can satisfy the allocation.
//
for (Block = Head; Block != NULL; Block = Block->Next) {
Mem = EmmcPeimAllocMemFromBlock (Block, AllocSize / EMMC_PEIM_MEM_UNIT);
if (Mem != NULL) {
ZeroMem (Mem, Size);
break;
}
}
if (Mem != NULL) {
return Mem;
}
//
// Create a new memory block if there is not enough memory
// in the pool. If the allocation size is larger than the
// default page number, just allocate a large enough memory
// block. Otherwise allocate default pages.
//
if (AllocSize > EFI_PAGES_TO_SIZE (EMMC_PEIM_MEM_DEFAULT_PAGES)) {
Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
} else {
Pages = EMMC_PEIM_MEM_DEFAULT_PAGES;
}
NewBlock = EmmcPeimAllocMemBlock (Pages);
if (NewBlock == NULL) {
return NULL;
}
//
// Add the new memory block to the pool, then allocate memory from it
//
EmmcPeimInsertMemBlockToPool (Head, NewBlock);
Mem = EmmcPeimAllocMemFromBlock (NewBlock, AllocSize / EMMC_PEIM_MEM_UNIT);
if (Mem != NULL) {
ZeroMem (Mem, Size);
}
return Mem;
}
/**
Free the allocated memory back to the memory pool.
@param Pool The memory pool of the host controller.
@param Mem The memory to free.
@param Size The size of the memory to free.
**/
VOID
EmmcPeimFreeMem (
IN EMMC_PEIM_MEM_POOL *Pool,
IN VOID *Mem,
IN UINTN Size
)
{
EMMC_PEIM_MEM_BLOCK *Head;
EMMC_PEIM_MEM_BLOCK *Block;
UINT8 *ToFree;
UINTN AllocSize;
UINTN Byte;
UINTN Bit;
UINTN Count;
Head = Pool->Head;
AllocSize = EMMC_PEIM_MEM_ROUND (Size);
ToFree = (UINT8 *) Mem;
for (Block = Head; Block != NULL; Block = Block->Next) {
//
// scan the memory block list for the memory block that
// completely contains the memory to free.
//
if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {
//
// compute the start byte and bit in the bit array
//
Byte = ((ToFree - Block->Buf) / EMMC_PEIM_MEM_UNIT) / 8;
Bit = ((ToFree - Block->Buf) / EMMC_PEIM_MEM_UNIT) % 8;
//
// reset associated bits in bit arry
//
for (Count = 0; Count < (AllocSize / EMMC_PEIM_MEM_UNIT); Count++) {
ASSERT (EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));
Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ EMMC_PEIM_MEM_BIT (Bit));
EMMC_PEIM_NEXT_BIT (Byte, Bit);
}
break;
}
}
//
// If Block == NULL, it means that the current memory isn't
// in the host controller's pool. This is critical because
// the caller has passed in a wrong memory point
//
ASSERT (Block != NULL);
//
// Release the current memory block if it is empty and not the head
//
if ((Block != Head) && EmmcPeimIsMemBlockEmpty (Block)) {
EmmcPeimFreeMemBlock (Pool, Block);
}
return ;
}

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 _EMMC_PEIM_MEM_H_
#define _EMMC_PEIM_MEM_H_
#define EMMC_PEIM_MEM_BIT(a) ((UINTN)(1 << (a)))
#define EMMC_PEIM_MEM_BIT_IS_SET(Data, Bit) \
((BOOLEAN)(((Data) & EMMC_PEIM_MEM_BIT(Bit)) == EMMC_PEIM_MEM_BIT(Bit)))
typedef struct _EMMC_PEIM_MEM_BLOCK EMMC_PEIM_MEM_BLOCK;
struct _EMMC_PEIM_MEM_BLOCK {
UINT8 *Bits; // Bit array to record which unit is allocated
UINTN BitsLen;
UINT8 *Buf;
UINTN BufLen; // Memory size in bytes
EMMC_PEIM_MEM_BLOCK *Next;
};
typedef struct _EMMC_PEIM_MEM_POOL {
EMMC_PEIM_MEM_BLOCK *Head;
} EMMC_PEIM_MEM_POOL;
//
// Memory allocation unit, note that the value must meet EMMC spec alignment requirement.
//
#define EMMC_PEIM_MEM_UNIT 128
#define EMMC_PEIM_MEM_UNIT_MASK (EMMC_PEIM_MEM_UNIT - 1)
#define EMMC_PEIM_MEM_DEFAULT_PAGES 16
#define EMMC_PEIM_MEM_ROUND(Len) (((Len) + EMMC_PEIM_MEM_UNIT_MASK) & (~EMMC_PEIM_MEM_UNIT_MASK))
//
// Advance the byte and bit to the next bit, adjust byte accordingly.
//
#define EMMC_PEIM_NEXT_BIT(Byte, Bit) \
do { \
(Bit)++; \
if ((Bit) > 7) { \
(Byte)++; \
(Bit) = 0; \
} \
} while (0)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,345 @@
/** @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 _EMMC_HCI_H_
#define _EMMC_HCI_H_
//
// EMMC Host Controller MMIO Register Offset
//
#define EMMC_HC_SDMA_ADDR 0x00
#define EMMC_HC_ARG2 0x00
#define EMMC_HC_BLK_SIZE 0x04
#define EMMC_HC_BLK_COUNT 0x06
#define EMMC_HC_ARG1 0x08
#define EMMC_HC_TRANS_MOD 0x0C
#define EMMC_HC_COMMAND 0x0E
#define EMMC_HC_RESPONSE 0x10
#define EMMC_HC_BUF_DAT_PORT 0x20
#define EMMC_HC_PRESENT_STATE 0x24
#define EMMC_HC_HOST_CTRL1 0x28
#define EMMC_HC_POWER_CTRL 0x29
#define EMMC_HC_BLK_GAP_CTRL 0x2A
#define EMMC_HC_WAKEUP_CTRL 0x2B
#define EMMC_HC_CLOCK_CTRL 0x2C
#define EMMC_HC_TIMEOUT_CTRL 0x2E
#define EMMC_HC_SW_RST 0x2F
#define EMMC_HC_NOR_INT_STS 0x30
#define EMMC_HC_ERR_INT_STS 0x32
#define EMMC_HC_NOR_INT_STS_EN 0x34
#define EMMC_HC_ERR_INT_STS_EN 0x36
#define EMMC_HC_NOR_INT_SIG_EN 0x38
#define EMMC_HC_ERR_INT_SIG_EN 0x3A
#define EMMC_HC_AUTO_CMD_ERR_STS 0x3C
#define EMMC_HC_HOST_CTRL2 0x3E
#define EMMC_HC_CAP 0x40
#define EMMC_HC_MAX_CURRENT_CAP 0x48
#define EMMC_HC_FORCE_EVT_AUTO_CMD 0x50
#define EMMC_HC_FORCE_EVT_ERR_INT 0x52
#define EMMC_HC_ADMA_ERR_STS 0x54
#define EMMC_HC_ADMA_SYS_ADDR 0x58
#define EMMC_HC_PRESET_VAL 0x60
#define EMMC_HC_SHARED_BUS_CTRL 0xE0
#define EMMC_HC_SLOT_INT_STS 0xFC
#define EMMC_HC_CTRL_VER 0xFE
//
// The transfer modes supported by SD Host Controller
// Simplified Spec 3.0 Table 1-2
//
typedef enum {
EmmcNoData,
EmmcPioMode,
EmmcSdmaMode,
EmmcAdmaMode
} EMMC_HC_TRANSFER_MODE;
//
// The maximum data length of each descriptor line
//
#define ADMA_MAX_DATA_PER_LINE 0x10000
#define EMMC_SDMA_BOUNDARY 512 * 1024
#define EMMC_SDMA_ROUND_UP(x, n) (((x) + n) & ~(n - 1))
typedef enum {
EmmcCommandTypeBc, // Broadcast commands, no response
EmmcCommandTypeBcr, // Broadcast commands with response
EmmcCommandTypeAc, // Addressed(point-to-point) commands
EmmcCommandTypeAdtc // Addressed(point-to-point) data transfer commands
} EMMC_COMMAND_TYPE;
typedef enum {
EmmcResponceTypeR1,
EmmcResponceTypeR1b,
EmmcResponceTypeR2,
EmmcResponceTypeR3,
EmmcResponceTypeR4,
EmmcResponceTypeR5,
EmmcResponceTypeR5b,
EmmcResponceTypeR6,
EmmcResponceTypeR7
} EMMC_RESPONSE_TYPE;
typedef struct _EMMC_COMMAND_BLOCK {
UINT16 CommandIndex;
UINT32 CommandArgument;
UINT32 CommandType; // One of the EMMC_COMMAND_TYPE values
UINT32 ResponseType; // One of the EMMC_RESPONSE_TYPE values
} EMMC_COMMAND_BLOCK;
typedef struct _EMMC_STATUS_BLOCK {
UINT32 Resp0;
UINT32 Resp1;
UINT32 Resp2;
UINT32 Resp3;
} EMMC_STATUS_BLOCK;
typedef struct _EMMC_COMMAND_PACKET {
UINT64 Timeout;
EMMC_COMMAND_BLOCK *EmmcCmdBlk;
EMMC_STATUS_BLOCK *EmmcStatusBlk;
VOID *InDataBuffer;
VOID *OutDataBuffer;
UINT32 InTransferLength;
UINT32 OutTransferLength;
} EMMC_COMMAND_PACKET;
#pragma pack(1)
typedef struct {
UINT32 Valid:1;
UINT32 End:1;
UINT32 Int:1;
UINT32 Reserved:1;
UINT32 Act:2;
UINT32 Reserved1:10;
UINT32 Length:16;
UINT32 Address;
} EMMC_HC_ADMA_DESC_LINE;
typedef struct {
UINT32 TimeoutFreq:6; // bit 0:5
UINT32 Reserved:1; // bit 6
UINT32 TimeoutUnit:1; // bit 7
UINT32 BaseClkFreq:8; // bit 8:15
UINT32 MaxBlkLen:2; // bit 16:17
UINT32 BusWidth8:1; // bit 18
UINT32 Adma2:1; // bit 19
UINT32 Reserved2:1; // bit 20
UINT32 HighSpeed:1; // bit 21
UINT32 Sdma:1; // bit 22
UINT32 SuspRes:1; // bit 23
UINT32 Voltage33:1; // bit 24
UINT32 Voltage30:1; // bit 25
UINT32 Voltage18:1; // bit 26
UINT32 Reserved3:1; // bit 27
UINT32 SysBus64:1; // bit 28
UINT32 AsyncInt:1; // bit 29
UINT32 SlotType:2; // bit 30:31
UINT32 Sdr50:1; // bit 32
UINT32 Sdr104:1; // bit 33
UINT32 Ddr50:1; // bit 34
UINT32 Reserved4:1; // bit 35
UINT32 DriverTypeA:1; // bit 36
UINT32 DriverTypeC:1; // bit 37
UINT32 DriverTypeD:1; // bit 38
UINT32 DriverType4:1; // bit 39
UINT32 TimerCount:4; // bit 40:43
UINT32 Reserved5:1; // bit 44
UINT32 TuningSDR50:1; // bit 45
UINT32 RetuningMod:2; // bit 46:47
UINT32 ClkMultiplier:8; // bit 48:55
UINT32 Reserved6:7; // bit 56:62
UINT32 Hs400:1; // bit 63
} EMMC_HC_SLOT_CAP;
#pragma pack()
/**
Software reset the specified EMMC host controller and enable all interrupts.
@param[in] Bar The mmio base address of the slot to be accessed.
@retval EFI_SUCCESS The software reset executes successfully.
@retval Others The software reset fails.
**/
EFI_STATUS
EmmcPeimHcReset (
IN UINTN Bar
);
/**
Set all interrupt status bits in Normal and Error Interrupt Status Enable
register.
@param[in] Bar The mmio base address of the slot to be accessed.
@retval EFI_SUCCESS The operation executes successfully.
@retval Others The operation fails.
**/
EFI_STATUS
EmmcPeimHcEnableInterrupt (
IN UINTN Bar
);
/**
Get the capability data from the specified slot.
@param[in] Bar The mmio base address of the slot to be accessed.
@param[out] Capability The buffer to store the capability data.
@retval EFI_SUCCESS The operation executes successfully.
@retval Others The operation fails.
**/
EFI_STATUS
EmmcPeimHcGetCapability (
IN UINTN Bar,
OUT EMMC_HC_SLOT_CAP *Capability
);
/**
Detect whether there is a EMMC card attached at the specified EMMC host controller
slot.
Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
@param[in] Bar The mmio base address of the slot to be accessed.
@retval EFI_SUCCESS There is a EMMC card attached.
@retval EFI_NO_MEDIA There is not a EMMC card attached.
@retval Others The detection fails.
**/
EFI_STATUS
EmmcPeimHcCardDetect (
IN UINTN Bar
);
/**
Initial EMMC host controller with lowest clock frequency, max power and max timeout value
at initialization.
@param[in] Bar The mmio base address of the slot to be accessed.
@retval EFI_SUCCESS The host controller is initialized successfully.
@retval Others The host controller isn't initialized successfully.
**/
EFI_STATUS
EmmcPeimHcInitHost (
IN UINTN Bar
);
/**
Send command SWITCH to the EMMC device to switch the mode of operation of the
selected Device or modifies the EXT_CSD registers.
Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
@param[in] Slot The slot number of the Emmc card to send the command to.
@param[in] Access The access mode of SWTICH command.
@param[in] Index The offset of the field to be access.
@param[in] Value The value to be set to the specified field of EXT_CSD register.
@param[in] CmdSet The value of CmdSet field of EXT_CSD register.
@retval EFI_SUCCESS The operation is done correctly.
@retval Others The operation fails.
**/
EFI_STATUS
EmmcPeimSwitch (
IN EMMC_PEIM_HC_SLOT *Slot,
IN UINT8 Access,
IN UINT8 Index,
IN UINT8 Value,
IN UINT8 CmdSet
);
/**
Send command SET_BLOCK_COUNT to the addressed EMMC device to set the number of
blocks for the following block read/write cmd.
Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
@param[in] Slot The slot number of the Emmc card to send the command to.
@param[in] BlockCount The number of the logical block to access.
@retval EFI_SUCCESS The operation is done correctly.
@retval Others The operation fails.
**/
EFI_STATUS
EmmcPeimSetBlkCount (
IN EMMC_PEIM_HC_SLOT *Slot,
IN UINT16 BlockCount
);
/**
Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed EMMC device
to read/write the specified number of blocks.
Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
@param[in] Slot The slot number of the Emmc card to send the command to.
@param[in] Lba The logical block address of starting access.
@param[in] BlockSize The block size of specified EMMC device partition.
@param[in] Buffer The pointer to the transfer buffer.
@param[in] BufferSize The size of transfer buffer.
@param[in] IsRead Boolean to show the operation direction.
@retval EFI_SUCCESS The operation is done correctly.
@retval Others The operation fails.
**/
EFI_STATUS
EmmcPeimRwMultiBlocks (
IN EMMC_PEIM_HC_SLOT *Slot,
IN EFI_LBA Lba,
IN UINT32 BlockSize,
IN VOID *Buffer,
IN UINTN BufferSize,
IN BOOLEAN IsRead
);
/**
Execute EMMC device identification procedure.
Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
@param[in] Slot The slot number of the Emmc card to send the command to.
@retval EFI_SUCCESS There is a EMMC card.
@retval Others There is not a EMMC card.
**/
EFI_STATUS
EmmcPeimIdentification (
IN EMMC_PEIM_HC_SLOT *Slot
);
/**
Free the resource used by the TRB.
@param[in] Trb The pointer to the EMMC_TRB instance.
**/
VOID
EmmcPeimFreeTrb (
IN EMMC_TRB *Trb
);
#endif

View File

@ -0,0 +1,241 @@
/** @file
UEFI Component Name(2) protocol implementation for EmmcDxe 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.
**/
#include "EmmcDxe.h"
//
// Driver name table
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mEmmcDxeDriverNameTable[] = {
{ "eng;en", L"Edkii Emmc Device Driver" },
{ NULL , NULL }
};
//
// Controller name table
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mEmmcDxeControllerNameTable[] = {
{ "eng;en", L"Edkii Emmc Host Controller" },
{ NULL , NULL }
};
//
// EFI Component Name Protocol
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gEmmcDxeComponentName = {
EmmcDxeComponentNameGetDriverName,
EmmcDxeComponentNameGetControllerName,
"eng"
};
//
// EFI Component Name 2 Protocol
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gEmmcDxeComponentName2 = {
(EFI_COMPONENT_NAME2_GET_DRIVER_NAME) EmmcDxeComponentNameGetDriverName,
(EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) EmmcDxeComponentNameGetControllerName,
"en"
};
/**
Retrieves a Unicode string that is the user readable name of the driver.
This function retrieves the user readable name of a driver in the form of a
Unicode string. If the driver specified by This has a user readable name in
the language specified by Language, then a pointer to the driver name is
returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
by This does not support the language specified by Language,
then EFI_UNSUPPORTED is returned.
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param Language[in] A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified
in RFC 4646 or ISO 639-2 language code format.
@param DriverName[out] A pointer to the Unicode string to return.
This Unicode string is the name of the
driver specified by This in the language
specified by Language.
@retval EFI_SUCCESS The Unicode string for the Driver specified by
This and the language specified by Language was
returned in DriverName.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER DriverName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
EmmcDxeComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
{
return LookupUnicodeString2 (
Language,
This->SupportedLanguages,
mEmmcDxeDriverNameTable,
DriverName,
(BOOLEAN)(This == &gEmmcDxeComponentName)
);
}
/**
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by a driver.
This function retrieves the user readable name of the controller specified by
ControllerHandle and ChildHandle in the form of a Unicode string. If the
driver specified by This has a user readable name in the language specified by
Language, then a pointer to the controller name is returned in ControllerName,
and EFI_SUCCESS is returned. If the driver specified by This is not currently
managing the controller specified by ControllerHandle and ChildHandle,
then EFI_UNSUPPORTED is returned. If the driver specified by This does not
support the language specified by Language, then EFI_UNSUPPORTED is returned.
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param ControllerHandle[in] The handle of a controller that the driver
specified by This is managing. This handle
specifies the controller whose name is to be
returned.
@param ChildHandle[in] The handle of the child controller to retrieve
the name of. This is an optional parameter that
may be NULL. It will be NULL for device
drivers. It will also be NULL for a bus drivers
that wish to retrieve the name of the bus
controller. It will not be NULL for a bus
driver that wishes to retrieve the name of a
child controller.
@param Language[in] A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified in
RFC 4646 or ISO 639-2 language code format.
@param ControllerName[out] A pointer to the Unicode string to return.
This Unicode string is the name of the
controller specified by ControllerHandle and
ChildHandle in the language specified by
Language from the point of view of the driver
specified by This.
@retval EFI_SUCCESS The Unicode string for the user readable name in
the language specified by Language for the
driver specified by This was returned in
DriverName.
@retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
EFI_HANDLE.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This is not currently
managing the controller specified by
ControllerHandle and ChildHandle.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
EmmcDxeComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
{
EFI_STATUS Status;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
EMMC_DEVICE *Device;
EMMC_PARTITION *Partition;
EFI_UNICODE_STRING_TABLE *ControllerNameTable;
//
// Make sure this driver is currently managing ControllHandle
//
Status = EfiTestManagedDevice (
ControllerHandle,
gEmmcDxeDriverBinding.DriverBindingHandle,
&gEfiSdMmcPassThruProtocolGuid
);
if (EFI_ERROR (Status)) {
return Status;
}
ControllerNameTable = mEmmcDxeControllerNameTable;
if (ChildHandle != NULL) {
Status = EfiTestChildHandle (
ControllerHandle,
ChildHandle,
&gEfiSdMmcPassThruProtocolGuid
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get the child context
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiBlockIoProtocolGuid,
(VOID **) &BlockIo,
gEmmcDxeDriverBinding.DriverBindingHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
Partition = EMMC_PARTITION_DATA_FROM_BLKIO (BlockIo);
Device = Partition->Device;
ControllerNameTable = Device->ControllerNameTable;
}
return LookupUnicodeString2 (
Language,
This->SupportedLanguages,
ControllerNameTable,
ControllerName,
(BOOLEAN)(This == &gEmmcDxeComponentName)
);}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,466 @@
/** @file
Header file for EmmcDxe Driver.
This file defines common data structures, macro definitions and some module
internal function header files.
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 _EMMC_BLOCK_IO_H_
#define _EMMC_BLOCK_IO_H_
/**
Reset the Block Device.
@param This Indicates a pointer to the calling context.
@param ExtendedVerification Driver may perform diagnostics on reset.
@retval EFI_SUCCESS The device was reset.
@retval EFI_DEVICE_ERROR The device is not functioning properly and could
not be reset.
**/
EFI_STATUS
EFIAPI
EmmcReset (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
);
/**
Read BufferSize bytes from Lba into Buffer.
@param This Indicates a pointer to the calling context.
@param MediaId Id of the media, changes every time the media is replaced.
@param Lba The starting Logical Block Address to read from
@param BufferSize Size of Buffer, must be a multiple of device block size.
@param Buffer A pointer to the destination buffer for the data. The caller is
responsible for either having implicit or explicit ownership of the buffer.
@retval EFI_SUCCESS The data was read correctly from the device.
@retval EFI_DEVICE_ERROR The device reported an error while performing the read.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
or the buffer is not on proper alignment.
**/
EFI_STATUS
EFIAPI
EmmcReadBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
OUT VOID *Buffer
);
/**
Write BufferSize bytes from Lba into Buffer.
@param This Indicates a pointer to the calling context.
@param MediaId The media ID that the write request is for.
@param Lba The starting logical block address to be written. The caller is
responsible for writing to only legitimate locations.
@param BufferSize Size of Buffer, must be a multiple of device block size.
@param Buffer A pointer to the source buffer for the data.
@retval EFI_SUCCESS The data was written correctly to the device.
@retval EFI_WRITE_PROTECTED The device can not be written to.
@retval EFI_DEVICE_ERROR The device reported an error while performing the write.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
@retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
or the buffer is not on proper alignment.
**/
EFI_STATUS
EFIAPI
EmmcWriteBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
IN VOID *Buffer
);
/**
Flush the Block Device.
@param This Indicates a pointer to the calling context.
@retval EFI_SUCCESS All outstanding data was written to the device
@retval EFI_DEVICE_ERROR The device reported an error while writing back the data
@retval EFI_NO_MEDIA There is no media in the device.
**/
EFI_STATUS
EFIAPI
EmmcFlushBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This
);
/**
Reset the Block Device.
@param[in] This Indicates a pointer to the calling context.
@param[in] ExtendedVerification Driver may perform diagnostics on reset.
@retval EFI_SUCCESS The device was reset.
@retval EFI_DEVICE_ERROR The device is not functioning properly and could
not be reset.
**/
EFI_STATUS
EFIAPI
EmmcResetEx (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
);
/**
Read BufferSize bytes from Lba into Buffer.
@param[in] This Indicates a pointer to the calling context.
@param[in] MediaId Id of the media, changes every time the media is replaced.
@param[in] Lba The starting Logical Block Address to read from.
@param[in, out] Token A pointer to the token associated with the transaction.
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
@param[out] Buffer A pointer to the destination buffer for the data. The caller is
responsible for either having implicit or explicit ownership of the buffer.
@retval EFI_SUCCESS The read request was queued if Event is not NULL.
The data was read correctly from the device if
the Event is NULL.
@retval EFI_DEVICE_ERROR The device reported an error while performing
the read.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
intrinsic block size of the device.
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
or the buffer is not on proper alignment.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
**/
EFI_STATUS
EFIAPI
EmmcReadBlocksEx (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
IN UINTN BufferSize,
OUT VOID *Buffer
);
/**
Write BufferSize bytes from Lba into Buffer.
@param[in] This Indicates a pointer to the calling context.
@param[in] MediaId The media ID that the write request is for.
@param[in] Lba The starting logical block address to be written. The
caller is responsible for writing to only legitimate
locations.
@param[in, out] Token A pointer to the token associated with the transaction.
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
@param[in] Buffer A pointer to the source buffer for the data.
@retval EFI_SUCCESS The data was written correctly to the device.
@retval EFI_WRITE_PROTECTED The device can not be written to.
@retval EFI_DEVICE_ERROR The device reported an error while performing the write.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
@retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
or the buffer is not on proper alignment.
**/
EFI_STATUS
EFIAPI
EmmcWriteBlocksEx (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
IN UINTN BufferSize,
IN VOID *Buffer
);
/**
Flush the Block Device.
@param[in] This Indicates a pointer to the calling context.
@param[in, out] Token A pointer to the token associated with the transaction.
@retval EFI_SUCCESS All outstanding data was written to the device
@retval EFI_DEVICE_ERROR The device reported an error while writing back the data
@retval EFI_NO_MEDIA There is no media in the device.
**/
EFI_STATUS
EFIAPI
EmmcFlushBlocksEx (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN OUT EFI_BLOCK_IO2_TOKEN *Token
);
/**
Send a security protocol command to a device that receives data and/or the result
of one or more commands sent by SendData.
The ReceiveData function sends a security protocol command to the given MediaId.
The security protocol command sent is defined by SecurityProtocolId and contains
the security protocol specific data SecurityProtocolSpecificData. The function
returns the data from the security protocol command in PayloadBuffer.
For devices supporting the SCSI command set, the security protocol command is sent
using the SECURITY PROTOCOL IN command defined in SPC-4.
For devices supporting the ATA command set, the security protocol command is sent
using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
is non-zero.
If the PayloadBufferSize is zero, the security protocol command is sent using the
Trusted Non-Data command defined in ATA8-ACS.
If PayloadBufferSize is too small to store the available data from the security
protocol command, the function shall copy PayloadBufferSize bytes into the
PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
the function shall return EFI_INVALID_PARAMETER.
If the given MediaId does not support security protocol commands, the function shall
return EFI_UNSUPPORTED. If there is no media in the device, the function returns
EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
the function returns EFI_MEDIA_CHANGED.
If the security protocol fails to complete within the Timeout period, the function
shall return EFI_TIMEOUT.
If the security protocol command completes without an error, the function shall
return EFI_SUCCESS. If the security protocol command completes with an error, the
function shall return EFI_DEVICE_ERROR.
@param[in] This Indicates a pointer to the calling context.
@param[in] MediaId ID of the medium to receive data from.
@param[in] Timeout The timeout, in 100ns units, to use for the execution
of the security protocol command. A Timeout value of 0
means that this function will wait indefinitely for the
security protocol command to execute. If Timeout is greater
than zero, then this function will return EFI_TIMEOUT
if the time required to execute the receive data command
is greater than Timeout.
@param[in] SecurityProtocolId The value of the "Security Protocol" parameter of
the security protocol command to be sent.
@param[in] SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
of the security protocol command to be sent.
@param[in] PayloadBufferSize Size in bytes of the payload data buffer.
@param[out] PayloadBuffer A pointer to a destination buffer to store the security
protocol command specific payload data for the security
protocol command. The caller is responsible for having
either implicit or explicit ownership of the buffer.
@param[out] PayloadTransferSize A pointer to a buffer to store the size in bytes of the
data written to the payload data buffer.
@param[in] IsRead Indicates it is a read or write operation.
@retval EFI_SUCCESS The security protocol command completed successfully.
@retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
data from the device. The PayloadBuffer contains the truncated data.
@retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
@retval EFI_DEVICE_ERROR The security protocol command completed with an error.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
@retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
PayloadBufferSize is non-zero.
@retval EFI_TIMEOUT A timeout occurred while waiting for the security
protocol command to execute.
**/
EFI_STATUS
EFIAPI
EmmcSecurityProtocolInOut (
IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
IN UINT32 MediaId,
IN UINT64 Timeout,
IN UINT8 SecurityProtocolId,
IN UINT16 SecurityProtocolSpecificData,
IN UINTN PayloadBufferSize,
OUT VOID *PayloadBuffer,
OUT UINTN *PayloadTransferSize,
IN BOOLEAN IsRead
);
/**
Send a security protocol command to a device that receives data and/or the result
of one or more commands sent by SendData.
The ReceiveData function sends a security protocol command to the given MediaId.
The security protocol command sent is defined by SecurityProtocolId and contains
the security protocol specific data SecurityProtocolSpecificData. The function
returns the data from the security protocol command in PayloadBuffer.
For devices supporting the SCSI command set, the security protocol command is sent
using the SECURITY PROTOCOL IN command defined in SPC-4.
For devices supporting the ATA command set, the security protocol command is sent
using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
is non-zero.
If the PayloadBufferSize is zero, the security protocol command is sent using the
Trusted Non-Data command defined in ATA8-ACS.
If PayloadBufferSize is too small to store the available data from the security
protocol command, the function shall copy PayloadBufferSize bytes into the
PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
the function shall return EFI_INVALID_PARAMETER.
If the given MediaId does not support security protocol commands, the function shall
return EFI_UNSUPPORTED. If there is no media in the device, the function returns
EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
the function returns EFI_MEDIA_CHANGED.
If the security protocol fails to complete within the Timeout period, the function
shall return EFI_TIMEOUT.
If the security protocol command completes without an error, the function shall
return EFI_SUCCESS. If the security protocol command completes with an error, the
function shall return EFI_DEVICE_ERROR.
@param This Indicates a pointer to the calling context.
@param MediaId ID of the medium to receive data from.
@param Timeout The timeout, in 100ns units, to use for the execution
of the security protocol command. A Timeout value of 0
means that this function will wait indefinitely for the
security protocol command to execute. If Timeout is greater
than zero, then this function will return EFI_TIMEOUT
if the time required to execute the receive data command
is greater than Timeout.
@param SecurityProtocolId The value of the "Security Protocol" parameter of
the security protocol command to be sent.
@param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
of the security protocol command to be sent.
@param PayloadBufferSize Size in bytes of the payload data buffer.
@param PayloadBuffer A pointer to a destination buffer to store the security
protocol command specific payload data for the security
protocol command. The caller is responsible for having
either implicit or explicit ownership of the buffer.
@param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
data written to the payload data buffer.
@retval EFI_SUCCESS The security protocol command completed successfully.
@retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
data from the device. The PayloadBuffer contains the truncated data.
@retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
@retval EFI_DEVICE_ERROR The security protocol command completed with an error.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
@retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
PayloadBufferSize is non-zero.
@retval EFI_TIMEOUT A timeout occurred while waiting for the security
protocol command to execute.
**/
EFI_STATUS
EFIAPI
EmmcSecurityProtocolIn (
IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
IN UINT32 MediaId,
IN UINT64 Timeout,
IN UINT8 SecurityProtocolId,
IN UINT16 SecurityProtocolSpecificData,
IN UINTN PayloadBufferSize,
OUT VOID *PayloadBuffer,
OUT UINTN *PayloadTransferSize
);
/**
Send a security protocol command to a device.
The SendData function sends a security protocol command containing the payload
PayloadBuffer to the given MediaId. The security protocol command sent is
defined by SecurityProtocolId and contains the security protocol specific data
SecurityProtocolSpecificData. If the underlying protocol command requires a
specific padding for the command payload, the SendData function shall add padding
bytes to the command payload to satisfy the padding requirements.
For devices supporting the SCSI command set, the security protocol command is sent
using the SECURITY PROTOCOL OUT command defined in SPC-4.
For devices supporting the ATA command set, the security protocol command is sent
using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
is non-zero. If the PayloadBufferSize is zero, the security protocol command is
sent using the Trusted Non-Data command defined in ATA8-ACS.
If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
return EFI_INVALID_PARAMETER.
If the given MediaId does not support security protocol commands, the function
shall return EFI_UNSUPPORTED. If there is no media in the device, the function
returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
device, the function returns EFI_MEDIA_CHANGED.
If the security protocol fails to complete within the Timeout period, the function
shall return EFI_TIMEOUT.
If the security protocol command completes without an error, the function shall return
EFI_SUCCESS. If the security protocol command completes with an error, the function
shall return EFI_DEVICE_ERROR.
@param This Indicates a pointer to the calling context.
@param MediaId ID of the medium to receive data from.
@param Timeout The timeout, in 100ns units, to use for the execution
of the security protocol command. A Timeout value of 0
means that this function will wait indefinitely for the
security protocol command to execute. If Timeout is greater
than zero, then this function will return EFI_TIMEOUT
if the time required to execute the receive data command
is greater than Timeout.
@param SecurityProtocolId The value of the "Security Protocol" parameter of
the security protocol command to be sent.
@param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
of the security protocol command to be sent.
@param PayloadBufferSize Size in bytes of the payload data buffer.
@param PayloadBuffer A pointer to a destination buffer to store the security
protocol command specific payload data for the security
protocol command.
@retval EFI_SUCCESS The security protocol command completed successfully.
@retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
@retval EFI_DEVICE_ERROR The security protocol command completed with an error.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
@retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
@retval EFI_TIMEOUT A timeout occurred while waiting for the security
protocol command to execute.
**/
EFI_STATUS
EFIAPI
EmmcSecurityProtocolOut (
IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
IN UINT32 MediaId,
IN UINT64 Timeout,
IN UINT8 SecurityProtocolId,
IN UINT16 SecurityProtocolSpecificData,
IN UINTN PayloadBufferSize,
IN VOID *PayloadBuffer
);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,495 @@
/** @file
Header file for EmmcDxe Driver.
This file defines common data structures, macro definitions and some module
internal function header files.
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 _EMMC_DXE_H_
#define _EMMC_DXE_H_
#include <Uefi.h>
#include <IndustryStandard/Emmc.h>
#include <Protocol/SdMmcPassThru.h>
#include <Protocol/BlockIo.h>
#include <Protocol/BlockIo2.h>
#include <Protocol/StorageSecurityCommand.h>
#include <Protocol/DevicePath.h>
#include <Library/DebugLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/BaseLib.h>
#include <Library/UefiLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DevicePathLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include "EmmcBlockIo.h"
//
// Global Variables
//
extern EFI_DRIVER_BINDING_PROTOCOL gEmmcDxeDriverBinding;
extern EFI_COMPONENT_NAME_PROTOCOL gEmmcDxeComponentName;
extern EFI_COMPONENT_NAME2_PROTOCOL gEmmcDxeComponentName2;
#define EMMC_PARTITION_SIGNATURE SIGNATURE_32 ('E', 'm', 'm', 'P')
#define EMMC_PARTITION_DATA_FROM_BLKIO(a) \
CR(a, EMMC_PARTITION, BlockIo, EMMC_PARTITION_SIGNATURE)
#define EMMC_PARTITION_DATA_FROM_BLKIO2(a) \
CR(a, EMMC_PARTITION, BlockIo2, EMMC_PARTITION_SIGNATURE)
#define EMMC_PARTITION_DATA_FROM_SSP(a) \
CR(a, EMMC_PARTITION, StorageSecurity, EMMC_PARTITION_SIGNATURE)
//
// Take 2.5 seconds as generic time out value, 1 microsecond as unit.
//
#define EMMC_GENERIC_TIMEOUT 2500 * 1000
#define EMMC_REQUEST_SIGNATURE SIGNATURE_32 ('E', 'm', 'R', 'e')
typedef struct _EMMC_DEVICE EMMC_DEVICE;
typedef struct _EMMC_DRIVER_PRIVATE_DATA EMMC_DRIVER_PRIVATE_DATA;
//
// Asynchronous I/O request.
//
typedef struct {
UINT32 Signature;
LIST_ENTRY Link;
EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
BOOLEAN IsEnd;
EFI_BLOCK_IO2_TOKEN *Token;
EFI_EVENT Event;
} EMMC_REQUEST;
#define EMMC_REQUEST_FROM_LINK(a) \
CR(a, EMMC_REQUEST, Link, EMMC_REQUEST_SIGNATURE)
typedef struct {
UINT32 Signature;
BOOLEAN Enable;
EMMC_PARTITION_TYPE PartitionType;
EFI_HANDLE Handle;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_BLOCK_IO_PROTOCOL BlockIo;
EFI_BLOCK_IO2_PROTOCOL BlockIo2;
EFI_BLOCK_IO_MEDIA BlockMedia;
EFI_STORAGE_SECURITY_COMMAND_PROTOCOL StorageSecurity;
LIST_ENTRY Queue;
EMMC_DEVICE *Device;
} EMMC_PARTITION;
//
// Up to 6 slots per EMMC PCI host controller
//
#define EMMC_MAX_DEVICES 6
//
// Up to 8 partitions per EMMC device.
//
#define EMMC_MAX_PARTITIONS 8
#define EMMC_MODEL_NAME_MAX_LEN 32
struct _EMMC_DEVICE {
EFI_HANDLE Handle;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
UINT8 Slot;
BOOLEAN SectorAddressing;
EMMC_PARTITION Partition[EMMC_MAX_PARTITIONS];
EMMC_CSD Csd;
EMMC_CID Cid;
EMMC_EXT_CSD ExtCsd;
EFI_UNICODE_STRING_TABLE *ControllerNameTable;
//
// The model name consists of three fields in CID register
// 1) OEM/Application ID (2 bytes)
// 2) Product Name (5 bytes)
// 3) Product Serial Number (4 bytes)
// The delimiters of these fields are whitespace.
//
CHAR16 ModelName[EMMC_MODEL_NAME_MAX_LEN];
EMMC_DRIVER_PRIVATE_DATA *Private;
} ;
//
// EMMC DXE driver private data structure
//
struct _EMMC_DRIVER_PRIVATE_DATA {
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
EFI_HANDLE Controller;
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
EFI_HANDLE DriverBindingHandle;
EMMC_DEVICE Device[EMMC_MAX_DEVICES];
} ;
/**
Tests to see if this driver supports a given controller. If a child device is provided,
it further tests to see if this driver supports creating a handle for the specified child device.
This function checks to see if the driver specified by This supports the device specified by
ControllerHandle. Drivers will typically use the device path attached to
ControllerHandle and/or the services from the bus I/O abstraction attached to
ControllerHandle to determine if the driver supports ControllerHandle. This function
may be called many times during platform initialization. In order to reduce boot times, the tests
performed by this function must be very small, and take as little time as possible to execute. This
function must not change the state of any hardware devices, and this function must be aware that the
device specified by ControllerHandle may already be managed by the same driver or a
different driver. This function must match its calls to AllocatePages() with FreePages(),
AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
Since ControllerHandle may have been previously started by the same driver, if a protocol is
already in the opened state, then it must not be closed with CloseProtocol(). This is required
to guarantee the state of ControllerHandle is not modified by this function.
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param[in] ControllerHandle The handle of the controller to test. This handle
must support a protocol interface that supplies
an I/O abstraction to the driver.
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
parameter is ignored by device drivers, and is optional for bus
drivers. For bus drivers, if this parameter is not NULL, then
the bus driver must determine if the bus controller specified
by ControllerHandle and the child controller specified
by RemainingDevicePath are both supported by this
bus driver.
@retval EFI_SUCCESS The device specified by ControllerHandle and
RemainingDevicePath is supported by the driver specified by This.
@retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
RemainingDevicePath is already being managed by the driver
specified by This.
@retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
RemainingDevicePath is already being managed by a different
driver or an application that requires exclusive access.
Currently not implemented.
@retval EFI_UNSUPPORTED The device specified by ControllerHandle and
RemainingDevicePath is not supported by the driver specified by This.
**/
EFI_STATUS
EFIAPI
EmmcDxeDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
);
/**
Starts a device controller or a bus controller.
The Start() function is designed to be invoked from the EFI boot service ConnectController().
As a result, much of the error checking on the parameters to Start() has been moved into this
common boot service. It is legal to call Start() from other locations,
but the following calling restrictions must be followed or the system behavior will not be deterministic.
1. ControllerHandle must be a valid EFI_HANDLE.
2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
EFI_DEVICE_PATH_PROTOCOL.
3. Prior to calling Start(), the Supported() function for the driver specified by This must
have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param[in] ControllerHandle The handle of the controller to start. This handle
must support a protocol interface that supplies
an I/O abstraction to the driver.
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
parameter is ignored by device drivers, and is optional for bus
drivers. For a bus driver, if this parameter is NULL, then handles
for all the children of Controller are created by this driver.
If this parameter is not NULL and the first Device Path Node is
not the End of Device Path Node, then only the handle for the
child device specified by the first Device Path Node of
RemainingDevicePath is created by this driver.
If the first Device Path Node of RemainingDevicePath is
the End of Device Path Node, no child handle is created by this
driver.
@retval EFI_SUCCESS The device was started.
@retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
@retval Others The driver failded to start the device.
**/
EFI_STATUS
EFIAPI
EmmcDxeDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
);
/**
Stops a device controller or a bus controller.
The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
As a result, much of the error checking on the parameters to Stop() has been moved
into this common boot service. It is legal to call Stop() from other locations,
but the following calling restrictions must be followed or the system behavior will not be deterministic.
1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
same driver's Start() function.
2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
EFI_HANDLE. In addition, all of these handles must have been created in this driver's
Start() function, and the Start() function must have called OpenProtocol() on
ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param[in] ControllerHandle A handle to the device being stopped. The handle must
support a bus specific I/O protocol for the driver
to use to stop the device.
@param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
@param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
if NumberOfChildren is 0.
@retval EFI_SUCCESS The device was stopped.
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
**/
EFI_STATUS
EFIAPI
EmmcDxeDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
);
/**
Retrieves a Unicode string that is the user readable name of the driver.
This function retrieves the user readable name of a driver in the form of a
Unicode string. If the driver specified by This has a user readable name in
the language specified by Language, then a pointer to the driver name is
returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
by This does not support the language specified by Language,
then EFI_UNSUPPORTED is returned.
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param Language[in] A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified
in RFC 4646 or ISO 639-2 language code format.
@param DriverName[out] A pointer to the Unicode string to return.
This Unicode string is the name of the
driver specified by This in the language
specified by Language.
@retval EFI_SUCCESS The Unicode string for the Driver specified by
This and the language specified by Language was
returned in DriverName.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER DriverName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
EmmcDxeComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
);
/**
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by a driver.
This function retrieves the user readable name of the controller specified by
ControllerHandle and ChildHandle in the form of a Unicode string. If the
driver specified by This has a user readable name in the language specified by
Language, then a pointer to the controller name is returned in ControllerName,
and EFI_SUCCESS is returned. If the driver specified by This is not currently
managing the controller specified by ControllerHandle and ChildHandle,
then EFI_UNSUPPORTED is returned. If the driver specified by This does not
support the language specified by Language, then EFI_UNSUPPORTED is returned.
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param ControllerHandle[in] The handle of a controller that the driver
specified by This is managing. This handle
specifies the controller whose name is to be
returned.
@param ChildHandle[in] The handle of the child controller to retrieve
the name of. This is an optional parameter that
may be NULL. It will be NULL for device
drivers. It will also be NULL for a bus drivers
that wish to retrieve the name of the bus
controller. It will not be NULL for a bus
driver that wishes to retrieve the name of a
child controller.
@param Language[in] A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified in
RFC 4646 or ISO 639-2 language code format.
@param ControllerName[out] A pointer to the Unicode string to return.
This Unicode string is the name of the
controller specified by ControllerHandle and
ChildHandle in the language specified by
Language from the point of view of the driver
specified by This.
@retval EFI_SUCCESS The Unicode string for the user readable name in
the language specified by Language for the
driver specified by This was returned in
DriverName.
@retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
EFI_HANDLE.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This is not currently
managing the controller specified by
ControllerHandle and ChildHandle.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
EmmcDxeComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
);
/**
Send command SELECT to the device to select/deselect the device.
@param[in] Device A pointer to the EMMC_DEVICE instance.
@param[in] Rca The relative device address to use.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
EmmcSelect (
IN EMMC_DEVICE *Device,
IN UINT16 Rca
);
/**
Send command SEND_STATUS to the device to get device status.
@param[in] Device A pointer to the EMMC_DEVICE instance.
@param[in] Rca The relative device address to use.
@param[out] DevStatus The buffer to store the device status.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
EmmcSendStatus (
IN EMMC_DEVICE *Device,
IN UINT16 Rca,
OUT UINT32 *DevStatus
);
/**
Send command SEND_CSD to the device to get the CSD register data.
@param[in] Device A pointer to the EMMC_DEVICE instance.
@param[in] Rca The relative device address to use.
@param[out] Csd The buffer to store the EMMC_CSD register data.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
EmmcGetCsd (
IN EMMC_DEVICE *Device,
IN UINT16 Rca,
OUT EMMC_CSD *Csd
);
/**
Send command SEND_CID to the device to get the CID register data.
@param[in] Device A pointer to the EMMC_DEVICE instance.
@param[in] Rca The relative device address to use.
@param[out] Csd The buffer to store the EMMC_CSD register data.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
EmmcGetCid (
IN EMMC_DEVICE *Device,
IN UINT16 Rca,
OUT EMMC_CID *Cid
);
/**
Send command SEND_EXT_CSD to the device to get the EXT_CSD register data.
@param[in] Device A pointer to the EMMC_DEVICE instance.
@param[out] ExtCsd The buffer to store the EXT_CSD register data.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
EmmcGetExtCsd (
IN EMMC_DEVICE *Device,
OUT EMMC_EXT_CSD *ExtCsd
);
#endif

View File

@ -0,0 +1,66 @@
## @file
# EmmcDxe driver is used to manage the EMMC device.
#
# It produces BlockIo, BlockIo2 and StorageSecurity protocols to allow upper layer
# access the EMMC device.
#
# Copyright (c) 2015, 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 = EmmcDxe
MODULE_UNI_FILE = EmmcDxe.uni
FILE_GUID = 2145F72F-E6F1-4440-A828-59DC9AAB5F89
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = InitializeEmmcDxe
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
# DRIVER_BINDING = gEmmcDxeDriverBinding
# COMPONENT_NAME = gEmmcDxeComponentName
# COMPONENT_NAME2 = gEmmcDxeComponentName2
#
[Sources.common]
ComponentName.c
EmmcDxe.c
EmmcDxe.h
EmmcBlockIo.c
EmmcBlockIo.h
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
DevicePathLib
UefiBootServicesTableLib
MemoryAllocationLib
BaseMemoryLib
UefiLib
BaseLib
UefiDriverEntryPoint
DebugLib
[Protocols]
gEfiSdMmcPassThruProtocolGuid ## TO_START
gEfiBlockIoProtocolGuid ## BY_START
gEfiBlockIo2ProtocolGuid ## BY_START
gEfiStorageSecurityCommandProtocolGuid ## SOMETIMES_PRODUCES
## TO_START
## BY_START
gEfiDevicePathProtocolGuid

View File

@ -0,0 +1,20 @@
// /** @file
// EMMC device driver to manage the EMMC device and provide interface for upper layer
// access.
//
// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
//
// 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 "EMMC device driver to manage the EMMC device and provide interface for upper layer access"
#string STR_MODULE_DESCRIPTION #language en-US "This driver follows the UEFI driver model and layers on the SdMmcPassThru protocol. It installs BlockIo/BlockIo2/StorageSecurity protocols for the EMMC device partitions."

View File

@ -0,0 +1,19 @@
// /** @file
// EmmcDxe 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
"EMMC Device Driver"

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

View File

@ -0,0 +1,240 @@
/** @file
UEFI Component Name(2) protocol implementation for SdDxe 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.
**/
#include "SdDxe.h"
//
// Driver name table
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdDxeDriverNameTable[] = {
{ "eng;en", L"Edkii Sd Memory Card Device Driver" },
{ NULL , NULL }
};
//
// Controller name table
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdDxeControllerNameTable[] = {
{ "eng;en", L"Edkii Sd Host Controller" },
{ NULL , NULL }
};
//
// EFI Component Name Protocol
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSdDxeComponentName = {
SdDxeComponentNameGetDriverName,
SdDxeComponentNameGetControllerName,
"eng"
};
//
// EFI Component Name 2 Protocol
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSdDxeComponentName2 = {
(EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SdDxeComponentNameGetDriverName,
(EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SdDxeComponentNameGetControllerName,
"en"
};
/**
Retrieves a Unicode string that is the user readable name of the driver.
This function retrieves the user readable name of a driver in the form of a
Unicode string. If the driver specified by This has a user readable name in
the language specified by Language, then a pointer to the driver name is
returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
by This does not support the language specified by Language,
then EFI_UNSUPPORTED is returned.
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param Language[in] A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified
in RFC 4646 or ISO 639-2 language code format.
@param DriverName[out] A pointer to the Unicode string to return.
This Unicode string is the name of the
driver specified by This in the language
specified by Language.
@retval EFI_SUCCESS The Unicode string for the Driver specified by
This and the language specified by Language was
returned in DriverName.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER DriverName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
SdDxeComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
{
return LookupUnicodeString2 (
Language,
This->SupportedLanguages,
mSdDxeDriverNameTable,
DriverName,
(BOOLEAN)(This == &gSdDxeComponentName)
);
}
/**
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by a driver.
This function retrieves the user readable name of the controller specified by
ControllerHandle and ChildHandle in the form of a Unicode string. If the
driver specified by This has a user readable name in the language specified by
Language, then a pointer to the controller name is returned in ControllerName,
and EFI_SUCCESS is returned. If the driver specified by This is not currently
managing the controller specified by ControllerHandle and ChildHandle,
then EFI_UNSUPPORTED is returned. If the driver specified by This does not
support the language specified by Language, then EFI_UNSUPPORTED is returned.
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param ControllerHandle[in] The handle of a controller that the driver
specified by This is managing. This handle
specifies the controller whose name is to be
returned.
@param ChildHandle[in] The handle of the child controller to retrieve
the name of. This is an optional parameter that
may be NULL. It will be NULL for device
drivers. It will also be NULL for a bus drivers
that wish to retrieve the name of the bus
controller. It will not be NULL for a bus
driver that wishes to retrieve the name of a
child controller.
@param Language[in] A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified in
RFC 4646 or ISO 639-2 language code format.
@param ControllerName[out] A pointer to the Unicode string to return.
This Unicode string is the name of the
controller specified by ControllerHandle and
ChildHandle in the language specified by
Language from the point of view of the driver
specified by This.
@retval EFI_SUCCESS The Unicode string for the user readable name in
the language specified by Language for the
driver specified by This was returned in
DriverName.
@retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
EFI_HANDLE.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This is not currently
managing the controller specified by
ControllerHandle and ChildHandle.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
SdDxeComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
{
EFI_STATUS Status;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
SD_DEVICE *Device;
EFI_UNICODE_STRING_TABLE *ControllerNameTable;
//
// Make sure this driver is currently managing ControllHandle
//
Status = EfiTestManagedDevice (
ControllerHandle,
gSdDxeDriverBinding.DriverBindingHandle,
&gEfiSdMmcPassThruProtocolGuid
);
if (EFI_ERROR (Status)) {
return Status;
}
ControllerNameTable = mSdDxeControllerNameTable;
if (ChildHandle != NULL) {
Status = EfiTestChildHandle (
ControllerHandle,
ChildHandle,
&gEfiSdMmcPassThruProtocolGuid
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get the child context
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiBlockIoProtocolGuid,
(VOID **) &BlockIo,
gSdDxeDriverBinding.DriverBindingHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
Device = SD_DEVICE_DATA_FROM_BLKIO (BlockIo);
ControllerNameTable = Device->ControllerNameTable;
}
return LookupUnicodeString2 (
Language,
This->SupportedLanguages,
ControllerNameTable,
ControllerName,
(BOOLEAN)(This == &gSdDxeComponentName)
);
}

View File

@ -0,0 +1,971 @@
/** @file
The helper functions for BlockIo and BlockIo2 protocol.
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 "SdDxe.h"
/**
Nonblocking I/O callback funtion when the event is signaled.
@param[in] Event The Event this notify function registered to.
@param[in] Context Pointer to the context data registered to the
Event.
**/
VOID
EFIAPI
AsyncIoCallback (
IN EFI_EVENT Event,
IN VOID *Context
)
{
SD_REQUEST *Request;
gBS->CloseEvent (Event);
Request = (SD_REQUEST *) Context;
DEBUG_CODE_BEGIN ();
DEBUG ((EFI_D_INFO, "Sd Async Request: CmdIndex[%d] Arg[%08x] %r\n",
Request->SdMmcCmdBlk.CommandIndex, Request->SdMmcCmdBlk.CommandArgument,
Request->Packet.TransactionStatus));
DEBUG_CODE_END ();
if (EFI_ERROR (Request->Packet.TransactionStatus)) {
Request->Token->TransactionStatus = Request->Packet.TransactionStatus;
}
RemoveEntryList (&Request->Link);
if (Request->IsEnd) {
gBS->SignalEvent (Request->Token->Event);
}
FreePool (Request);
}
/**
Send command SET_RELATIVE_ADDRESS to the device to set the device address.
@param[in] Device A pointer to the SD_DEVICE instance.
@param[out] Rca The relative device address to assign.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
SdSetRca (
IN SD_DEVICE *Device,
OUT UINT16 *Rca
)
{
EFI_STATUS Status;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
PassThru = Device->Private->PassThru;
ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
ZeroMem (&Packet, sizeof (Packet));
Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
Packet.Timeout = SD_GENERIC_TIMEOUT;
SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;
SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;
Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
if (!EFI_ERROR (Status)) {
DEBUG ((EFI_D_INFO, "Set RCA succeeds with Resp0 = 0x%x\n", SdMmcStatusBlk.Resp0));
*Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);
}
return Status;
}
/**
Send command SELECT to the device to select/deselect the device.
@param[in] Device A pointer to the SD_DEVICE instance.
@param[in] Rca The relative device address to use.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
SdSelect (
IN SD_DEVICE *Device,
IN UINT16 Rca
)
{
EFI_STATUS Status;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
PassThru = Device->Private->PassThru;
ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
ZeroMem (&Packet, sizeof (Packet));
Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
Packet.Timeout = SD_GENERIC_TIMEOUT;
SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;
SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
return Status;
}
/**
Send command SEND_STATUS to the device to get device status.
@param[in] Device A pointer to the SD_DEVICE instance.
@param[in] Rca The relative device address to use.
@param[out] DevStatus The buffer to store the device status.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
SdSendStatus (
IN SD_DEVICE *Device,
IN UINT16 Rca,
OUT UINT32 *DevStatus
)
{
EFI_STATUS Status;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
PassThru = Device->Private->PassThru;
ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
ZeroMem (&Packet, sizeof (Packet));
Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
Packet.Timeout = SD_GENERIC_TIMEOUT;
SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;
SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
if (!EFI_ERROR (Status)) {
CopyMem (DevStatus, &SdMmcStatusBlk.Resp0, sizeof (UINT32));
}
return Status;
}
/**
Send command SEND_CSD to the device to get the CSD register data.
@param[in] Device A pointer to the SD_DEVICE instance.
@param[in] Rca The relative device address to use.
@param[out] Csd The buffer to store the SD_CSD register data.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
SdGetCsd (
IN SD_DEVICE *Device,
IN UINT16 Rca,
OUT SD_CSD *Csd
)
{
EFI_STATUS Status;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
PassThru = Device->Private->PassThru;
ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
ZeroMem (&Packet, sizeof (Packet));
ZeroMem (Csd, sizeof (SD_CSD));
Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
Packet.Timeout = SD_GENERIC_TIMEOUT;
SdMmcCmdBlk.CommandIndex = SD_SEND_CSD;
SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
if (!EFI_ERROR (Status)) {
//
// For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
//
CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1);
}
return Status;
}
/**
Send command SEND_CID to the device to get the CID register data.
@param[in] Device A pointer to the SD_DEVICE instance.
@param[in] Rca The relative device address to use.
@param[out] Cid The buffer to store the SD_CID register data.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
SdGetCid (
IN SD_DEVICE *Device,
IN UINT16 Rca,
OUT SD_CID *Cid
)
{
EFI_STATUS Status;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
PassThru = Device->Private->PassThru;
ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
ZeroMem (&Packet, sizeof (Packet));
ZeroMem (Cid, sizeof (SD_CID));
Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
Packet.Timeout = SD_GENERIC_TIMEOUT;
SdMmcCmdBlk.CommandIndex = SD_SEND_CID;
SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
if (!EFI_ERROR (Status)) {
//
// For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
//
CopyMem (((UINT8*)Cid) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CID) - 1);
}
return Status;
}
/**
Read/write single block through sync or async I/O request.
@param[in] Device A pointer to the SD_DEVICE instance.
@param[in] Lba The starting logical block address to be read/written.
The caller is responsible for reading/writing to only
legitimate locations.
@param[in] Buffer A pointer to the destination/source buffer for the data.
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
@param[in] IsRead Indicates it is a read or write operation.
@param[in] Token A pointer to the token associated with the transaction.
@param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
This parameter is only meaningful in async I/O request.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
SdRwSingleBlock (
IN SD_DEVICE *Device,
IN EFI_LBA Lba,
IN VOID *Buffer,
IN UINTN BufferSize,
IN BOOLEAN IsRead,
IN EFI_BLOCK_IO2_TOKEN *Token,
IN BOOLEAN IsEnd
)
{
EFI_STATUS Status;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
SD_REQUEST *RwSingleBlkReq;
EFI_TPL OldTpl;
RwSingleBlkReq = NULL;
PassThru = Device->Private->PassThru;
RwSingleBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));
if (RwSingleBlkReq == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Error;
}
RwSingleBlkReq->Signature = SD_REQUEST_SIGNATURE;
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
InsertTailList (&Device->Queue, &RwSingleBlkReq->Link);
gBS->RestoreTPL (OldTpl);
RwSingleBlkReq->Packet.SdMmcCmdBlk = &RwSingleBlkReq->SdMmcCmdBlk;
RwSingleBlkReq->Packet.SdMmcStatusBlk = &RwSingleBlkReq->SdMmcStatusBlk;
//
// Calculate timeout value through the below formula.
// Timeout = (transfer size) / (2MB/s).
// Taking 2MB/s as divisor as it's the lowest transfer speed
// above class 2.
// Refer to SD Physical Layer Simplified spec section 3.4 for details.
//
RwSingleBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
if (IsRead) {
RwSingleBlkReq->Packet.InDataBuffer = Buffer;
RwSingleBlkReq->Packet.InTransferLength = (UINT32)BufferSize;
RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_SINGLE_BLOCK;
RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
} else {
RwSingleBlkReq->Packet.OutDataBuffer = Buffer;
RwSingleBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_SINGLE_BLOCK;
RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
}
if (Device->SectorAddressing) {
RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
} else {
RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);
}
RwSingleBlkReq->IsEnd = IsEnd;
RwSingleBlkReq->Token = Token;
if ((Token != NULL) && (Token->Event != NULL)) {
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
AsyncIoCallback,
RwSingleBlkReq,
&RwSingleBlkReq->Event
);
if (EFI_ERROR (Status)) {
goto Error;
}
} else {
RwSingleBlkReq->Event = NULL;
}
Status = PassThru->PassThru (PassThru, Device->Slot, &RwSingleBlkReq->Packet, RwSingleBlkReq->Event);
Error:
if ((Token != NULL) && (Token->Event != NULL)) {
//
// For asynchronous operation, only free request and event in error case.
// The request and event will be freed in asynchronous callback for success case.
//
if (EFI_ERROR (Status) && (RwSingleBlkReq != NULL)) {
RemoveEntryList (&RwSingleBlkReq->Link);
if (RwSingleBlkReq->Event != NULL) {
gBS->CloseEvent (RwSingleBlkReq->Event);
}
FreePool (RwSingleBlkReq);
}
} else {
//
// For synchronous operation, free request whatever the execution result is.
//
if (RwSingleBlkReq != NULL) {
RemoveEntryList (&RwSingleBlkReq->Link);
FreePool (RwSingleBlkReq);
}
}
return Status;
}
/**
Read/write multiple blocks through sync or async I/O request.
@param[in] Device A pointer to the SD_DEVICE instance.
@param[in] Lba The starting logical block address to be read/written.
The caller is responsible for reading/writing to only
legitimate locations.
@param[in] Buffer A pointer to the destination/source buffer for the data.
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
@param[in] IsRead Indicates it is a read or write operation.
@param[in] Token A pointer to the token associated with the transaction.
@param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
This parameter is only meaningful in async I/O request.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
SdRwMultiBlocks (
IN SD_DEVICE *Device,
IN EFI_LBA Lba,
IN VOID *Buffer,
IN UINTN BufferSize,
IN BOOLEAN IsRead,
IN EFI_BLOCK_IO2_TOKEN *Token,
IN BOOLEAN IsEnd
)
{
EFI_STATUS Status;
SD_REQUEST *RwMultiBlkReq;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
EFI_TPL OldTpl;
RwMultiBlkReq = NULL;
PassThru = Device->Private->PassThru;
RwMultiBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));
if (RwMultiBlkReq == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Error;
}
RwMultiBlkReq->Signature = SD_REQUEST_SIGNATURE;
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
InsertTailList (&Device->Queue, &RwMultiBlkReq->Link);
gBS->RestoreTPL (OldTpl);
RwMultiBlkReq->Packet.SdMmcCmdBlk = &RwMultiBlkReq->SdMmcCmdBlk;
RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk;
//
// Calculate timeout value through the below formula.
// Timeout = (transfer size) / (2MB/s).
// Taking 2MB/s as divisor as it's the lowest transfer speed
// above class 2.
// Refer to SD Physical Layer Simplified spec section 3.4 for details.
//
RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
if (IsRead) {
RwMultiBlkReq->Packet.InDataBuffer = Buffer;
RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;
RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK;
RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
} else {
RwMultiBlkReq->Packet.OutDataBuffer = Buffer;
RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK;
RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
}
if (Device->SectorAddressing) {
RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
} else {
RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);
}
RwMultiBlkReq->IsEnd = IsEnd;
RwMultiBlkReq->Token = Token;
if ((Token != NULL) && (Token->Event != NULL)) {
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
AsyncIoCallback,
RwMultiBlkReq,
&RwMultiBlkReq->Event
);
if (EFI_ERROR (Status)) {
goto Error;
}
} else {
RwMultiBlkReq->Event = NULL;
}
Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);
Error:
if ((Token != NULL) && (Token->Event != NULL)) {
//
// For asynchronous operation, only free request and event in error case.
// The request and event will be freed in asynchronous callback for success case.
//
if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {
RemoveEntryList (&RwMultiBlkReq->Link);
if (RwMultiBlkReq->Event != NULL) {
gBS->CloseEvent (RwMultiBlkReq->Event);
}
FreePool (RwMultiBlkReq);
}
} else {
//
// For synchronous operation, free request whatever the execution result is.
//
if (RwMultiBlkReq != NULL) {
RemoveEntryList (&RwMultiBlkReq->Link);
FreePool (RwMultiBlkReq);
}
}
return Status;
}
/**
This function transfers data from/to the sd memory card device.
@param[in] Device A pointer to the SD_DEVICE instance.
@param[in] MediaId The media ID that the read/write request is for.
@param[in] Lba The starting logical block address to be read/written.
The caller is responsible for reading/writing to only
legitimate locations.
@param[in, out] Buffer A pointer to the destination/source buffer for the data.
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
@param[in] IsRead Indicates it is a read or write operation.
@param[in, out] Token A pointer to the token associated with the transaction.
@retval EFI_SUCCESS The data was read/written correctly to the device.
@retval EFI_WRITE_PROTECTED The device can not be read/written to.
@retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
@retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,
or the buffer is not on proper alignment.
**/
EFI_STATUS
SdReadWrite (
IN SD_DEVICE *Device,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN OUT VOID *Buffer,
IN UINTN BufferSize,
IN BOOLEAN IsRead,
IN OUT EFI_BLOCK_IO2_TOKEN *Token
)
{
EFI_STATUS Status;
EFI_BLOCK_IO_MEDIA *Media;
UINTN BlockSize;
UINTN BlockNum;
UINTN IoAlign;
UINTN Remaining;
UINT32 MaxBlock;
BOOLEAN LastRw;
Status = EFI_SUCCESS;
Media = &Device->BlockMedia;
LastRw = FALSE;
if (MediaId != Media->MediaId) {
return EFI_MEDIA_CHANGED;
}
if (!IsRead && Media->ReadOnly) {
return EFI_WRITE_PROTECTED;
}
//
// Check parameters.
//
if (Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
if (BufferSize == 0) {
if ((Token != NULL) && (Token->Event != NULL)) {
Token->TransactionStatus = EFI_SUCCESS;
gBS->SignalEvent (Token->Event);
}
return EFI_SUCCESS;
}
BlockSize = Media->BlockSize;
if ((BufferSize % BlockSize) != 0) {
return EFI_BAD_BUFFER_SIZE;
}
BlockNum = BufferSize / BlockSize;
if ((Lba + BlockNum - 1) > Media->LastBlock) {
return EFI_INVALID_PARAMETER;
}
IoAlign = Media->IoAlign;
if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
return EFI_INVALID_PARAMETER;
}
if ((Token != NULL) && (Token->Event != NULL)) {
Token->TransactionStatus = EFI_SUCCESS;
}
//
// Start to execute data transfer. The max block number in single cmd is 65535 blocks.
//
Remaining = BlockNum;
MaxBlock = 0xFFFF;
while (Remaining > 0) {
if (Remaining <= MaxBlock) {
BlockNum = Remaining;
LastRw = TRUE;
} else {
BlockNum = MaxBlock;
}
BufferSize = BlockNum * BlockSize;
if (BlockNum == 1) {
Status = SdRwSingleBlock (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
} else {
Status = SdRwMultiBlocks (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
}
if (EFI_ERROR (Status)) {
return Status;
}
DEBUG ((EFI_D_INFO, "Sd%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", IsRead ? "Read" : "Write", Lba, BlockNum, Token->Event, Status));
Lba += BlockNum;
Buffer = (UINT8*)Buffer + BufferSize;
Remaining -= BlockNum;
}
return Status;
}
/**
Reset the Block Device.
@param This Indicates a pointer to the calling context.
@param ExtendedVerification Driver may perform diagnostics on reset.
@retval EFI_SUCCESS The device was reset.
@retval EFI_DEVICE_ERROR The device is not functioning properly and could
not be reset.
**/
EFI_STATUS
EFIAPI
SdReset (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
)
{
EFI_STATUS Status;
SD_DEVICE *Device;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
Device = SD_DEVICE_DATA_FROM_BLKIO (This);
PassThru = Device->Private->PassThru;
Status = PassThru->ResetDevice (PassThru, Device->Slot);
if (EFI_ERROR (Status)) {
Status = EFI_DEVICE_ERROR;
}
return Status;
}
/**
Read BufferSize bytes from Lba into Buffer.
@param This Indicates a pointer to the calling context.
@param MediaId Id of the media, changes every time the media is replaced.
@param Lba The starting Logical Block Address to read from
@param BufferSize Size of Buffer, must be a multiple of device block size.
@param Buffer A pointer to the destination buffer for the data. The caller is
responsible for either having implicit or explicit ownership of the buffer.
@retval EFI_SUCCESS The data was read correctly from the device.
@retval EFI_DEVICE_ERROR The device reported an error while performing the read.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
or the buffer is not on proper alignment.
**/
EFI_STATUS
EFIAPI
SdReadBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
OUT VOID *Buffer
)
{
EFI_STATUS Status;
SD_DEVICE *Device;
Device = SD_DEVICE_DATA_FROM_BLKIO (This);
Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);
return Status;
}
/**
Write BufferSize bytes from Lba into Buffer.
@param This Indicates a pointer to the calling context.
@param MediaId The media ID that the write request is for.
@param Lba The starting logical block address to be written. The caller is
responsible for writing to only legitimate locations.
@param BufferSize Size of Buffer, must be a multiple of device block size.
@param Buffer A pointer to the source buffer for the data.
@retval EFI_SUCCESS The data was written correctly to the device.
@retval EFI_WRITE_PROTECTED The device can not be written to.
@retval EFI_DEVICE_ERROR The device reported an error while performing the write.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
@retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
or the buffer is not on proper alignment.
**/
EFI_STATUS
EFIAPI
SdWriteBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
IN VOID *Buffer
)
{
EFI_STATUS Status;
SD_DEVICE *Device;
Device = SD_DEVICE_DATA_FROM_BLKIO (This);
Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);
return Status;
}
/**
Flush the Block Device.
@param This Indicates a pointer to the calling context.
@retval EFI_SUCCESS All outstanding data was written to the device
@retval EFI_DEVICE_ERROR The device reported an error while writing back the data
@retval EFI_NO_MEDIA There is no media in the device.
**/
EFI_STATUS
EFIAPI
SdFlushBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This
)
{
//
// return directly
//
return EFI_SUCCESS;
}
/**
Reset the Block Device.
@param[in] This Indicates a pointer to the calling context.
@param[in] ExtendedVerification Driver may perform diagnostics on reset.
@retval EFI_SUCCESS The device was reset.
@retval EFI_DEVICE_ERROR The device is not functioning properly and could
not be reset.
**/
EFI_STATUS
EFIAPI
SdResetEx (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
)
{
SD_DEVICE *Device;
LIST_ENTRY *Link;
LIST_ENTRY *NextLink;
SD_REQUEST *Request;
EFI_TPL OldTpl;
Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
for (Link = GetFirstNode (&Device->Queue);
!IsNull (&Device->Queue, Link);
Link = NextLink) {
NextLink = GetNextNode (&Device->Queue, Link);
RemoveEntryList (Link);
Request = SD_REQUEST_FROM_LINK (Link);
gBS->CloseEvent (Request->Event);
Request->Token->TransactionStatus = EFI_ABORTED;
if (Request->IsEnd) {
gBS->SignalEvent (Request->Token->Event);
}
FreePool (Request);
}
gBS->RestoreTPL (OldTpl);
return EFI_SUCCESS;
}
/**
Read BufferSize bytes from Lba into Buffer.
@param[in] This Indicates a pointer to the calling context.
@param[in] MediaId Id of the media, changes every time the media is replaced.
@param[in] Lba The starting Logical Block Address to read from.
@param[in, out] Token A pointer to the token associated with the transaction.
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
@param[out] Buffer A pointer to the destination buffer for the data. The caller is
responsible for either having implicit or explicit ownership of the buffer.
@retval EFI_SUCCESS The read request was queued if Event is not NULL.
The data was read correctly from the device if
the Event is NULL.
@retval EFI_DEVICE_ERROR The device reported an error while performing
the read.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
intrinsic block size of the device.
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
or the buffer is not on proper alignment.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
**/
EFI_STATUS
EFIAPI
SdReadBlocksEx (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
IN UINTN BufferSize,
OUT VOID *Buffer
)
{
EFI_STATUS Status;
SD_DEVICE *Device;
Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, Token);
return Status;
}
/**
Write BufferSize bytes from Lba into Buffer.
@param[in] This Indicates a pointer to the calling context.
@param[in] MediaId The media ID that the write request is for.
@param[in] Lba The starting logical block address to be written. The
caller is responsible for writing to only legitimate
locations.
@param[in, out] Token A pointer to the token associated with the transaction.
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
@param[in] Buffer A pointer to the source buffer for the data.
@retval EFI_SUCCESS The data was written correctly to the device.
@retval EFI_WRITE_PROTECTED The device can not be written to.
@retval EFI_DEVICE_ERROR The device reported an error while performing the write.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
@retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
or the buffer is not on proper alignment.
**/
EFI_STATUS
EFIAPI
SdWriteBlocksEx (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
IN UINTN BufferSize,
IN VOID *Buffer
)
{
EFI_STATUS Status;
SD_DEVICE *Device;
Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, Token);
return Status;
}
/**
Flush the Block Device.
@param[in] This Indicates a pointer to the calling context.
@param[in, out] Token A pointer to the token associated with the transaction.
@retval EFI_SUCCESS All outstanding data was written to the device
@retval EFI_DEVICE_ERROR The device reported an error while writing back the data
@retval EFI_NO_MEDIA There is no media in the device.
**/
EFI_STATUS
EFIAPI
SdFlushBlocksEx (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN OUT EFI_BLOCK_IO2_TOKEN *Token
)
{
//
// Signal event and return directly.
//
if (Token != NULL && Token->Event != NULL) {
Token->TransactionStatus = EFI_SUCCESS;
gBS->SignalEvent (Token->Event);
}
return EFI_SUCCESS;
}

View File

@ -0,0 +1,221 @@
/** @file
Header file for SdDxe Driver.
This file defines common data structures, macro definitions and some module
internal function header files.
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_H_
#define _SD_BLOCK_IO_H_
/**
Reset the Block Device.
@param This Indicates a pointer to the calling context.
@param ExtendedVerification Driver may perform diagnostics on reset.
@retval EFI_SUCCESS The device was reset.
@retval EFI_DEVICE_ERROR The device is not functioning properly and could
not be reset.
**/
EFI_STATUS
EFIAPI
SdReset (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
);
/**
Read BufferSize bytes from Lba into Buffer.
@param This Indicates a pointer to the calling context.
@param MediaId Id of the media, changes every time the media is replaced.
@param Lba The starting Logical Block Address to read from
@param BufferSize Size of Buffer, must be a multiple of device block size.
@param Buffer A pointer to the destination buffer for the data. The caller is
responsible for either having implicit or explicit ownership of the buffer.
@retval EFI_SUCCESS The data was read correctly from the device.
@retval EFI_DEVICE_ERROR The device reported an error while performing the read.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
or the buffer is not on proper alignment.
**/
EFI_STATUS
EFIAPI
SdReadBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
OUT VOID *Buffer
);
/**
Write BufferSize bytes from Lba into Buffer.
@param This Indicates a pointer to the calling context.
@param MediaId The media ID that the write request is for.
@param Lba The starting logical block address to be written. The caller is
responsible for writing to only legitimate locations.
@param BufferSize Size of Buffer, must be a multiple of device block size.
@param Buffer A pointer to the source buffer for the data.
@retval EFI_SUCCESS The data was written correctly to the device.
@retval EFI_WRITE_PROTECTED The device can not be written to.
@retval EFI_DEVICE_ERROR The device reported an error while performing the write.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
@retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
or the buffer is not on proper alignment.
**/
EFI_STATUS
EFIAPI
SdWriteBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
IN VOID *Buffer
);
/**
Flush the Block Device.
@param This Indicates a pointer to the calling context.
@retval EFI_SUCCESS All outstanding data was written to the device
@retval EFI_DEVICE_ERROR The device reported an error while writing back the data
@retval EFI_NO_MEDIA There is no media in the device.
**/
EFI_STATUS
EFIAPI
SdFlushBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This
);
/**
Reset the Block Device.
@param[in] This Indicates a pointer to the calling context.
@param[in] ExtendedVerification Driver may perform diagnostics on reset.
@retval EFI_SUCCESS The device was reset.
@retval EFI_DEVICE_ERROR The device is not functioning properly and could
not be reset.
**/
EFI_STATUS
EFIAPI
SdResetEx (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
);
/**
Read BufferSize bytes from Lba into Buffer.
@param[in] This Indicates a pointer to the calling context.
@param[in] MediaId Id of the media, changes every time the media is replaced.
@param[in] Lba The starting Logical Block Address to read from.
@param[in, out] Token A pointer to the token associated with the transaction.
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
@param[out] Buffer A pointer to the destination buffer for the data. The caller is
responsible for either having implicit or explicit ownership of the buffer.
@retval EFI_SUCCESS The read request was queued if Event is not NULL.
The data was read correctly from the device if
the Event is NULL.
@retval EFI_DEVICE_ERROR The device reported an error while performing
the read.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
intrinsic block size of the device.
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
or the buffer is not on proper alignment.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
**/
EFI_STATUS
EFIAPI
SdReadBlocksEx (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
IN UINTN BufferSize,
OUT VOID *Buffer
);
/**
Write BufferSize bytes from Lba into Buffer.
@param[in] This Indicates a pointer to the calling context.
@param[in] MediaId The media ID that the write request is for.
@param[in] Lba The starting logical block address to be written. The
caller is responsible for writing to only legitimate
locations.
@param[in, out] Token A pointer to the token associated with the transaction.
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
@param[in] Buffer A pointer to the source buffer for the data.
@retval EFI_SUCCESS The data was written correctly to the device.
@retval EFI_WRITE_PROTECTED The device can not be written to.
@retval EFI_DEVICE_ERROR The device reported an error while performing the write.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
@retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
or the buffer is not on proper alignment.
**/
EFI_STATUS
EFIAPI
SdWriteBlocksEx (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
IN UINTN BufferSize,
IN VOID *Buffer
);
/**
Flush the Block Device.
@param[in] This Indicates a pointer to the calling context.
@param[in, out] Token A pointer to the token associated with the transaction.
@retval EFI_SUCCESS All outstanding data was written to the device
@retval EFI_DEVICE_ERROR The device reported an error while writing back the data
@retval EFI_NO_MEDIA There is no media in the device.
**/
EFI_STATUS
EFIAPI
SdFlushBlocksEx (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN OUT EFI_BLOCK_IO2_TOKEN *Token
);
#endif

View File

@ -0,0 +1,888 @@
/** @file
The SdDxe driver is used to manage the SD memory card device.
It produces BlockIo and BlockIo2 protocols to allow upper layer
access the SD memory card device.
Copyright (c) 2015 - 2016, 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 "SdDxe.h"
//
// SdDxe Driver Binding Protocol Instance
//
EFI_DRIVER_BINDING_PROTOCOL gSdDxeDriverBinding = {
SdDxeDriverBindingSupported,
SdDxeDriverBindingStart,
SdDxeDriverBindingStop,
0x10,
NULL,
NULL
};
//
// Template for SD_DEVICE data structure.
//
SD_DEVICE mSdDeviceTemplate = {
SD_DEVICE_SIGNATURE, // Signature
NULL, // Handle
NULL, // DevicePath
0xFF, // Slot
FALSE, // SectorAddressing
{ // BlockIo
EFI_BLOCK_IO_PROTOCOL_REVISION,
NULL,
SdReset,
SdReadBlocks,
SdWriteBlocks,
SdFlushBlocks
},
{ // BlockIo2
NULL,
SdResetEx,
SdReadBlocksEx,
SdWriteBlocksEx,
SdFlushBlocksEx
},
{ // BlockMedia
0, // MediaId
FALSE, // RemovableMedia
TRUE, // MediaPresent
FALSE, // LogicPartition
FALSE, // ReadOnly
FALSE, // WritingCache
0x200, // BlockSize
0, // IoAlign
0 // LastBlock
},
{ // Queue
NULL,
NULL
},
{ // Csd
0,
},
{ // Cid
0,
},
NULL, // ControllerNameTable
{ // ModelName
0,
},
NULL // Private
};
/**
Decode and print SD CSD Register content.
@param[in] Csd Pointer to SD_CSD data structure.
@retval EFI_SUCCESS The function completed successfully
**/
EFI_STATUS
DumpCsd (
IN SD_CSD *Csd
)
{
SD_CSD2 *Csd2;
DEBUG((DEBUG_INFO, "== Dump Sd Csd Register==\n"));
DEBUG((DEBUG_INFO, " CSD structure 0x%x\n", Csd->CsdStructure));
DEBUG((DEBUG_INFO, " Data read access-time 1 0x%x\n", Csd->Taac));
DEBUG((DEBUG_INFO, " Data read access-time 2 0x%x\n", Csd->Nsac));
DEBUG((DEBUG_INFO, " Max. bus clock frequency 0x%x\n", Csd->TranSpeed));
DEBUG((DEBUG_INFO, " Device command classes 0x%x\n", Csd->Ccc));
DEBUG((DEBUG_INFO, " Max. read data block length 0x%x\n", Csd->ReadBlLen));
DEBUG((DEBUG_INFO, " Partial blocks for read allowed 0x%x\n", Csd->ReadBlPartial));
DEBUG((DEBUG_INFO, " Write block misalignment 0x%x\n", Csd->WriteBlkMisalign));
DEBUG((DEBUG_INFO, " Read block misalignment 0x%x\n", Csd->ReadBlkMisalign));
DEBUG((DEBUG_INFO, " DSR implemented 0x%x\n", Csd->DsrImp));
if (Csd->CsdStructure == 0) {
DEBUG((DEBUG_INFO, " Device size 0x%x\n", Csd->CSizeLow | (Csd->CSizeHigh << 2)));
DEBUG((DEBUG_INFO, " Max. read current @ VDD min 0x%x\n", Csd->VddRCurrMin));
DEBUG((DEBUG_INFO, " Max. read current @ VDD max 0x%x\n", Csd->VddRCurrMax));
DEBUG((DEBUG_INFO, " Max. write current @ VDD min 0x%x\n", Csd->VddWCurrMin));
DEBUG((DEBUG_INFO, " Max. write current @ VDD max 0x%x\n", Csd->VddWCurrMax));
} else {
Csd2 = (SD_CSD2*)(VOID*)Csd;
DEBUG((DEBUG_INFO, " Device size 0x%x\n", Csd2->CSizeLow | (Csd->CSizeHigh << 16)));
}
DEBUG((DEBUG_INFO, " Erase sector size 0x%x\n", Csd->SectorSize));
DEBUG((DEBUG_INFO, " Erase single block enable 0x%x\n", Csd->EraseBlkEn));
DEBUG((DEBUG_INFO, " Write protect group size 0x%x\n", Csd->WpGrpSize));
DEBUG((DEBUG_INFO, " Write protect group enable 0x%x\n", Csd->WpGrpEnable));
DEBUG((DEBUG_INFO, " Write speed factor 0x%x\n", Csd->R2WFactor));
DEBUG((DEBUG_INFO, " Max. write data block length 0x%x\n", Csd->WriteBlLen));
DEBUG((DEBUG_INFO, " Partial blocks for write allowed 0x%x\n", Csd->WriteBlPartial));
DEBUG((DEBUG_INFO, " File format group 0x%x\n", Csd->FileFormatGrp));
DEBUG((DEBUG_INFO, " Copy flag (OTP) 0x%x\n", Csd->Copy));
DEBUG((DEBUG_INFO, " Permanent write protection 0x%x\n", Csd->PermWriteProtect));
DEBUG((DEBUG_INFO, " Temporary write protection 0x%x\n", Csd->TmpWriteProtect));
DEBUG((DEBUG_INFO, " File format 0x%x\n", Csd->FileFormat));
return EFI_SUCCESS;
}
/**
Get SD device model name.
@param[in, out] Device The pointer to the SD_DEVICE data structure.
@param[in] Cid Pointer to SD_CID data structure.
@retval EFI_SUCCESS The function completed successfully
**/
EFI_STATUS
GetSdModelName (
IN OUT SD_DEVICE *Device,
IN SD_CID *Cid
)
{
CHAR8 String[SD_MODEL_NAME_MAX_LEN];
ZeroMem (String, sizeof (String));
CopyMem (String, Cid->OemId, sizeof (Cid->OemId));
String[sizeof (Cid->OemId)] = ' ';
CopyMem (String + sizeof (Cid->OemId) + 1, Cid->ProductName, sizeof (Cid->ProductName));
String[sizeof (Cid->OemId) + sizeof (Cid->ProductName)] = ' ';
CopyMem (String + sizeof (Cid->OemId) + sizeof (Cid->ProductName) + 1, Cid->ProductSerialNumber, sizeof (Cid->ProductSerialNumber));
AsciiStrToUnicodeStr (String, Device->ModelName);
return EFI_SUCCESS;
}
/**
Discover user area partition in the SD device.
@param[in] Device The pointer to the SD_DEVICE data structure.
@retval EFI_SUCCESS The user area partition in the SD device is successfully identified.
@return Others Some error occurs when identifying the user area.
**/
EFI_STATUS
DiscoverUserArea (
IN SD_DEVICE *Device
)
{
EFI_STATUS Status;
SD_CSD *Csd;
SD_CSD2 *Csd2;
SD_CID *Cid;
UINT64 Capacity;
UINT32 DevStatus;
UINT16 Rca;
UINT32 CSize;
UINT32 CSizeMul;
UINT32 ReadBlLen;
//
// Deselect the device to force it enter stby mode.
// Note here we don't judge return status as some SD devices return
// error but the state has been stby.
//
SdSelect (Device, 0);
Status = SdSetRca (Device, &Rca);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "DiscoverUserArea(): Assign new Rca = 0x%x fails with %r\n", Rca, Status));
return Status;
}
Csd = &Device->Csd;
Status = SdGetCsd (Device, Rca, Csd);
if (EFI_ERROR (Status)) {
return Status;
}
DumpCsd (Csd);
Cid = &Device->Cid;
Status = SdGetCid (Device, Rca, Cid);
if (EFI_ERROR (Status)) {
return Status;
}
GetSdModelName (Device, Cid);
Status = SdSelect (Device, Rca);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "DiscoverUserArea(): Reselect the device 0x%x fails with %r\n", Rca, Status));
return Status;
}
Status = SdSendStatus (Device, Rca, &DevStatus);
if (EFI_ERROR (Status)) {
return Status;
}
if (Csd->CsdStructure == 0) {
Device->SectorAddressing = FALSE;
CSize = (Csd->CSizeHigh << 2 | Csd->CSizeLow) + 1;
CSizeMul = (1 << (Csd->CSizeMul + 2));
ReadBlLen = (1 << (Csd->ReadBlLen));
Capacity = MultU64x32 (MultU64x32 ((UINT64)CSize, CSizeMul), ReadBlLen);
} else {
Device->SectorAddressing = TRUE;
Csd2 = (SD_CSD2*)(VOID*)Csd;
CSize = (Csd2->CSizeHigh << 16 | Csd2->CSizeLow) + 1;
Capacity = MultU64x32 ((UINT64)CSize, SIZE_512KB);
}
Device->BlockIo.Media = &Device->BlockMedia;
Device->BlockIo2.Media = &Device->BlockMedia;
Device->BlockMedia.IoAlign = Device->Private->PassThru->IoAlign;
Device->BlockMedia.BlockSize = 0x200;
Device->BlockMedia.LastBlock = 0x00;
Device->BlockMedia.RemovableMedia = TRUE;
Device->BlockMedia.MediaPresent = TRUE;
Device->BlockMedia.LogicalPartition = FALSE;
Device->BlockMedia.LastBlock = DivU64x32 (Capacity, Device->BlockMedia.BlockSize) - 1;
return Status;
}
/**
Scan SD Bus to discover the device.
@param[in] Private The SD driver private data structure.
@param[in] Slot The slot number to check device present.
@retval EFI_SUCCESS Successfully to discover the device and attach
SdMmcIoProtocol to it.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
@retval EFI_ALREADY_STARTED The device was discovered before.
@retval Others Fail to discover the device.
**/
EFI_STATUS
EFIAPI
DiscoverSdDevice (
IN SD_DRIVER_PRIVATE_DATA *Private,
IN UINT8 Slot
)
{
EFI_STATUS Status;
SD_DEVICE *Device;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
EFI_HANDLE DeviceHandle;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
Device = NULL;
DevicePath = NULL;
NewDevicePath = NULL;
RemainingDevicePath = NULL;
PassThru = Private->PassThru;
//
// Build Device Path
//
Status = PassThru->BuildDevicePath (
PassThru,
Slot,
&DevicePath
);
if (EFI_ERROR(Status)) {
return Status;
}
if (DevicePath->SubType != MSG_SD_DP) {
Status = EFI_UNSUPPORTED;
goto Error;
}
NewDevicePath = AppendDevicePathNode (
Private->ParentDevicePath,
DevicePath
);
if (NewDevicePath == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Error;
}
DeviceHandle = NULL;
RemainingDevicePath = NewDevicePath;
Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);
if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {
//
// The device has been started, directly return to fast boot.
//
Status = EFI_ALREADY_STARTED;
goto Error;
}
//
// Allocate buffer to store SD_DEVICE private data.
//
Device = AllocateCopyPool (sizeof (SD_DEVICE), &mSdDeviceTemplate);
if (Device == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Error;
}
Device->DevicePath = NewDevicePath;
Device->Slot = Slot;
Device->Private = Private;
InitializeListHead (&Device->Queue);
//
// Expose user area in the Sd memory card to upper layer.
//
Status = DiscoverUserArea (Device);
if (EFI_ERROR(Status)) {
goto Error;
}
Device->ControllerNameTable = NULL;
AddUnicodeString2 (
"eng",
gSdDxeComponentName.SupportedLanguages,
&Device->ControllerNameTable,
Device->ModelName,
TRUE
);
AddUnicodeString2 (
"en",
gSdDxeComponentName.SupportedLanguages,
&Device->ControllerNameTable,
Device->ModelName,
FALSE
);
Status = gBS->InstallMultipleProtocolInterfaces (
&Device->Handle,
&gEfiDevicePathProtocolGuid,
Device->DevicePath,
&gEfiBlockIoProtocolGuid,
&Device->BlockIo,
&gEfiBlockIo2ProtocolGuid,
&Device->BlockIo2,
NULL
);
if (!EFI_ERROR (Status)) {
gBS->OpenProtocol (
Private->Controller,
&gEfiSdMmcPassThruProtocolGuid,
(VOID **) &(Private->PassThru),
Private->DriverBindingHandle,
Device->Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
}
Error:
FreePool (DevicePath);
if (EFI_ERROR (Status) && (NewDevicePath != NULL)) {
FreePool (NewDevicePath);
}
if (EFI_ERROR (Status) && (Device != NULL)) {
FreePool (Device);
}
return Status;
}
/**
Tests to see if this driver supports a given controller. If a child device is provided,
it further tests to see if this driver supports creating a handle for the specified child device.
This function checks to see if the driver specified by This supports the device specified by
ControllerHandle. Drivers will typically use the device path attached to
ControllerHandle and/or the services from the bus I/O abstraction attached to
ControllerHandle to determine if the driver supports ControllerHandle. This function
may be called many times during platform initialization. In order to reduce boot times, the tests
performed by this function must be very small, and take as little time as possible to execute. This
function must not change the state of any hardware devices, and this function must be aware that the
device specified by ControllerHandle may already be managed by the same driver or a
different driver. This function must match its calls to AllocatePages() with FreePages(),
AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
Since ControllerHandle may have been previously started by the same driver, if a protocol is
already in the opened state, then it must not be closed with CloseProtocol(). This is required
to guarantee the state of ControllerHandle is not modified by this function.
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param[in] ControllerHandle The handle of the controller to test. This handle
must support a protocol interface that supplies
an I/O abstraction to the driver.
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
parameter is ignored by device drivers, and is optional for bus
drivers. For bus drivers, if this parameter is not NULL, then
the bus driver must determine if the bus controller specified
by ControllerHandle and the child controller specified
by RemainingDevicePath are both supported by this
bus driver.
@retval EFI_SUCCESS The device specified by ControllerHandle and
RemainingDevicePath is supported by the driver specified by This.
@retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
RemainingDevicePath is already being managed by the driver
specified by This.
@retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
RemainingDevicePath is already being managed by a different
driver or an application that requires exclusive access.
Currently not implemented.
@retval EFI_UNSUPPORTED The device specified by ControllerHandle and
RemainingDevicePath is not supported by the driver specified by This.
**/
EFI_STATUS
EFIAPI
SdDxeDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
UINT8 Slot;
//
// Test EFI_SD_MMC_PASS_THRU_PROTOCOL on the controller handle.
//
Status = gBS->OpenProtocol (
Controller,
&gEfiSdMmcPassThruProtocolGuid,
(VOID**) &PassThru,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (Status == EFI_ALREADY_STARTED) {
return EFI_SUCCESS;
}
if (EFI_ERROR (Status)) {
return Status;
}
//
// Test RemainingDevicePath is valid or not.
//
if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {
Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);
if (EFI_ERROR (Status)) {
//
// Close the I/O Abstraction(s) used to perform the supported test
//
gBS->CloseProtocol (
Controller,
&gEfiSdMmcPassThruProtocolGuid,
This->DriverBindingHandle,
Controller
);
return Status;
}
}
//
// Close the I/O Abstraction(s) used to perform the supported test
//
gBS->CloseProtocol (
Controller,
&gEfiSdMmcPassThruProtocolGuid,
This->DriverBindingHandle,
Controller
);
//
// Open the EFI Device Path protocol needed to perform the supported test
//
Status = gBS->OpenProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
(VOID **) &ParentDevicePath,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
return Status;
}
/**
Starts a device controller or a bus controller.
The Start() function is designed to be invoked from the EFI boot service ConnectController().
As a result, much of the error checking on the parameters to Start() has been moved into this
common boot service. It is legal to call Start() from other locations,
but the following calling restrictions must be followed or the system behavior will not be deterministic.
1. ControllerHandle must be a valid EFI_HANDLE.
2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
EFI_DEVICE_PATH_PROTOCOL.
3. Prior to calling Start(), the Supported() function for the driver specified by This must
have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param[in] ControllerHandle The handle of the controller to start. This handle
must support a protocol interface that supplies
an I/O abstraction to the driver.
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
parameter is ignored by device drivers, and is optional for bus
drivers. For a bus driver, if this parameter is NULL, then handles
for all the children of Controller are created by this driver.
If this parameter is not NULL and the first Device Path Node is
not the End of Device Path Node, then only the handle for the
child device specified by the first Device Path Node of
RemainingDevicePath is created by this driver.
If the first Device Path Node of RemainingDevicePath is
the End of Device Path Node, no child handle is created by this
driver.
@retval EFI_SUCCESS The device was started.
@retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
@retval Others The driver failded to start the device.
**/
EFI_STATUS
EFIAPI
SdDxeDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
SD_DRIVER_PRIVATE_DATA *Private;
UINT8 Slot;
Private = NULL;
PassThru = NULL;
Status = gBS->OpenProtocol (
Controller,
&gEfiSdMmcPassThruProtocolGuid,
(VOID **) &PassThru,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
return Status;
}
//
// Check EFI_ALREADY_STARTED to reuse the original SD_DRIVER_PRIVATE_DATA.
//
if (Status != EFI_ALREADY_STARTED) {
Private = AllocateZeroPool (sizeof (SD_DRIVER_PRIVATE_DATA));
if (Private == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Error;
}
Status = gBS->OpenProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
(VOID **) &ParentDevicePath,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
ASSERT_EFI_ERROR (Status);
Private->PassThru = PassThru;
Private->Controller = Controller;
Private->ParentDevicePath = ParentDevicePath;
Private->DriverBindingHandle = This->DriverBindingHandle;
Status = gBS->InstallProtocolInterface (
&Controller,
&gEfiCallerIdGuid,
EFI_NATIVE_INTERFACE,
Private
);
if (EFI_ERROR (Status)) {
goto Error;
}
} else {
Status = gBS->OpenProtocol (
Controller,
&gEfiCallerIdGuid,
(VOID **) &Private,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
goto Error;
}
}
if (RemainingDevicePath == NULL) {
Slot = 0xFF;
while (TRUE) {
Status = PassThru->GetNextSlot (PassThru, &Slot);
if (EFI_ERROR (Status)) {
//
// Cannot find more legal slots.
//
Status = EFI_SUCCESS;
break;
}
Status = DiscoverSdDevice (Private, Slot);
if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
break;
}
}
} else if (!IsDevicePathEnd (RemainingDevicePath)) {
Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);
if (!EFI_ERROR (Status)) {
Status = DiscoverSdDevice (Private, Slot);
}
}
Error:
if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
gBS->CloseProtocol (
Controller,
&gEfiSdMmcPassThruProtocolGuid,
This->DriverBindingHandle,
Controller
);
if (Private != NULL) {
gBS->UninstallMultipleProtocolInterfaces (
Controller,
&gEfiCallerIdGuid,
Private,
NULL
);
FreePool (Private);
}
}
return Status;
}
/**
Stops a device controller or a bus controller.
The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
As a result, much of the error checking on the parameters to Stop() has been moved
into this common boot service. It is legal to call Stop() from other locations,
but the following calling restrictions must be followed or the system behavior will not be deterministic.
1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
same driver's Start() function.
2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
EFI_HANDLE. In addition, all of these handles must have been created in this driver's
Start() function, and the Start() function must have called OpenProtocol() on
ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param[in] ControllerHandle A handle to the device being stopped. The handle must
support a bus specific I/O protocol for the driver
to use to stop the device.
@param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
@param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
if NumberOfChildren is 0.
@retval EFI_SUCCESS The device was stopped.
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
**/
EFI_STATUS
EFIAPI
SdDxeDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_STATUS Status;
BOOLEAN AllChildrenStopped;
UINTN Index;
SD_DRIVER_PRIVATE_DATA *Private;
SD_DEVICE *Device;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
LIST_ENTRY *Link;
LIST_ENTRY *NextLink;
SD_REQUEST *Request;
EFI_TPL OldTpl;
if (NumberOfChildren == 0) {
Status = gBS->OpenProtocol (
Controller,
&gEfiCallerIdGuid,
(VOID **) &Private,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
gBS->UninstallProtocolInterface (
Controller,
&gEfiCallerIdGuid,
Private
);
gBS->CloseProtocol (
Controller,
&gEfiSdMmcPassThruProtocolGuid,
This->DriverBindingHandle,
Controller
);
FreePool (Private);
return EFI_SUCCESS;
}
AllChildrenStopped = TRUE;
for (Index = 0; Index < NumberOfChildren; Index++) {
BlockIo = NULL;
BlockIo2 = NULL;
Status = gBS->OpenProtocol (
ChildHandleBuffer[Index],
&gEfiBlockIoProtocolGuid,
(VOID **) &BlockIo,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
Status = gBS->OpenProtocol (
ChildHandleBuffer[Index],
&gEfiBlockIo2ProtocolGuid,
(VOID **) &BlockIo2,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
AllChildrenStopped = FALSE;
continue;
}
}
if (BlockIo != NULL) {
Device = SD_DEVICE_DATA_FROM_BLKIO (BlockIo);
} else {
ASSERT (BlockIo2 != NULL);
Device = SD_DEVICE_DATA_FROM_BLKIO2 (BlockIo2);
}
//
// Free all on-going async tasks.
//
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
for (Link = GetFirstNode (&Device->Queue);
!IsNull (&Device->Queue, Link);
Link = NextLink) {
NextLink = GetNextNode (&Device->Queue, Link);
RemoveEntryList (Link);
Request = SD_REQUEST_FROM_LINK (Link);
gBS->CloseEvent (Request->Event);
Request->Token->TransactionStatus = EFI_ABORTED;
if (Request->IsEnd) {
gBS->SignalEvent (Request->Token->Event);
}
FreePool (Request);
}
gBS->RestoreTPL (OldTpl);
//
// Close the child handle
//
Status = gBS->CloseProtocol (
Controller,
&gEfiSdMmcPassThruProtocolGuid,
This->DriverBindingHandle,
ChildHandleBuffer[Index]
);
Status = gBS->UninstallMultipleProtocolInterfaces (
ChildHandleBuffer[Index],
&gEfiDevicePathProtocolGuid,
Device->DevicePath,
&gEfiBlockIoProtocolGuid,
&Device->BlockIo,
&gEfiBlockIo2ProtocolGuid,
&Device->BlockIo2,
NULL
);
if (EFI_ERROR (Status)) {
AllChildrenStopped = FALSE;
gBS->OpenProtocol (
Controller,
&gEfiSdMmcPassThruProtocolGuid,
(VOID **)&PassThru,
This->DriverBindingHandle,
ChildHandleBuffer[Index],
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
} else {
FreePool (Device->DevicePath);
FreeUnicodeStringTable (Device->ControllerNameTable);
FreePool (Device);
}
}
if (!AllChildrenStopped) {
return EFI_DEVICE_ERROR;
}
return EFI_SUCCESS;
}
/**
The user Entry Point for module SdDxe. The user code starts with this function.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point is executed successfully.
@retval other Some errors occur when executing this entry point.
**/
EFI_STATUS
EFIAPI
InitializeSdDxe (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// Install driver model protocol(s).
//
Status = EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
SystemTable,
&gSdDxeDriverBinding,
ImageHandle,
&gSdDxeComponentName,
&gSdDxeComponentName2
);
ASSERT_EFI_ERROR (Status);
return Status;
}

View File

@ -0,0 +1,469 @@
/** @file
Header file for SdDxe Driver.
This file defines common data structures, macro definitions and some module
internal function header files.
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_DXE_H_
#define _SD_DXE_H_
#include <Uefi.h>
#include <IndustryStandard/Sd.h>
#include <Protocol/SdMmcPassThru.h>
#include <Protocol/BlockIo.h>
#include <Protocol/BlockIo2.h>
#include <Protocol/DevicePath.h>
#include <Library/DebugLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/BaseLib.h>
#include <Library/UefiLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DevicePathLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include "SdBlockIo.h"
//
// Global Variables
//
extern EFI_DRIVER_BINDING_PROTOCOL gSdDxeDriverBinding;
extern EFI_COMPONENT_NAME_PROTOCOL gSdDxeComponentName;
extern EFI_COMPONENT_NAME2_PROTOCOL gSdDxeComponentName2;
#define SD_DEVICE_SIGNATURE SIGNATURE_32 ('S', 'D', 't', 'f')
#define SD_DEVICE_DATA_FROM_BLKIO(a) \
CR(a, SD_DEVICE, BlockIo, SD_DEVICE_SIGNATURE)
#define SD_DEVICE_DATA_FROM_BLKIO2(a) \
CR(a, SD_DEVICE, BlockIo2, SD_DEVICE_SIGNATURE)
//
// Take 2.5 seconds as generic time out value, 1 microsecond as unit.
//
#define SD_GENERIC_TIMEOUT 2500 * 1000
#define SD_REQUEST_SIGNATURE SIGNATURE_32 ('S', 'D', 'R', 'E')
#define SD_MODEL_NAME_MAX_LEN 32
typedef struct _SD_DEVICE SD_DEVICE;
typedef struct _SD_DRIVER_PRIVATE_DATA SD_DRIVER_PRIVATE_DATA;
//
// Asynchronous I/O request.
//
typedef struct {
UINT32 Signature;
LIST_ENTRY Link;
EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
BOOLEAN IsEnd;
EFI_BLOCK_IO2_TOKEN *Token;
EFI_EVENT Event;
} SD_REQUEST;
#define SD_REQUEST_FROM_LINK(a) \
CR(a, SD_REQUEST, Link, SD_REQUEST_SIGNATURE)
struct _SD_DEVICE {
UINT32 Signature;
EFI_HANDLE Handle;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
UINT8 Slot;
BOOLEAN SectorAddressing;
EFI_BLOCK_IO_PROTOCOL BlockIo;
EFI_BLOCK_IO2_PROTOCOL BlockIo2;
EFI_BLOCK_IO_MEDIA BlockMedia;
LIST_ENTRY Queue;
SD_CSD Csd;
SD_CID Cid;
EFI_UNICODE_STRING_TABLE *ControllerNameTable;
//
// The model name consists of three fields in CID register
// 1) OEM/Application ID (2 bytes)
// 2) Product Name (5 bytes)
// 3) Product Serial Number (4 bytes)
// The delimiters of these fields are whitespace.
//
CHAR16 ModelName[SD_MODEL_NAME_MAX_LEN];
SD_DRIVER_PRIVATE_DATA *Private;
} ;
//
// SD DXE driver private data structure
//
struct _SD_DRIVER_PRIVATE_DATA {
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
EFI_HANDLE Controller;
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
EFI_HANDLE DriverBindingHandle;
} ;
/**
Tests to see if this driver supports a given controller. If a child device is provided,
it further tests to see if this driver supports creating a handle for the specified child device.
This function checks to see if the driver specified by This supports the device specified by
ControllerHandle. Drivers will typically use the device path attached to
ControllerHandle and/or the services from the bus I/O abstraction attached to
ControllerHandle to determine if the driver supports ControllerHandle. This function
may be called many times during platform initialization. In order to reduce boot times, the tests
performed by this function must be very small, and take as little time as possible to execute. This
function must not change the state of any hardware devices, and this function must be aware that the
device specified by ControllerHandle may already be managed by the same driver or a
different driver. This function must match its calls to AllocatePages() with FreePages(),
AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
Since ControllerHandle may have been previously started by the same driver, if a protocol is
already in the opened state, then it must not be closed with CloseProtocol(). This is required
to guarantee the state of ControllerHandle is not modified by this function.
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param[in] ControllerHandle The handle of the controller to test. This handle
must support a protocol interface that supplies
an I/O abstraction to the driver.
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
parameter is ignored by device drivers, and is optional for bus
drivers. For bus drivers, if this parameter is not NULL, then
the bus driver must determine if the bus controller specified
by ControllerHandle and the child controller specified
by RemainingDevicePath are both supported by this
bus driver.
@retval EFI_SUCCESS The device specified by ControllerHandle and
RemainingDevicePath is supported by the driver specified by This.
@retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
RemainingDevicePath is already being managed by the driver
specified by This.
@retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
RemainingDevicePath is already being managed by a different
driver or an application that requires exclusive access.
Currently not implemented.
@retval EFI_UNSUPPORTED The device specified by ControllerHandle and
RemainingDevicePath is not supported by the driver specified by This.
**/
EFI_STATUS
EFIAPI
SdDxeDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
);
/**
Starts a device controller or a bus controller.
The Start() function is designed to be invoked from the EFI boot service ConnectController().
As a result, much of the error checking on the parameters to Start() has been moved into this
common boot service. It is legal to call Start() from other locations,
but the following calling restrictions must be followed or the system behavior will not be deterministic.
1. ControllerHandle must be a valid EFI_HANDLE.
2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
EFI_DEVICE_PATH_PROTOCOL.
3. Prior to calling Start(), the Supported() function for the driver specified by This must
have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param[in] ControllerHandle The handle of the controller to start. This handle
must support a protocol interface that supplies
an I/O abstraction to the driver.
@param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
parameter is ignored by device drivers, and is optional for bus
drivers. For a bus driver, if this parameter is NULL, then handles
for all the children of Controller are created by this driver.
If this parameter is not NULL and the first Device Path Node is
not the End of Device Path Node, then only the handle for the
child device specified by the first Device Path Node of
RemainingDevicePath is created by this driver.
If the first Device Path Node of RemainingDevicePath is
the End of Device Path Node, no child handle is created by this
driver.
@retval EFI_SUCCESS The device was started.
@retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
@retval Others The driver failded to start the device.
**/
EFI_STATUS
EFIAPI
SdDxeDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
);
/**
Stops a device controller or a bus controller.
The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
As a result, much of the error checking on the parameters to Stop() has been moved
into this common boot service. It is legal to call Stop() from other locations,
but the following calling restrictions must be followed or the system behavior will not be deterministic.
1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
same driver's Start() function.
2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
EFI_HANDLE. In addition, all of these handles must have been created in this driver's
Start() function, and the Start() function must have called OpenProtocol() on
ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
@param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param[in] ControllerHandle A handle to the device being stopped. The handle must
support a bus specific I/O protocol for the driver
to use to stop the device.
@param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
@param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
if NumberOfChildren is 0.
@retval EFI_SUCCESS The device was stopped.
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
**/
EFI_STATUS
EFIAPI
SdDxeDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
);
/**
Retrieves a Unicode string that is the user readable name of the driver.
This function retrieves the user readable name of a driver in the form of a
Unicode string. If the driver specified by This has a user readable name in
the language specified by Language, then a pointer to the driver name is
returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
by This does not support the language specified by Language,
then EFI_UNSUPPORTED is returned.
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param Language[in] A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified
in RFC 4646 or ISO 639-2 language code format.
@param DriverName[out] A pointer to the Unicode string to return.
This Unicode string is the name of the
driver specified by This in the language
specified by Language.
@retval EFI_SUCCESS The Unicode string for the Driver specified by
This and the language specified by Language was
returned in DriverName.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER DriverName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
SdDxeComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
);
/**
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by a driver.
This function retrieves the user readable name of the controller specified by
ControllerHandle and ChildHandle in the form of a Unicode string. If the
driver specified by This has a user readable name in the language specified by
Language, then a pointer to the controller name is returned in ControllerName,
and EFI_SUCCESS is returned. If the driver specified by This is not currently
managing the controller specified by ControllerHandle and ChildHandle,
then EFI_UNSUPPORTED is returned. If the driver specified by This does not
support the language specified by Language, then EFI_UNSUPPORTED is returned.
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param ControllerHandle[in] The handle of a controller that the driver
specified by This is managing. This handle
specifies the controller whose name is to be
returned.
@param ChildHandle[in] The handle of the child controller to retrieve
the name of. This is an optional parameter that
may be NULL. It will be NULL for device
drivers. It will also be NULL for a bus drivers
that wish to retrieve the name of the bus
controller. It will not be NULL for a bus
driver that wishes to retrieve the name of a
child controller.
@param Language[in] A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified in
RFC 4646 or ISO 639-2 language code format.
@param ControllerName[out] A pointer to the Unicode string to return.
This Unicode string is the name of the
controller specified by ControllerHandle and
ChildHandle in the language specified by
Language from the point of view of the driver
specified by This.
@retval EFI_SUCCESS The Unicode string for the user readable name in
the language specified by Language for the
driver specified by This was returned in
DriverName.
@retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
EFI_HANDLE.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This is not currently
managing the controller specified by
ControllerHandle and ChildHandle.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
SdDxeComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
);
/**
Send command SET_RELATIVE_ADDRESS to the device to set the device address.
@param[in] Device A pointer to the SD_DEVICE instance.
@param[out] Rca The relative device address to assign.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
SdSetRca (
IN SD_DEVICE *Device,
OUT UINT16 *Rca
);
/**
Send command SELECT to the device to select/deselect the device.
@param[in] Device A pointer to the SD_DEVICE instance.
@param[in] Rca The relative device address to use.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
SdSelect (
IN SD_DEVICE *Device,
IN UINT16 Rca
);
/**
Send command SEND_STATUS to the device to get device status.
@param[in] Device A pointer to the SD_DEVICE instance.
@param[in] Rca The relative device address to use.
@param[out] DevStatus The buffer to store the device status.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
SdSendStatus (
IN SD_DEVICE *Device,
IN UINT16 Rca,
OUT UINT32 *DevStatus
);
/**
Send command SEND_CSD to the device to get the CSD register data.
@param[in] Device A pointer to the SD_DEVICE instance.
@param[in] Rca The relative device address to use.
@param[out] Csd The buffer to store the SD_CSD register data.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
SdGetCsd (
IN SD_DEVICE *Device,
IN UINT16 Rca,
OUT SD_CSD *Csd
);
/**
Send command SEND_CID to the device to get the CID register data.
@param[in] Device A pointer to the SD_DEVICE instance.
@param[in] Rca The relative device address to use.
@param[out] Cid The buffer to store the SD_CID register data.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
SdGetCid (
IN SD_DEVICE *Device,
IN UINT16 Rca,
OUT SD_CID *Cid
);
#endif

View File

@ -0,0 +1,65 @@
## @file
# SdDxe driver is used to manage the SD memory card device.
#
# It produces BlockIo and BlockIo2 protocols to allow upper layer
# access the SD memory card device.
#
# Copyright (c) 2015, 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 = SdDxe
MODULE_UNI_FILE = SdDxe.uni
FILE_GUID = 430AC2F7-EEC6-4093-94F7-9F825A7C1C40
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = InitializeSdDxe
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
# DRIVER_BINDING = gSdDxeDriverBinding
# COMPONENT_NAME = gSdDxeComponentName
# COMPONENT_NAME2 = gSdDxeComponentName2
#
[Sources.common]
ComponentName.c
SdDxe.c
SdDxe.h
SdBlockIo.c
SdBlockIo.h
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
DevicePathLib
UefiBootServicesTableLib
MemoryAllocationLib
BaseMemoryLib
UefiLib
BaseLib
UefiDriverEntryPoint
DebugLib
[Protocols]
gEfiSdMmcPassThruProtocolGuid ## TO_START
gEfiBlockIoProtocolGuid ## BY_START
gEfiBlockIo2ProtocolGuid ## BY_START
## TO_START
## BY_START
gEfiDevicePathProtocolGuid

View File

@ -0,0 +1,20 @@
// /** @file
// SD memory card device driver to manage the SD memory card device and provide interface for upper layer
// access.
//
// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
//
// 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 "SD device driver to manage the SD memory card device and provide interface for upper layer access"
#string STR_MODULE_DESCRIPTION #language en-US "This driver follows the UEFI driver model and layers on the SdMmcPassThru protocol. It installs BlockIo and BlockIo2 protocols on the SD device."

View File

@ -0,0 +1,20 @@
// /** @file
// SD memory card device driver to manage the SD memory card device and provide interface for upper layer
// access.
//
// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
//
// 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 "SD device driver to manage the SD memory card device and provide interface for upper layer access"
#string STR_MODULE_DESCRIPTION #language en-US "This driver follows the UEFI driver model and layers on the SdMmcPassThru protocol. It installs BlockIo and BlockIo2 protocols on the SD device."

View File

@ -0,0 +1,64 @@
/** @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 _EDKII_PEI_SD_MMC_HOST_CONTROLLER_PPI_H_
#define _EDKII_PEI_SD_MMC_HOST_CONTROLLER_PPI_H_
///
/// Global ID for the EDKII_SD_MMC_HOST_CONTROLLER_PPI.
///
#define EDKII_SD_MMC_HOST_CONTROLLER_PPI_GUID \
{ \
0xb30dfeed, 0x947f, 0x4396, { 0xb1, 0x5a, 0xdf, 0xbd, 0xb9, 0x16, 0xdc, 0x24 } \
}
///
/// Forward declaration for the SD_MMC_HOST_CONTROLLER_PPI.
///
typedef struct _EDKII_SD_MMC_HOST_CONTROLLER_PPI EDKII_SD_MMC_HOST_CONTROLLER_PPI;
/**
Get the MMIO base address of SD/MMC host controller.
@param[in] This The protocol instance pointer.
@param[in] ControllerId The ID of the SD/MMC host controller.
@param[in,out] MmioBar The pointer to store the array of available
SD/MMC host controller slot MMIO base addresses.
The entry number of the array is specified by BarNum.
@param[out] BarNum The pointer to store the supported bar number.
@retval EFI_SUCCESS The operation succeeds.
@retval EFI_INVALID_PARAMETER The parameters are invalid.
**/
typedef
EFI_STATUS
(EFIAPI *EDKII_SD_MMC_HC_GET_MMIO_BAR)(
IN EDKII_SD_MMC_HOST_CONTROLLER_PPI *This,
IN UINT8 ControllerId,
IN OUT UINTN **MmioBar,
OUT UINT8 *BarNum
);
///
/// This PPI contains a set of services to interact with the SD_MMC host controller.
///
struct _EDKII_SD_MMC_HOST_CONTROLLER_PPI {
EDKII_SD_MMC_HC_GET_MMIO_BAR GetSdMmcHcMmioBar;
};
extern EFI_GUID gEdkiiPeiSdMmcHostControllerPpiGuid;
#endif

View File

@ -388,6 +388,9 @@
## Include/Ppi/IpmiPpi.h
gPeiIpmiPpiGuid = { 0xa9731431, 0xd968, 0x4277, { 0xb7, 0x52, 0xa3, 0xa9, 0xa6, 0xae, 0x18, 0x98 }}
## Include/Ppi/SdMmcHostController.h
gEdkiiPeiSdMmcHostControllerPpiGuid = { 0xb30dfeed, 0x947f, 0x4396, { 0xb1, 0x5a, 0xdf, 0xbd, 0xb9, 0x16, 0xdc, 0x24 }}
[Protocols]
## Load File protocol provides capability to load and unload EFI image into memory and execute it.
# Include/Protocol/LoadPe32Image.h
@ -1495,6 +1498,12 @@
# @Prompt Set NX for stack.
gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack|FALSE|BOOLEAN|0x0001006f
## This PCD specifies the PCI-based SD/MMC host controller mmio base address.
# Define the mmio base address of the pci-based SD/MMC host controller. If there are multiple SD/MMC
# host controllers, their mmio base addresses are calculated one by one from this base address.
# @Prompt Mmio base address of pci-based SD/MMC host controller.
gEfiMdeModulePkgTokenSpaceGuid.PcdSdMmcPciHostControllerMmioBase|0xd0000000|UINT32|0x30001043
[PcdsPatchableInModule]
## Specify memory size with page number for PEI code when
# Loading Module at Fixed Address feature is enabled.

View File

@ -215,6 +215,12 @@
MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf
MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf
MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf
MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.inf
MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.inf
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.inf
MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf
MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf
MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.inf
MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf
MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.inf