EmbeddedPkg: Move Universal/MmcDxe from ArmPkg to EmbeddedPkg
The MmcDxe is not ARM architecture specific. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11725 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
162
EmbeddedPkg/Universal/MmcDxe/ComponentName.c
Normal file
162
EmbeddedPkg/Universal/MmcDxe/ComponentName.c
Normal file
@@ -0,0 +1,162 @@
|
||||
/** @file
|
||||
Component Name Protocol implementation for the MMC DXE driver
|
||||
|
||||
Copyright (c) 2011, ARM Limited. All rights reserved.
|
||||
|
||||
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 "Mmc.h"
|
||||
|
||||
//
|
||||
// EFI Component Name Protocol
|
||||
//
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gMmcComponentName = {
|
||||
MmcGetDriverName,
|
||||
MmcGetControllerName,
|
||||
"eng"
|
||||
};
|
||||
|
||||
//
|
||||
// EFI Component Name 2 Protocol
|
||||
//
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gMmcComponentName2 = {
|
||||
(EFI_COMPONENT_NAME2_GET_DRIVER_NAME) MmcGetDriverName,
|
||||
(EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) MmcGetControllerName,
|
||||
"en"
|
||||
};
|
||||
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
|
||||
mMmcDriverNameTable[] = {
|
||||
{"eng;en", L"MMC/SD Card Interface Driver"},
|
||||
{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 A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
|
||||
EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
@param Language 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 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
|
||||
MmcGetDriverName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **DriverName
|
||||
)
|
||||
{
|
||||
return LookupUnicodeString2 (
|
||||
Language,
|
||||
This->SupportedLanguages,
|
||||
mMmcDriverNameTable,
|
||||
DriverName,
|
||||
(BOOLEAN)(This == &gMmcComponentName)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
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 A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
|
||||
EFI_COMPONENT_NAME_PROTOCOL instance.
|
||||
@param ControllerHandle 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 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 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 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
|
||||
MmcGetControllerName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_HANDLE ChildHandle OPTIONAL,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **ControllerName
|
||||
)
|
||||
{
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
215
EmbeddedPkg/Universal/MmcDxe/Diagnostics.c
Normal file
215
EmbeddedPkg/Universal/MmcDxe/Diagnostics.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/** @file
|
||||
Diagnostics Protocol implementation for the MMC DXE driver
|
||||
|
||||
Copyright (c) 2011, ARM Limited. All rights reserved.
|
||||
|
||||
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 <Uefi.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
|
||||
#include "Mmc.h"
|
||||
|
||||
#define DIAGNOSTIC_LOGBUFFER_MAXCHAR 1024
|
||||
|
||||
CHAR16* mLogBuffer = NULL;
|
||||
UINTN mLogRemainChar = 0;
|
||||
|
||||
CHAR16* DiagnosticInitLog(UINTN MaxBufferChar) {
|
||||
mLogRemainChar = MaxBufferChar;
|
||||
mLogBuffer = AllocatePool ((UINTN)MaxBufferChar * sizeof(CHAR16));
|
||||
return mLogBuffer;
|
||||
}
|
||||
|
||||
UINTN DiagnosticLog(CONST CHAR16* Str) {
|
||||
UINTN len = StrLen (Str);
|
||||
if (len <= mLogRemainChar) {
|
||||
mLogRemainChar -= len;
|
||||
StrCpy (mLogBuffer, Str);
|
||||
mLogBuffer += len;
|
||||
return len;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
VOID GenerateRandomBuffer(VOID* Buffer, UINTN BufferSize) {
|
||||
UINT64 i;
|
||||
UINT64* Buffer64 = (UINT64*)Buffer;
|
||||
|
||||
for (i = 0; i < (BufferSize >> 3); i++) {
|
||||
*Buffer64 = i | (~i << 32);
|
||||
Buffer64++;
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN CompareBuffer(VOID *BufferA, VOID *BufferB, UINTN BufferSize) {
|
||||
UINTN i;
|
||||
UINT64* BufferA64 = (UINT64*)BufferA;
|
||||
UINT64* BufferB64 = (UINT64*)BufferB;
|
||||
|
||||
for (i = 0; i < (BufferSize >> 3); i++) {
|
||||
if (*BufferA64 != *BufferB64) {
|
||||
DEBUG((EFI_D_ERROR, "CompareBuffer: Error at %i", i));
|
||||
DEBUG((EFI_D_ERROR, "(0x%lX) != (0x%lX)\n", *BufferA64, *BufferB64));
|
||||
return FALSE;
|
||||
}
|
||||
BufferA64++;
|
||||
BufferB64++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
EFI_STATUS MmcReadWriteDataTest(MMC_HOST_INSTANCE *MmcHostInstance, EFI_LBA Lba, UINTN BufferSize) {
|
||||
VOID *BackBuffer;
|
||||
VOID *WriteBuffer;
|
||||
VOID *ReadBuffer;
|
||||
EFI_STATUS Status;
|
||||
|
||||
// Check if a Media is Present
|
||||
if (!MmcHostInstance->BlockIo.Media->MediaPresent) {
|
||||
DiagnosticLog(L"ERROR: No Media Present\n");
|
||||
return EFI_NO_MEDIA;
|
||||
}
|
||||
|
||||
if (MmcHostInstance->State != MmcTransferState) {
|
||||
DiagnosticLog(L"ERROR: Not ready for Transfer state\n");
|
||||
return EFI_NOT_READY;
|
||||
}
|
||||
|
||||
BackBuffer = AllocatePool(BufferSize);
|
||||
WriteBuffer = AllocatePool(BufferSize);
|
||||
ReadBuffer = AllocatePool(BufferSize);
|
||||
|
||||
// Read (and save) buffer at a specific location
|
||||
Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,BackBuffer);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
DiagnosticLog(L"ERROR: Fail to Read Block (1)\n");
|
||||
return Status;
|
||||
}
|
||||
|
||||
// Write buffer at the same location
|
||||
GenerateRandomBuffer(WriteBuffer,BufferSize);
|
||||
Status = MmcWriteBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,WriteBuffer);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
DiagnosticLog(L"ERROR: Fail to Write Block (1)\n");
|
||||
return Status;
|
||||
}
|
||||
|
||||
// Read the buffer at the same location
|
||||
Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,ReadBuffer);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
DiagnosticLog(L"ERROR: Fail to Read Block (2)\n");
|
||||
return Status;
|
||||
}
|
||||
|
||||
// Check that is conform
|
||||
if (!CompareBuffer(ReadBuffer,WriteBuffer,BufferSize)) {
|
||||
DiagnosticLog(L"ERROR: Fail to Read/Write Block (1)\n");
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Restore content at the original location
|
||||
Status = MmcWriteBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,BackBuffer);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
DiagnosticLog(L"ERROR: Fail to Write Block (2)\n");
|
||||
return Status;
|
||||
}
|
||||
|
||||
// Read the restored content
|
||||
Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,ReadBuffer);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
DiagnosticLog(L"ERROR: Fail to Read Block (3)\n");
|
||||
return Status;
|
||||
}
|
||||
|
||||
// Check the content is correct
|
||||
if (!CompareBuffer(ReadBuffer,BackBuffer,BufferSize)) {
|
||||
DiagnosticLog(L"ERROR: Fail to Read/Write Block (2)\n");
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MmcDriverDiagnosticsRunDiagnostics (
|
||||
IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_HANDLE ChildHandle OPTIONAL,
|
||||
IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType,
|
||||
IN CHAR8 *Language,
|
||||
OUT EFI_GUID **ErrorType,
|
||||
OUT UINTN *BufferSize,
|
||||
OUT CHAR16 **Buffer
|
||||
)
|
||||
{
|
||||
LIST_ENTRY *CurrentLink;
|
||||
MMC_HOST_INSTANCE *MmcHostInstance;
|
||||
EFI_STATUS Status;
|
||||
|
||||
if (Language == NULL ||
|
||||
ErrorType == NULL ||
|
||||
Buffer == NULL ||
|
||||
ControllerHandle == NULL ||
|
||||
BufferSize == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
*ErrorType = NULL;
|
||||
*BufferSize = DIAGNOSTIC_LOGBUFFER_MAXCHAR;
|
||||
*Buffer = DiagnosticInitLog(DIAGNOSTIC_LOGBUFFER_MAXCHAR);
|
||||
|
||||
DiagnosticLog(L"MMC Driver Diagnostics\n");
|
||||
|
||||
// For each MMC instance
|
||||
CurrentLink = mMmcHostPool.ForwardLink;
|
||||
while (CurrentLink != NULL && CurrentLink != &mMmcHostPool && (Status == EFI_SUCCESS)) {
|
||||
MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);
|
||||
ASSERT(MmcHostInstance != NULL);
|
||||
|
||||
// LBA=1 Size=BlockSize
|
||||
DiagnosticLog(L"MMC Driver Diagnostics - Test: First Block\n");
|
||||
Status = MmcReadWriteDataTest(MmcHostInstance, 1, MmcHostInstance->BlockIo.Media->BlockSize);
|
||||
|
||||
// LBA=2 Size=BlockSize
|
||||
DiagnosticLog(L"MMC Driver Diagnostics - Test: Second Block\n");
|
||||
Status = MmcReadWriteDataTest(MmcHostInstance, 2, MmcHostInstance->BlockIo.Media->BlockSize);
|
||||
|
||||
// LBA=10 Size=BlockSize
|
||||
DiagnosticLog(L"MMC Driver Diagnostics - Test: Any Block\n");
|
||||
Status = MmcReadWriteDataTest(MmcHostInstance, MmcHostInstance->BlockIo.Media->LastBlock >> 1, MmcHostInstance->BlockIo.Media->BlockSize);
|
||||
|
||||
// LBA=LastBlock Size=BlockSize
|
||||
DiagnosticLog(L"MMC Driver Diagnostics - Test: Last Block\n");
|
||||
Status = MmcReadWriteDataTest(MmcHostInstance, MmcHostInstance->BlockIo.Media->LastBlock, MmcHostInstance->BlockIo.Media->BlockSize);
|
||||
|
||||
// LBA=1 Size=2*BlockSize
|
||||
DiagnosticLog(L"MMC Driver Diagnostics - Test: First Block / 2 BlockSSize\n");
|
||||
Status = MmcReadWriteDataTest(MmcHostInstance, 1, 2*MmcHostInstance->BlockIo.Media->BlockSize);
|
||||
|
||||
CurrentLink = CurrentLink->ForwardLink;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// EFI Driver Diagnostics 2 Protocol
|
||||
//
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gMmcDriverDiagnostics2 = {
|
||||
(EFI_DRIVER_DIAGNOSTICS2_RUN_DIAGNOSTICS) MmcDriverDiagnosticsRunDiagnostics,
|
||||
"en"
|
||||
};
|
387
EmbeddedPkg/Universal/MmcDxe/Mmc.c
Normal file
387
EmbeddedPkg/Universal/MmcDxe/Mmc.c
Normal file
@@ -0,0 +1,387 @@
|
||||
/** @file
|
||||
Main file of the MMC Dxe driver. The driver entrypoint is defined into this file.
|
||||
|
||||
Copyright (c) 2011, ARM Limited. All rights reserved.
|
||||
|
||||
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 <Protocol/DevicePath.h>
|
||||
#include <Protocol/MmcHost.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
|
||||
#include "Mmc.h"
|
||||
|
||||
EFI_BLOCK_IO_MEDIA mMmcMediaTemplate = {
|
||||
SIGNATURE_32('m','m','c','o'), // MediaId
|
||||
TRUE, // RemovableMedia
|
||||
FALSE, // MediaPresent
|
||||
FALSE, // LogicalPartition
|
||||
FALSE, // ReadOnly
|
||||
FALSE, // WriteCaching
|
||||
512, // BlockSize
|
||||
4, // IoAlign
|
||||
0, // Pad
|
||||
0 // LastBlock
|
||||
};
|
||||
|
||||
//
|
||||
// This device structure is serviced as a header.
|
||||
// Its next field points to the first root bridge device node.
|
||||
//
|
||||
LIST_ENTRY mMmcHostPool;
|
||||
|
||||
/**
|
||||
Initialize the MMC Host Pool to support multiple MMC devices
|
||||
**/
|
||||
VOID
|
||||
InitializeMmcHostPool (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
InitializeListHead (&mMmcHostPool);
|
||||
}
|
||||
|
||||
/**
|
||||
Insert a new Mmc Host controller to the pool
|
||||
**/
|
||||
VOID
|
||||
InsertMmcHost (
|
||||
IN MMC_HOST_INSTANCE *MmcHostInstance
|
||||
)
|
||||
{
|
||||
InsertTailList (&mMmcHostPool, &(MmcHostInstance->Link));
|
||||
}
|
||||
|
||||
/*
|
||||
Remove a new Mmc Host controller to the pool
|
||||
*/
|
||||
VOID
|
||||
RemoveMmcHost (
|
||||
IN MMC_HOST_INSTANCE *MmcHostInstance
|
||||
)
|
||||
{
|
||||
RemoveEntryList (&(MmcHostInstance->Link));
|
||||
}
|
||||
|
||||
MMC_HOST_INSTANCE* CreateMmcHostInstance(
|
||||
IN EFI_MMC_HOST_PROTOCOL* MmcHost
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
MMC_HOST_INSTANCE* MmcHostInstance;
|
||||
EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;
|
||||
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
||||
|
||||
MmcHostInstance = AllocateZeroPool (sizeof (MMC_HOST_INSTANCE));
|
||||
if (MmcHostInstance == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MmcHostInstance->Signature = MMC_HOST_INSTANCE_SIGNATURE;
|
||||
|
||||
MmcHostInstance->State = MmcHwInitializationState;
|
||||
|
||||
MmcHostInstance->BlockIo.Media = AllocateCopyPool (sizeof(EFI_BLOCK_IO_MEDIA), &mMmcMediaTemplate);
|
||||
if (MmcHostInstance->BlockIo.Media == NULL) {
|
||||
goto FREE_INSTANCE;
|
||||
}
|
||||
|
||||
MmcHostInstance->BlockIo.Revision = EFI_BLOCK_IO_INTERFACE_REVISION;
|
||||
MmcHostInstance->BlockIo.Reset = MmcReset;
|
||||
MmcHostInstance->BlockIo.ReadBlocks = MmcReadBlocks;
|
||||
MmcHostInstance->BlockIo.WriteBlocks = MmcWriteBlocks;
|
||||
MmcHostInstance->BlockIo.FlushBlocks = MmcFlushBlocks;
|
||||
|
||||
MmcHostInstance->MmcHost = MmcHost;
|
||||
|
||||
// Create DevicePath for the new MMC Host
|
||||
Status = MmcHost->BuildDevicePath(&NewDevicePathNode);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto FREE_MEDIA;
|
||||
}
|
||||
|
||||
DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocatePool (END_DEVICE_PATH_LENGTH);
|
||||
if (DevicePath == NULL) {
|
||||
goto FREE_MEDIA;
|
||||
}
|
||||
|
||||
SetDevicePathEndNode (DevicePath);
|
||||
MmcHostInstance->DevicePath = AppendDevicePathNode (DevicePath, NewDevicePathNode);
|
||||
|
||||
// Publish BlockIO protocol interface
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&MmcHostInstance->MmcHandle,
|
||||
&gEfiBlockIoProtocolGuid,&(MmcHostInstance->BlockIo),
|
||||
&gEfiDevicePathProtocolGuid,MmcHostInstance->DevicePath,
|
||||
NULL
|
||||
);
|
||||
if (EFI_ERROR(Status)) {
|
||||
goto FREE_DEVICE_PATH;
|
||||
}
|
||||
|
||||
return MmcHostInstance;
|
||||
|
||||
FREE_DEVICE_PATH:
|
||||
FreePool(DevicePath);
|
||||
|
||||
FREE_MEDIA:
|
||||
FreePool(MmcHostInstance->BlockIo.Media);
|
||||
|
||||
FREE_INSTANCE:
|
||||
FreePool(MmcHostInstance);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EFI_STATUS DestroyMmcHostInstance(
|
||||
IN MMC_HOST_INSTANCE* MmcHostInstance
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
// Uninstall Protocol Interfaces
|
||||
Status = gBS->UninstallMultipleProtocolInterfaces(
|
||||
MmcHostInstance->MmcHandle,
|
||||
&gEfiBlockIoProtocolGuid,&(MmcHostInstance->BlockIo),
|
||||
&gEfiDevicePathProtocolGuid,MmcHostInstance->DevicePath,
|
||||
NULL
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
// Free Memory allocated for the instance
|
||||
if (MmcHostInstance->BlockIo.Media) {
|
||||
FreePool(MmcHostInstance->BlockIo.Media);
|
||||
}
|
||||
FreePool (MmcHostInstance);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
This function checks if the controller implement the Mmc Host and the Device Path Protocols
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MmcDriverBindingSupported (
|
||||
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_MMC_HOST_PROTOCOL *MmcHost;
|
||||
EFI_DEV_PATH_PTR Node;
|
||||
|
||||
//
|
||||
// Check RemainingDevicePath validation
|
||||
//
|
||||
if (RemainingDevicePath != NULL) {
|
||||
//
|
||||
// Check if RemainingDevicePath is the End of Device Path Node,
|
||||
// if yes, go on checking other conditions
|
||||
//
|
||||
if (!IsDevicePathEnd (RemainingDevicePath)) {
|
||||
//
|
||||
// If RemainingDevicePath isn't the End of Device Path Node,
|
||||
// check its validation
|
||||
//
|
||||
Node.DevPath = RemainingDevicePath;
|
||||
if (Node.DevPath->Type != HARDWARE_DEVICE_PATH ||
|
||||
Node.DevPath->SubType != HW_VENDOR_DP ||
|
||||
DevicePathNodeLength(Node.DevPath) != sizeof(VENDOR_DEVICE_PATH)) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Check if Mmc Host protocol is installed by platform
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
Controller,
|
||||
&gEfiMmcHostProtocolGuid,
|
||||
(VOID **) &MmcHost,
|
||||
This->DriverBindingHandle,
|
||||
Controller,
|
||||
EFI_OPEN_PROTOCOL_BY_DRIVER
|
||||
);
|
||||
if (Status == EFI_ALREADY_STARTED) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Close the Mmc Host used to perform the supported test
|
||||
//
|
||||
gBS->CloseProtocol (
|
||||
Controller,
|
||||
&gEfiMmcHostProtocolGuid,
|
||||
This->DriverBindingHandle,
|
||||
Controller
|
||||
);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MmcDriverBindingStart (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
MMC_HOST_INSTANCE *MmcHostInstance;
|
||||
EFI_MMC_HOST_PROTOCOL *MmcHost;
|
||||
|
||||
//
|
||||
// Check RemainingDevicePath validation
|
||||
//
|
||||
if (RemainingDevicePath != NULL) {
|
||||
//
|
||||
// Check if RemainingDevicePath is the End of Device Path Node,
|
||||
// if yes, return EFI_SUCCESS
|
||||
//
|
||||
if (IsDevicePathEnd (RemainingDevicePath)) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Get the Mmc Host protocol
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
Controller,
|
||||
&gEfiMmcHostProtocolGuid,
|
||||
(VOID **) &MmcHost,
|
||||
This->DriverBindingHandle,
|
||||
Controller,
|
||||
EFI_OPEN_PROTOCOL_BY_DRIVER
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
if (Status == EFI_ALREADY_STARTED) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
MmcHostInstance = CreateMmcHostInstance(MmcHost);
|
||||
if (MmcHostInstance != NULL) {
|
||||
// Add the handle to the pool
|
||||
InsertMmcHost (MmcHostInstance);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MmcDriverBindingStop (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN UINTN NumberOfChildren,
|
||||
IN EFI_HANDLE *ChildHandleBuffer
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
LIST_ENTRY *CurrentLink;
|
||||
MMC_HOST_INSTANCE *MmcHostInstance;
|
||||
|
||||
MMC_TRACE("MmcDriverBindingStop()");
|
||||
|
||||
// For each MMC instance
|
||||
CurrentLink = mMmcHostPool.ForwardLink;
|
||||
while (CurrentLink != NULL && CurrentLink != &mMmcHostPool && (Status == EFI_SUCCESS)) {
|
||||
MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);
|
||||
ASSERT(MmcHostInstance != NULL);
|
||||
|
||||
// Close gEfiMmcHostProtocolGuid
|
||||
Status = gBS->CloseProtocol (
|
||||
Controller,
|
||||
&gEfiMmcHostProtocolGuid,(VOID **) &MmcHostInstance->MmcHost,
|
||||
This->DriverBindingHandle
|
||||
);
|
||||
|
||||
// Remove MMC Host Instance from the pool
|
||||
RemoveMmcHost (MmcHostInstance);
|
||||
|
||||
// Destroy MmcHostInstance
|
||||
DestroyMmcHostInstance (MmcHostInstance);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
EFI_DRIVER_BINDING_PROTOCOL gMmcDriverBinding = {
|
||||
MmcDriverBindingSupported,
|
||||
MmcDriverBindingStart,
|
||||
MmcDriverBindingStop,
|
||||
0xa,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MmcDxeInitialize (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// Initializes MMC Host pool
|
||||
//
|
||||
InitializeMmcHostPool ();
|
||||
|
||||
//
|
||||
// Install driver model protocol(s).
|
||||
//
|
||||
Status = EfiLibInstallDriverBindingComponentName2 (
|
||||
ImageHandle,
|
||||
SystemTable,
|
||||
&gMmcDriverBinding,
|
||||
ImageHandle,
|
||||
&gMmcComponentName,
|
||||
&gMmcComponentName2
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
// Install driver diagnostics
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&ImageHandle,
|
||||
&gEfiDriverDiagnostics2ProtocolGuid,&gMmcDriverDiagnostics2,
|
||||
NULL
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
return Status;
|
||||
}
|
286
EmbeddedPkg/Universal/MmcDxe/Mmc.h
Normal file
286
EmbeddedPkg/Universal/MmcDxe/Mmc.h
Normal file
@@ -0,0 +1,286 @@
|
||||
/** @file
|
||||
Main Header file for the MMC DXE driver
|
||||
|
||||
Copyright (c) 2011, ARM Limited. All rights reserved.
|
||||
|
||||
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 __MMC_H
|
||||
#define __MMC_H
|
||||
|
||||
#include <Uefi.h>
|
||||
|
||||
#include <Protocol/DiskIo.h>
|
||||
#include <Protocol/BlockIo.h>
|
||||
#include <Protocol/DevicePath.h>
|
||||
#include <Protocol/MmcHost.h>
|
||||
|
||||
#include <Library/UefiLib.h>
|
||||
|
||||
#define MMC_TRACE(txt) DEBUG((EFI_D_BLKIO, "MMC: " txt "\n"))
|
||||
|
||||
#define MMC_IOBLOCKS_READ 0
|
||||
#define MMC_IOBLOCKS_WRITE 1
|
||||
|
||||
#define MMC_OCR_POWERUP 0x80000000
|
||||
|
||||
#define MMC_CSD_GET_CCC(Response) (Response[1] >> 20)
|
||||
#define MMC_CSD_GET_TRANSPEED(Response) (Response[0] & 0xFF)
|
||||
#define MMC_CSD_GET_READBLLEN(Response) ((Response[1] >> 16) & 0xF)
|
||||
#define MMC_CSD_GET_WRITEBLLEN(Response) ((Response[3] >> 22) & 0xF)
|
||||
#define MMC_CSD_GET_FILEFORMAT(Response) ((Response[3] >> 10) & 0x3)
|
||||
#define MMC_CSD_GET_FILEFORMATGRP(Response) ((Response[3] >> 15) & 0x1)
|
||||
#define MMC_CSD_GET_DEVICESIZE(csd) (((Response[2] >> 30) & 0x3) | ((Response[1] & 0x3FF) << 2))
|
||||
#define MMC_CSD_GET_DEVICESIZEMULT(csd) ((Response[2] >> 15) & 0x7)
|
||||
|
||||
#define MMC_R0_CURRENTSTATE(Response) ((Response[0] >> 9) & 0xF)
|
||||
|
||||
#define MMC_R0_STATE_IDLE 0
|
||||
#define MMC_R0_STATE_READY 1
|
||||
#define MMC_R0_STATE_IDENT 2
|
||||
#define MMC_R0_STATE_STDBY 3
|
||||
#define MMC_R0_STATE_TRAN 4
|
||||
#define MMC_R0_STATE_DATA 5
|
||||
|
||||
typedef enum {
|
||||
UNKNOWN_CARD,
|
||||
MMC_CARD, //MMC card
|
||||
MMC_CARD_HIGH, //MMC Card with High capacity
|
||||
SD_CARD, //SD 1.1 card
|
||||
SD_CARD_2, //SD 2.0 or above standard card
|
||||
SD_CARD_2_HIGH //SD 2.0 or above high capacity card
|
||||
} CARD_TYPE;
|
||||
|
||||
typedef struct {
|
||||
UINT32 Reserved0: 7; // 0
|
||||
UINT32 V170_V195: 1; // 1.70V - 1.95V
|
||||
UINT32 V200_V260: 7; // 2.00V - 2.60V
|
||||
UINT32 V270_V360: 9; // 2.70V - 3.60V
|
||||
UINT32 RESERVED_1: 5; // Reserved
|
||||
UINT32 AccessMode: 2; // 00b (byte mode), 10b (sector mode)
|
||||
UINT32 Busy: 1; // This bit is set to LOW if the card has not finished the power up routine
|
||||
} OCR;
|
||||
|
||||
typedef struct {
|
||||
UINT32 NOT_USED; // 1 [0:0]
|
||||
UINT32 CRC; // CRC7 checksum [7:1]
|
||||
UINT32 MDT; // Manufacturing date [19:8]
|
||||
UINT32 RESERVED_1; // Reserved [23:20]
|
||||
UINT32 PSN; // Product serial number [55:24]
|
||||
UINT8 PRV; // Product revision [63:56]
|
||||
UINT8 PNM[5]; // Product name [64:103]
|
||||
UINT16 OID; // OEM/Application ID [119:104]
|
||||
UINT8 MID; // Manufacturer ID [127:120]
|
||||
} CID;
|
||||
|
||||
typedef struct {
|
||||
UINT8 NOT_USED: 1; // Not used, always 1 [0:0]
|
||||
UINT8 CRC: 7; // CRC [7:1]
|
||||
|
||||
UINT8 RESERVED_1: 2; // Reserved [9:8]
|
||||
UINT8 FILE_FORMAT: 2; // File format [11:10]
|
||||
UINT8 TMP_WRITE_PROTECT: 1; // Temporary write protection [12:12]
|
||||
UINT8 PERM_WRITE_PROTECT: 1; // Permanent write protection [13:13]
|
||||
UINT8 COPY: 1; // Copy flag (OTP) [14:14]
|
||||
UINT8 FILE_FORMAT_GRP: 1; // File format group [15:15]
|
||||
|
||||
UINT16 RESERVED_2: 5; // Reserved [20:16]
|
||||
UINT16 WRITE_BL_PARTIAL: 1; // Partial blocks for write allowed [21:21]
|
||||
UINT16 WRITE_BL_LEN: 4; // Max. write data block length [25:22]
|
||||
UINT16 R2W_FACTOR: 3; // Write speed factor [28:26]
|
||||
UINT16 RESERVED_3: 2; // Reserved [30:29]
|
||||
UINT16 WP_GRP_ENABLE: 1; // Write protect group enable [31:31]
|
||||
|
||||
UINT32 WP_GRP_SIZE: 7; // Write protect group size [38:32]
|
||||
UINT32 SECTOR_SIZE: 7; // Erase sector size [45:39]
|
||||
UINT32 ERASE_BLK_EN: 1; // Erase single block enable [46:46]
|
||||
UINT32 C_SIZE_MULT: 3; // Device size multiplier [49:47]
|
||||
UINT32 VDD_W_CURR_MAX: 3; // Max. write current @ VDD max [52:50]
|
||||
UINT32 VDD_W_CURR_MIN: 3; // Max. write current @ VDD min [55:53]
|
||||
UINT32 VDD_R_CURR_MAX: 3; // Max. read current @ VDD max [58:56]
|
||||
UINT32 VDD_R_CURR_MIN: 3; // Max. read current @ VDD min [61:59]
|
||||
UINT32 C_SIZELow2: 2; // Device size [63:62]
|
||||
|
||||
UINT32 C_SIZEHigh10: 10;// Device size [73:64]
|
||||
UINT32 RESERVED_4: 2; // Reserved [75:74]
|
||||
UINT32 DSR_IMP: 1; // DSR implemented [76:76]
|
||||
UINT32 READ_BLK_MISALIGN: 1; // Read block misalignment [77:77]
|
||||
UINT32 WRITE_BLK_MISALIGN: 1; // Write block misalignment [78:78]
|
||||
UINT32 READ_BL_PARTIAL: 1; // Partial blocks for read allowed [79:79]
|
||||
UINT32 READ_BL_LEN: 4; // Max. read data block length [83:80]
|
||||
UINT32 CCC: 12;// Card command classes [95:84]
|
||||
|
||||
UINT8 TRAN_SPEED ; // Max. bus clock frequency [103:96]
|
||||
UINT8 NSAC ; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104]
|
||||
UINT8 TAAC ; // Data read access-time 1 [119:112]
|
||||
|
||||
UINT8 RESERVED_5: 6; // Reserved [125:120]
|
||||
UINT8 CSD_STRUCTURE: 2; // CSD structure [127:126]
|
||||
} CSD;
|
||||
|
||||
typedef struct {
|
||||
UINT16 RCA;
|
||||
CARD_TYPE CardType;
|
||||
OCR OCRData;
|
||||
CID CIDData;
|
||||
CSD CSDData;
|
||||
} CARD_INFO;
|
||||
|
||||
typedef struct _MMC_HOST_INSTANCE {
|
||||
UINTN Signature;
|
||||
LIST_ENTRY Link;
|
||||
EFI_HANDLE MmcHandle;
|
||||
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
||||
|
||||
MMC_STATE State;
|
||||
EFI_BLOCK_IO_PROTOCOL BlockIo;
|
||||
CARD_INFO CardInfo;
|
||||
EFI_MMC_HOST_PROTOCOL *MmcHost;
|
||||
} MMC_HOST_INSTANCE;
|
||||
|
||||
#define MMC_HOST_INSTANCE_SIGNATURE SIGNATURE_32('m', 'm', 'c', 'h')
|
||||
#define MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS(a) CR (a, MMC_HOST_INSTANCE, BlockIo, MMC_HOST_INSTANCE_SIGNATURE)
|
||||
#define MMC_HOST_INSTANCE_FROM_LINK(a) CR (a, MMC_HOST_INSTANCE, Link, MMC_HOST_INSTANCE_SIGNATURE)
|
||||
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MmcGetDriverName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **DriverName
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MmcGetControllerName (
|
||||
IN EFI_COMPONENT_NAME_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_HANDLE ChildHandle OPTIONAL,
|
||||
IN CHAR8 *Language,
|
||||
OUT CHAR16 **ControllerName
|
||||
);
|
||||
|
||||
extern EFI_COMPONENT_NAME_PROTOCOL gMmcComponentName;
|
||||
extern EFI_COMPONENT_NAME2_PROTOCOL gMmcComponentName2;
|
||||
|
||||
extern EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gMmcDriverDiagnostics2;
|
||||
|
||||
extern LIST_ENTRY mMmcHostPool;
|
||||
|
||||
/**
|
||||
Reset the block device.
|
||||
|
||||
This function implements EFI_BLOCK_IO_PROTOCOL.Reset().
|
||||
It resets the block device hardware.
|
||||
ExtendedVerification is ignored in this implementation.
|
||||
|
||||
@param This Indicates a pointer to the calling context.
|
||||
@param ExtendedVerification Indicates that the driver may perform a more exhaustive
|
||||
verification operation of the device during reset.
|
||||
|
||||
@retval EFI_SUCCESS The block device was reset.
|
||||
@retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MmcReset (
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN BOOLEAN ExtendedVerification
|
||||
);
|
||||
|
||||
/**
|
||||
Reads the requested number of blocks from the device.
|
||||
|
||||
This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks().
|
||||
It reads the requested number of blocks from the device.
|
||||
All the blocks are read, or an error is returned.
|
||||
|
||||
@param This Indicates a pointer to the calling context.
|
||||
@param MediaId The media ID that the read request is for.
|
||||
@param Lba The starting logical block address to read from on the device.
|
||||
@param BufferSize The size of the Buffer in bytes.
|
||||
This must be a multiple of the intrinsic block size of the device.
|
||||
@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 attempting to perform the read operation.
|
||||
@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.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MmcReadBlocks (
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN UINT32 MediaId,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN BufferSize,
|
||||
OUT VOID *Buffer
|
||||
);
|
||||
|
||||
/**
|
||||
Writes a specified number of blocks to the device.
|
||||
|
||||
This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks().
|
||||
It writes a specified number of blocks to the device.
|
||||
All blocks are written, or an error is returned.
|
||||
|
||||
@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.
|
||||
@param BufferSize The size of the Buffer in bytes.
|
||||
This must be a multiple of the intrinsic block size of the device.
|
||||
@param Buffer Pointer to the source buffer for the data.
|
||||
|
||||
@retval EFI_SUCCESS The data were written correctly to the device.
|
||||
@retval EFI_WRITE_PROTECTED The device cannot be written to.
|
||||
@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_DEVICE_ERROR The device reported an error while attempting to perform the write operation.
|
||||
@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 write request contains LBAs that are not valid,
|
||||
or the buffer is not on proper alignment.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MmcWriteBlocks (
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN UINT32 MediaId,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN BufferSize,
|
||||
IN VOID *Buffer
|
||||
);
|
||||
|
||||
/**
|
||||
Flushes all modified data to a physical block device.
|
||||
|
||||
@param This Indicates a pointer to the calling context.
|
||||
|
||||
@retval EFI_SUCCESS All outstanding data were written correctly to the device.
|
||||
@retval EFI_DEVICE_ERROR The device reported an error while attempting to write data.
|
||||
@retval EFI_NO_MEDIA There is no media in the device.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MmcFlushBlocks (
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This
|
||||
);
|
||||
|
||||
#endif
|
614
EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c
Normal file
614
EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c
Normal file
@@ -0,0 +1,614 @@
|
||||
/** @file
|
||||
*
|
||||
* Copyright (c) 2011, ARM Limited. All rights reserved.
|
||||
*
|
||||
* 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 <Protocol/MmcHost.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/TimerLib.h>
|
||||
|
||||
#include "Mmc.h"
|
||||
|
||||
// Untested ...
|
||||
//#define USE_STREAM
|
||||
|
||||
#define MAX_RETRY_COUNT 1000
|
||||
#define CMD_RETRY_COUNT 20
|
||||
|
||||
EFI_STATUS
|
||||
MmcNotifyState (
|
||||
MMC_HOST_INSTANCE *MmcHostInstance,
|
||||
MMC_STATE State
|
||||
) {
|
||||
MmcHostInstance->State = State;
|
||||
return MmcHostInstance->MmcHost->NotifyState(State);
|
||||
}
|
||||
|
||||
VOID PrintOCR(UINT32 ocr) {
|
||||
UINTN minv, maxv, volts;
|
||||
UINTN loop;
|
||||
|
||||
minv = 36; // 3.6
|
||||
maxv = 20; // 2.0
|
||||
volts = 20; // 2.0
|
||||
|
||||
// The MMC register bits [23:8] indicate the working range of the card
|
||||
for (loop = 8; loop < 24; loop++) {
|
||||
if (ocr & (1 << loop)) {
|
||||
if (minv > volts) minv = volts;
|
||||
if (maxv < volts) maxv = volts + 1;
|
||||
}
|
||||
volts = volts + 1;
|
||||
}
|
||||
|
||||
DEBUG((EFI_D_ERROR, "- PrintOCR ocr (0x%X)\n",ocr));
|
||||
DEBUG((EFI_D_ERROR, "\t- Card operating voltage: %d.%d to %d.%d\n", minv/10, minv % 10, maxv/10, maxv % 10));
|
||||
if (((ocr >> 29) & 3) == 0)
|
||||
DEBUG((EFI_D_ERROR, "\t- AccessMode: Byte Mode\n"));
|
||||
else
|
||||
DEBUG((EFI_D_ERROR, "\t- AccessMode: Block Mode (0x%X)\n",((ocr >> 29) & 3)));
|
||||
|
||||
if (ocr & MMC_OCR_POWERUP)
|
||||
DEBUG((EFI_D_ERROR, "\t- PowerUp\n"));
|
||||
else
|
||||
DEBUG((EFI_D_ERROR, "\t- Voltage Not Supported\n"));
|
||||
}
|
||||
|
||||
VOID PrintCID(UINT32* cid) {
|
||||
DEBUG((EFI_D_ERROR, "- PrintCID\n"));
|
||||
DEBUG((EFI_D_ERROR, "\t- Manufacturing date: %d/%d\n",(cid[0] >> 8) & 0xF,(cid[0] >> 12) & 0xFF));
|
||||
DEBUG((EFI_D_ERROR, "\t- Product serial number: 0x%X%X\n",cid[1] & 0xFFFFFF,(cid[0] >> 24) & 0xFF));
|
||||
DEBUG((EFI_D_ERROR, "\t- Product revision: %d\n",cid[1] >> 24));
|
||||
//DEBUG((EFI_D_ERROR, "\t- Product name: %s\n",(char*)(cid + 2)));
|
||||
DEBUG((EFI_D_ERROR, "\t- OEM ID: %c%c\n",(cid[3] >> 8) & 0xFF,(cid[3] >> 16) & 0xFF));
|
||||
}
|
||||
|
||||
VOID PrintCSD(UINT32* csd) {
|
||||
UINTN val32;
|
||||
CONST CHAR8* str_unit[] = { "100kbit/s","1Mbit/s","10Mbit/s","100MBit/s","Unkbown","Unkbown","Unkbown","Unkbown" };
|
||||
CONST CHAR8* str_value[] = { "1.0","1.2","1.3","1.5","2.0","2.5","3.0","3.5","4.0","4.5","5.0","Unknown","Unknown","Unknown","Unknown" };
|
||||
|
||||
if (((csd[2] >> 30) & 0x3) == 0)
|
||||
DEBUG((EFI_D_ERROR, "- PrintCSD Version 1.01-1.10/Version 2.00/Standard Capacity\n"));
|
||||
else if (((csd[2] >> 30) & 0x3) == 1)
|
||||
DEBUG((EFI_D_ERROR, "- PrintCSD Version 2.00/High Capacity\n"));
|
||||
else
|
||||
DEBUG((EFI_D_ERROR, "- PrintCSD Version Higher than v3.3\n"));
|
||||
|
||||
DEBUG((EFI_D_ERROR, "\t- Supported card command class: 0x%X\n",MMC_CSD_GET_CCC(csd)));
|
||||
DEBUG((EFI_D_ERROR, "\t- Speed: %a %a\n",str_value[(MMC_CSD_GET_TRANSPEED(csd) >> 3) & 0xF],str_unit[MMC_CSD_GET_TRANSPEED(csd) & 7]));
|
||||
DEBUG((EFI_D_ERROR, "\t- Maximum Read Data Block: %d\n",2 << (MMC_CSD_GET_READBLLEN(csd)-1)));
|
||||
DEBUG((EFI_D_ERROR, "\t- Maximum Write Data Block: %d\n",2 << (MMC_CSD_GET_WRITEBLLEN(csd)-1)));
|
||||
|
||||
if (!MMC_CSD_GET_FILEFORMATGRP(csd)) {
|
||||
val32 = MMC_CSD_GET_FILEFORMAT(csd);
|
||||
if (val32 == 0) DEBUG((EFI_D_ERROR, "\t- Format(0): Hard disk-like file system with partition table\n"));
|
||||
else if (val32 == 1) DEBUG((EFI_D_ERROR, "\t- Format(1): DOS FAT (floppy-like) with boot sector only (no partition table)\n"));
|
||||
else if (val32 == 2) DEBUG((EFI_D_ERROR, "\t- Format(2): Universal File Format\n"));
|
||||
else DEBUG((EFI_D_ERROR, "\t- Format(3): Others/Unknown\n"));
|
||||
} else {
|
||||
DEBUG((EFI_D_ERROR, "\t- Format: Reserved\n"));
|
||||
}
|
||||
}
|
||||
|
||||
VOID PrintRCA(UINT32 rca) {
|
||||
DEBUG((EFI_D_ERROR, "- PrintRCA: 0x%X\n",rca));
|
||||
DEBUG((EFI_D_ERROR, "\t- Status: 0x%X\n",rca & 0xFFFF));
|
||||
DEBUG((EFI_D_ERROR, "\t- RCA: 0x%X\n",(rca >> 16) & 0xFFFF));
|
||||
}
|
||||
|
||||
VOID PrintResponseR1(UINT32 response) {
|
||||
DEBUG((EFI_D_INFO, "Response: 0x%X\n",response));
|
||||
if (response & (1 << 8)) DEBUG((EFI_D_INFO, "\t- READY_FOR_DATA\n"));
|
||||
|
||||
if (((response >> 9) & 0xF) == 0) DEBUG((EFI_D_INFO, "\t- State: Idle\n"));
|
||||
else if (((response >> 9) & 0xF) == 1) DEBUG((EFI_D_INFO, "\t- State: Ready\n"));
|
||||
else if (((response >> 9) & 0xF) == 2) DEBUG((EFI_D_INFO, "\t- State: Ident\n"));
|
||||
else if (((response >> 9) & 0xF) == 3) DEBUG((EFI_D_INFO, "\t- State: StandBy\n"));
|
||||
else if (((response >> 9) & 0xF) == 4) DEBUG((EFI_D_INFO, "\t- State: Tran\n"));
|
||||
else if (((response >> 9) & 0xF) == 5) DEBUG((EFI_D_INFO, "\t- State: Data\n"));
|
||||
else if (((response >> 9) & 0xF) == 6) DEBUG((EFI_D_INFO, "\t- State: Rcv\n"));
|
||||
else if (((response >> 9) & 0xF) == 7) DEBUG((EFI_D_INFO, "\t- State: Prg\n"));
|
||||
else if (((response >> 9) & 0xF) == 8) DEBUG((EFI_D_INFO, "\t- State: Dis\n"));
|
||||
else DEBUG((EFI_D_INFO, "\t- State: Reserved\n"));
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MmcGetCardStatus(
|
||||
MMC_HOST_INSTANCE *MmcHostInstance
|
||||
){
|
||||
EFI_STATUS Status=EFI_SUCCESS;
|
||||
UINT32 Response[4];
|
||||
UINTN CmdArg;
|
||||
EFI_MMC_HOST_PROTOCOL *MmcHost;
|
||||
|
||||
MmcHost = MmcHostInstance->MmcHost;
|
||||
CmdArg = 0;
|
||||
|
||||
if (MmcHost == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
if(MmcHostInstance->State != MmcHwInitializationState){
|
||||
//Get the Status of the card.
|
||||
CmdArg = MmcHostInstance->CardInfo.RCA << 16;
|
||||
Status = MmcHost->SendCommand(MMC_CMD13, CmdArg);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "MmcGetCardStatus(MMC_CMD13): Error and Status = %r\n", Status));
|
||||
ASSERT(0);
|
||||
return Status;
|
||||
}
|
||||
|
||||
//Read Response
|
||||
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_R1,Response);
|
||||
PrintResponseR1(Response[0]);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MmcIdentificationMode (
|
||||
MMC_HOST_INSTANCE *MmcHostInstance
|
||||
) {
|
||||
EFI_STATUS Status;
|
||||
UINT32 Response[4];
|
||||
UINTN Timeout;
|
||||
UINTN CmdArg;
|
||||
BOOLEAN bHCS;
|
||||
EFI_MMC_HOST_PROTOCOL *MmcHost;
|
||||
UINTN CmdRetryCnt;
|
||||
|
||||
MmcHost = MmcHostInstance->MmcHost;
|
||||
CmdArg = 0;
|
||||
bHCS = FALSE;
|
||||
|
||||
if (MmcHost == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// We can get into this function if we restart the identification mode
|
||||
if (MmcHostInstance->State == MmcHwInitializationState) {
|
||||
// Initialize the MMC Host HW
|
||||
Status = MmcNotifyState (MmcHostInstance, MmcHwInitializationState);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcHwInitializationState\n"));
|
||||
return Status;
|
||||
}
|
||||
} else {
|
||||
//Note: Could even be used in all cases. But it looks this command could put the state machine into inactive for some cards
|
||||
Status = MmcHost->SendCommand(MMC_CMD0, 0);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD0): Error\n"));
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
Status = MmcNotifyState (MmcHostInstance, MmcIdleState);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdleState\n"));
|
||||
return Status;
|
||||
}
|
||||
|
||||
// Are we using SDIO ?
|
||||
Status = MmcHost->SendCommand(MMC_CMD5, 0);
|
||||
if (Status == EFI_SUCCESS) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD5): Error - SDIO not supported.\n"));
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
// Check which kind of card we are using. Ver2.00 or later SD Memory Card (PL180 is SD v1.1)
|
||||
CmdArg = (0x0UL << 12 | BIT8 | 0xCEUL << 0);
|
||||
Status = MmcHost->SendCommand(MMC_CMD8, CmdArg);
|
||||
if (Status == EFI_SUCCESS) {
|
||||
DEBUG ((EFI_D_ERROR, "Card is SD2.0 => Supports high capacity\n"));
|
||||
bHCS = TRUE;
|
||||
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_R7,Response);
|
||||
PrintResponseR1(Response[0]);
|
||||
//check if it is valid response
|
||||
if(Response[0] != CmdArg){
|
||||
DEBUG ((EFI_D_ERROR, "The Card is not usable\n"));
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
} else {
|
||||
DEBUG ((EFI_D_ERROR, "Not a SD2.0 Card\n"));
|
||||
}
|
||||
|
||||
// We need to wait for the MMC or SD card is ready => (gCardInfo.OCRData.Busy == 1)
|
||||
Timeout = MAX_RETRY_COUNT;
|
||||
while (Timeout > 0) {
|
||||
// SD Card or MMC Card ? CMD55 indicates to the card that the next command is an application specific command
|
||||
Status = MmcHost->SendCommand(MMC_CMD55, 0);
|
||||
if (Status == EFI_SUCCESS) {
|
||||
DEBUG ((EFI_D_INFO, "Card should be SD\n"));
|
||||
if (bHCS) {
|
||||
MmcHostInstance->CardInfo.CardType = SD_CARD_2;
|
||||
} else {
|
||||
MmcHostInstance->CardInfo.CardType = SD_CARD;
|
||||
}
|
||||
|
||||
// Note: The first time CmdArg will be zero
|
||||
CmdArg = ((UINTN *) &(MmcHostInstance->CardInfo.OCRData))[0];
|
||||
if (bHCS) {
|
||||
CmdArg |= BIT30;
|
||||
}
|
||||
Status = MmcHost->SendCommand(MMC_ACMD41, CmdArg);
|
||||
if (!EFI_ERROR(Status)) {
|
||||
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_OCR,Response);
|
||||
((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];
|
||||
}
|
||||
} else {
|
||||
DEBUG ((EFI_D_INFO, "Card should be MMC\n"));
|
||||
MmcHostInstance->CardInfo.CardType = MMC_CARD;
|
||||
|
||||
Status = MmcHost->SendCommand(MMC_CMD1, 0x800000);
|
||||
if (!EFI_ERROR(Status)) {
|
||||
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_OCR,Response);
|
||||
((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (!EFI_ERROR(Status)) {
|
||||
if (MmcHostInstance->CardInfo.OCRData.Busy == 0) {
|
||||
MicroSecondDelay(1);
|
||||
Timeout--;
|
||||
} else {
|
||||
if ((MmcHostInstance->CardInfo.CardType == SD_CARD_2) && (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1)) {
|
||||
MmcHostInstance->CardInfo.CardType = SD_CARD_2_HIGH;
|
||||
DEBUG ((EFI_D_ERROR, "High capacity card.\n"));
|
||||
}
|
||||
break; // The MMC/SD card is ready. Continue the Identification Mode
|
||||
}
|
||||
} else {
|
||||
MicroSecondDelay(1);
|
||||
Timeout--;
|
||||
}
|
||||
}
|
||||
|
||||
if (Timeout == 0) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(): No Card\n"));
|
||||
ASSERT(0);
|
||||
return EFI_NO_MEDIA;
|
||||
} else {
|
||||
PrintOCR(Response[0]);
|
||||
}
|
||||
|
||||
Status = MmcNotifyState (MmcHostInstance, MmcReadyState);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcReadyState\n"));
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = MmcHost->SendCommand(MMC_CMD2, 0);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD2): Error\n"));
|
||||
ASSERT(0);
|
||||
return Status;
|
||||
}
|
||||
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_CID,Response);
|
||||
PrintCID(Response);
|
||||
|
||||
Status = MmcNotifyState (MmcHostInstance, MmcIdentificationState);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdentificationState\n"));
|
||||
return Status;
|
||||
}
|
||||
|
||||
CmdArg = 0;
|
||||
CmdRetryCnt = CMD_RETRY_COUNT;
|
||||
//Keep sending CMD 3 until card enters to Standby mode and Card status is ready
|
||||
while((MMC_R0_CURRENTSTATE(Response) != MMC_R0_STATE_STDBY) && CmdRetryCnt-- ){
|
||||
Status = MmcHost->SendCommand(MMC_CMD3, CmdArg);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD3): Error\n"));
|
||||
return Status;
|
||||
}
|
||||
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_RCA,Response);
|
||||
PrintRCA(Response[0]);
|
||||
}
|
||||
|
||||
// For MMC card, RCA is assigned by CMD3 while CMD3 dumps the RCA for SD card
|
||||
if (MmcHostInstance->CardInfo.CardType != MMC_CARD) {
|
||||
MmcHostInstance->CardInfo.RCA = Response[0] >> 16;
|
||||
} else {
|
||||
MmcHostInstance->CardInfo.RCA = CmdArg;
|
||||
}
|
||||
|
||||
Status = MmcNotifyState (MmcHostInstance, MmcStandByState);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcStandByState\n"));
|
||||
return Status;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MmcReset (
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN BOOLEAN ExtendedVerification
|
||||
) {
|
||||
// Implement me. Either send a CMD0 (could not work for some MMC host) or just turn off/turn
|
||||
// on power and restart Identification mode
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
MmcDetectCard (
|
||||
EFI_MMC_HOST_PROTOCOL *MmcHost
|
||||
)
|
||||
{
|
||||
if (!MmcHost->IsCardPresent()) {
|
||||
return EFI_NO_MEDIA;
|
||||
} else {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
#define MMCI0_BLOCKLEN 512
|
||||
#define MMCI0_TIMEOUT 10000
|
||||
|
||||
EFI_STATUS MmcIoBlocks (
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN UINTN Transfer,
|
||||
IN UINT32 MediaId,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN BufferSize,
|
||||
OUT VOID *Buffer
|
||||
) {
|
||||
UINT32 Response[4];
|
||||
EFI_STATUS Status;
|
||||
UINTN CardSize, NumBlocks, BlockSize, CmdArg;
|
||||
UINTN Timeout;
|
||||
UINTN Cmd;
|
||||
MMC_HOST_INSTANCE *MmcHostInstance;
|
||||
EFI_MMC_HOST_PROTOCOL *MmcHost;
|
||||
UINTN BytesRemainingToBeTransfered;
|
||||
UINTN BlockCount = 1;
|
||||
|
||||
MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS(This);
|
||||
ASSERT(MmcHostInstance != 0);
|
||||
MmcHost = MmcHostInstance->MmcHost;
|
||||
ASSERT(MmcHost);
|
||||
|
||||
if (MmcHost == 0) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Check if a Card is Present
|
||||
if (!MmcHost->IsCardPresent()) {
|
||||
MmcHostInstance->BlockIo.Media->MediaPresent = FALSE;
|
||||
MmcHostInstance->BlockIo.Media->LastBlock = 0;
|
||||
MmcHostInstance->BlockIo.Media->BlockSize = 512; // Should be zero but there is a bug in DiskIo
|
||||
MmcHostInstance->BlockIo.Media->ReadOnly = FALSE;
|
||||
return EFI_NO_MEDIA;
|
||||
}
|
||||
|
||||
// If the driver has not been initialized yet then go into Iddentification Mode
|
||||
if (MmcHostInstance->State == MmcHwInitializationState) {
|
||||
MmcIdentificationMode (MmcHostInstance);
|
||||
|
||||
//Send a command to get Card specific data
|
||||
CmdArg = MmcHostInstance->CardInfo.RCA << 16;
|
||||
Status = MmcHost->SendCommand(MMC_CMD9, CmdArg);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD9): Error, Status=%r\n", Status));
|
||||
ASSERT(0);
|
||||
return Status;
|
||||
}
|
||||
//Read Response
|
||||
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_CSD,Response);
|
||||
PrintCSD(Response);
|
||||
|
||||
if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) {
|
||||
ASSERT(0); //TODO: Implementation needed
|
||||
CardSize = MMC_CSD_GET_DEVICESIZE(Response);
|
||||
NumBlocks = ((CardSize + 1) * 1024);;
|
||||
BlockSize = 1 << MMC_CSD_GET_READBLLEN(Response);
|
||||
} else {
|
||||
CardSize = MMC_CSD_GET_DEVICESIZE(Response);
|
||||
NumBlocks = (CardSize + 1) * (1 << (MMC_CSD_GET_DEVICESIZEMULT(Response) + 2));
|
||||
BlockSize = 1 << MMC_CSD_GET_READBLLEN(Response);
|
||||
}
|
||||
|
||||
//For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes.
|
||||
if (BlockSize > 512) {
|
||||
NumBlocks = MultU64x32(NumBlocks, BlockSize/512);
|
||||
BlockSize = 512;
|
||||
}
|
||||
|
||||
MmcHostInstance->BlockIo.Media->LastBlock = (NumBlocks - 1);
|
||||
MmcHostInstance->BlockIo.Media->BlockSize = BlockSize;
|
||||
MmcHostInstance->BlockIo.Media->ReadOnly = MmcHost->IsReadOnly();
|
||||
MmcHostInstance->BlockIo.Media->MediaPresent = TRUE;
|
||||
MmcHostInstance->BlockIo.Media->MediaId++;
|
||||
|
||||
CmdArg = MmcHostInstance->CardInfo.RCA << 16;
|
||||
Status = MmcHost->SendCommand(MMC_CMD7, CmdArg);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD7): Error and Status = %r\n", Status));
|
||||
ASSERT(0);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = MmcNotifyState (MmcHostInstance, MmcTransferState);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcTransferState\n"));
|
||||
return Status;
|
||||
}
|
||||
} else {
|
||||
// Maybe test if the card has changed to update gMmcMedia information
|
||||
if (MmcHostInstance->State == MmcTransferState) {
|
||||
//DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : MmcTransferState\n"));
|
||||
} else if (MmcHostInstance->State == MmcStandByState) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : MmcStandByState\n"));
|
||||
} else {
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (Lba > This->Media->LastBlock) {
|
||||
ASSERT(0);
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if ((BufferSize % This->Media->BlockSize) != 0) {
|
||||
ASSERT(0);
|
||||
return EFI_BAD_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
BytesRemainingToBeTransfered = BufferSize;
|
||||
while (BytesRemainingToBeTransfered > 0) {
|
||||
|
||||
//Check if the Card is in Ready status
|
||||
CmdArg = MmcHostInstance->CardInfo.RCA << 16;
|
||||
Response[0] = 0;
|
||||
Timeout = 20;
|
||||
while((Response[0] & (1 << 8)) && Timeout-- ){
|
||||
Status = MmcHost->SendCommand(MMC_CMD13, CmdArg);
|
||||
if (!EFI_ERROR(Status)){
|
||||
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_R1,Response);
|
||||
}
|
||||
}
|
||||
|
||||
// Set Block Length
|
||||
Status = MmcHost->SendCommand(MMC_CMD16, This->Media->BlockSize);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD16): Error This->Media->BlockSize:%d and Error = %r\n",This->Media->BlockSize, Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
// Block Count (not used). Could return an error for SD card
|
||||
MmcHost->SendCommand(MMC_CMD23, BlockCount);
|
||||
|
||||
//Set command argument based on the card access mode (Byte mode or Block mode)
|
||||
if (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1) {
|
||||
CmdArg = Lba;
|
||||
} else {
|
||||
CmdArg = Lba * This->Media->BlockSize;
|
||||
}
|
||||
|
||||
if (Transfer == MMC_IOBLOCKS_READ) {
|
||||
#ifndef USE_STREAM
|
||||
// Read a single block
|
||||
Cmd = MMC_CMD17;
|
||||
#else
|
||||
//TODO: Should we support read stream (MMC_CMD11)
|
||||
#endif
|
||||
} else {
|
||||
#ifndef USE_STREAM
|
||||
// Write a single block
|
||||
Cmd = MMC_CMD24;
|
||||
#else
|
||||
//TODO: Should we support write stream (MMC_CMD20)
|
||||
#endif
|
||||
}
|
||||
Status = MmcHost->SendCommand(Cmd, CmdArg);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD%d): Error %r\n",Cmd, Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (Transfer == MMC_IOBLOCKS_READ) {
|
||||
#ifndef USE_STREAM
|
||||
// Read one block of Data
|
||||
Status = MmcHost->ReadBlockData(Lba,This->Media->BlockSize,Buffer);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_BLKIO, "MmcIdentificationMode(): Error Read Block Data and Status = %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
#else
|
||||
//TODO: Read a steam
|
||||
ASSERT(0);
|
||||
#endif
|
||||
Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcProgrammingState\n"));
|
||||
return Status;
|
||||
}
|
||||
} else {
|
||||
#ifndef USE_STREAM
|
||||
// Write one block of Data
|
||||
Status = MmcHost->WriteBlockData(Lba,This->Media->BlockSize,Buffer);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_BLKIO, "MmcIdentificationMode(): Error Write Block Data and Status = %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
#else
|
||||
//TODO: Write a steam
|
||||
ASSERT(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Command 12 - Stop transmission (ends read)
|
||||
Status = MmcHost->SendCommand(MMC_CMD12, 0);
|
||||
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_R1b,Response);
|
||||
|
||||
// Command 13 - Read status and wait for programming to complete (return to tran)
|
||||
Timeout = MMCI0_TIMEOUT;
|
||||
CmdArg = MmcHostInstance->CardInfo.RCA << 16;
|
||||
while ((MMC_R0_CURRENTSTATE(Response) != MMC_R0_STATE_TRAN) && Timeout) {
|
||||
MmcHost->SendCommand(MMC_CMD13, CmdArg);
|
||||
MmcHost->ReceiveResponse(MMC_RESPONSE_TYPE_R1,Response);
|
||||
NanoSecondDelay(100);
|
||||
Timeout--;
|
||||
}
|
||||
|
||||
Status = MmcNotifyState (MmcHostInstance, MmcTransferState);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcTransferState\n"));
|
||||
return Status;
|
||||
}
|
||||
|
||||
BytesRemainingToBeTransfered -= This->Media->BlockSize;
|
||||
Lba += BlockCount;
|
||||
Buffer = (UINT8 *)Buffer + This->Media->BlockSize;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MmcReadBlocks (
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN UINT32 MediaId,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN BufferSize,
|
||||
OUT VOID *Buffer
|
||||
) {
|
||||
return MmcIoBlocks (This, MMC_IOBLOCKS_READ, MediaId, Lba, BufferSize, Buffer);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MmcWriteBlocks (
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN UINT32 MediaId,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN BufferSize,
|
||||
IN VOID *Buffer
|
||||
) {
|
||||
return MmcIoBlocks (This, MMC_IOBLOCKS_WRITE, MediaId, Lba, BufferSize, Buffer);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
MmcFlushBlocks (
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This
|
||||
) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
50
EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf
Normal file
50
EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf
Normal file
@@ -0,0 +1,50 @@
|
||||
#/** @file
|
||||
# Build file for the MMC DXE driver
|
||||
#
|
||||
# Copyright (c) 2011, ARM Limited. All rights reserved.
|
||||
#
|
||||
# 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 = MmcDxe
|
||||
FILE_GUID = b6f44cc0-9e45-11df-be21-0002a5d5c51b
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
|
||||
ENTRY_POINT = MmcDxeInitialize
|
||||
|
||||
[Sources.common]
|
||||
ComponentName.c
|
||||
Mmc.c
|
||||
MmcBlockIo.c
|
||||
Diagnostics.c
|
||||
|
||||
[Packages]
|
||||
EmbeddedPkg/EmbeddedPkg.dec
|
||||
MdePkg/MdePkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
UefiLib
|
||||
UefiDriverEntryPoint
|
||||
BaseMemoryLib
|
||||
TimerLib
|
||||
|
||||
[Protocols]
|
||||
gEfiDiskIoProtocolGuid
|
||||
gEfiBlockIoProtocolGuid
|
||||
gEfiDevicePathProtocolGuid
|
||||
gEfiMmcHostProtocolGuid
|
||||
gEfiDriverDiagnostics2ProtocolGuid
|
||||
|
||||
[Depex]
|
||||
TRUE
|
Reference in New Issue
Block a user