Moving OMAP 3530 code out of BeagleBoard package into its own package
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9854 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
763
Omap35xxPkg/Flash/Flash.c
Normal file
763
Omap35xxPkg/Flash/Flash.c
Normal file
@@ -0,0 +1,763 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2008-2009, Apple Inc. All rights reserved.
|
||||
|
||||
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 "Flash.h"
|
||||
|
||||
NAND_PART_INFO_TABLE gNandPartInfoTable[1] = {
|
||||
{ 0x2C, 0xBA, 17, 11 }
|
||||
};
|
||||
|
||||
NAND_FLASH_INFO *gNandFlashInfo = NULL;
|
||||
UINT8 *gEccCode;
|
||||
UINTN gNum512BytesChunks = 0;
|
||||
|
||||
//
|
||||
// Device path for SemiHosting. It contains our autogened Caller ID GUID.
|
||||
//
|
||||
typedef struct {
|
||||
VENDOR_DEVICE_PATH Guid;
|
||||
EFI_DEVICE_PATH_PROTOCOL End;
|
||||
} FLASH_DEVICE_PATH;
|
||||
|
||||
FLASH_DEVICE_PATH gDevicePath = {
|
||||
{
|
||||
{ HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH), 0 },
|
||||
EFI_CALLER_ID_GUID
|
||||
},
|
||||
{ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, sizeof (EFI_DEVICE_PATH_PROTOCOL), 0}
|
||||
};
|
||||
|
||||
|
||||
//Actual page address = Column address + Page address + Block address.
|
||||
UINTN
|
||||
GetActualPageAddressInBytes (
|
||||
UINTN BlockIndex,
|
||||
UINTN PageIndex
|
||||
)
|
||||
{
|
||||
//BlockAddressStart = Start of the Block address in actual NAND
|
||||
//PageAddressStart = Start of the Page address in actual NAND
|
||||
return ((BlockIndex << gNandFlashInfo->BlockAddressStart) + (PageIndex << gNandFlashInfo->PageAddressStart));
|
||||
}
|
||||
|
||||
VOID
|
||||
NandSendCommand (
|
||||
UINT8 Command
|
||||
)
|
||||
{
|
||||
MmioWrite16(GPMC_NAND_COMMAND_0, Command);
|
||||
}
|
||||
|
||||
VOID
|
||||
NandSendAddress (
|
||||
UINT8 Address
|
||||
)
|
||||
{
|
||||
MmioWrite16(GPMC_NAND_ADDRESS_0, Address);
|
||||
}
|
||||
|
||||
UINT16
|
||||
NandReadStatus (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//Send READ STATUS command
|
||||
NandSendCommand(READ_STATUS_CMD);
|
||||
|
||||
//Read status.
|
||||
return MmioRead16(GPMC_NAND_DATA_0);
|
||||
}
|
||||
|
||||
VOID
|
||||
NandSendAddressCycles (
|
||||
UINTN Address
|
||||
)
|
||||
{
|
||||
//Column address
|
||||
NandSendAddress(Address & 0xff);
|
||||
Address >>= 8;
|
||||
|
||||
//Column address
|
||||
NandSendAddress(Address & 0x07);
|
||||
Address >>= 3;
|
||||
|
||||
//Page and Block address
|
||||
NandSendAddress(Address & 0xff);
|
||||
Address >>= 8;
|
||||
|
||||
//Block address
|
||||
NandSendAddress(Address & 0xff);
|
||||
Address >>= 8;
|
||||
|
||||
//Block address
|
||||
NandSendAddress(Address & 0x01);
|
||||
}
|
||||
|
||||
VOID
|
||||
GpmcInit (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//Enable Smart-idle mode.
|
||||
MmioWrite32(GPMC_SYSCONFIG, SMARTIDLEMODE);
|
||||
|
||||
//Set IRQSTATUS and IRQENABLE to the reset value
|
||||
MmioWrite32(GPMC_IRQSTATUS, 0x0);
|
||||
MmioWrite32(GPMC_IRQENABLE, 0x0);
|
||||
|
||||
//Disable GPMC timeout control.
|
||||
MmioWrite32(GPMC_TIMEOUT_CONTROL, TIMEOUTDISABLE);
|
||||
|
||||
//Set WRITEPROTECT bit to enable write access.
|
||||
MmioWrite32(GPMC_CONFIG, WRITEPROTECT_HIGH);
|
||||
|
||||
//NOTE: Following GPMC_CONFIGi_0 register settings are taken from u-boot memory dump.
|
||||
MmioWrite32(GPMC_CONFIG1_0, DEVICETYPE_NAND | DEVICESIZE_X16);
|
||||
MmioWrite32(GPMC_CONFIG2_0, CSRDOFFTIME | CSWROFFTIME);
|
||||
MmioWrite32(GPMC_CONFIG3_0, ADVRDOFFTIME | ADVWROFFTIME);
|
||||
MmioWrite32(GPMC_CONFIG4_0, OEONTIME | OEOFFTIME | WEONTIME | WEOFFTIME);
|
||||
MmioWrite32(GPMC_CONFIG5_0, RDCYCLETIME | WRCYCLETIME | RDACCESSTIME | PAGEBURSTACCESSTIME);
|
||||
MmioWrite32(GPMC_CONFIG6_0, WRACCESSTIME | WRDATAONADMUXBUS | CYCLE2CYCLEDELAY | CYCLE2CYCLESAMECSEN);
|
||||
MmioWrite32(GPMC_CONFIG7_0, MASKADDRESS_128MB | CSVALID | BASEADDRESS);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
NandDetectPart (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
UINT8 NandInfo = 0;
|
||||
UINT8 PartInfo[5];
|
||||
UINTN Index;
|
||||
BOOLEAN Found = FALSE;
|
||||
|
||||
//Send READ ID command
|
||||
NandSendCommand(READ_ID_CMD);
|
||||
|
||||
//Send one address cycle.
|
||||
NandSendAddress(0);
|
||||
|
||||
//Read 5-bytes to idenfity code programmed into the NAND flash devices.
|
||||
//BYTE 0 = Manufacture ID
|
||||
//Byte 1 = Device ID
|
||||
//Byte 2, 3, 4 = Nand part specific information (Page size, Block size etc)
|
||||
for (Index = 0; Index < sizeof(PartInfo); Index++) {
|
||||
PartInfo[Index] = MmioRead16(GPMC_NAND_DATA_0);
|
||||
}
|
||||
|
||||
//Check if the ManufactureId and DeviceId are part of the currently supported nand parts.
|
||||
for (Index = 0; Index < sizeof(gNandPartInfoTable)/sizeof(NAND_PART_INFO_TABLE); Index++) {
|
||||
if (gNandPartInfoTable[Index].ManufactureId == PartInfo[0] && gNandPartInfoTable[Index].DeviceId == PartInfo[1]) {
|
||||
gNandFlashInfo->BlockAddressStart = gNandPartInfoTable[Index].BlockAddressStart;
|
||||
gNandFlashInfo->PageAddressStart = gNandPartInfoTable[Index].PageAddressStart;
|
||||
Found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Found == FALSE) {
|
||||
DEBUG ((EFI_D_ERROR, "Nand part is not currently supported. Manufacture id: %x, Device id: %x\n", PartInfo[0], PartInfo[1]));
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
//Populate NAND_FLASH_INFO based on the result of READ ID command.
|
||||
gNandFlashInfo->ManufactureId = PartInfo[0];
|
||||
gNandFlashInfo->DeviceId = PartInfo[1];
|
||||
NandInfo = PartInfo[3];
|
||||
|
||||
if (PAGE_SIZE(NandInfo) == PAGE_SIZE_2K_VAL) {
|
||||
gNandFlashInfo->PageSize = PAGE_SIZE_2K;
|
||||
} else {
|
||||
DEBUG ((EFI_D_ERROR, "Unknown Page size.\n"));
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
if (SPARE_AREA_SIZE(NandInfo) == SPARE_AREA_SIZE_64B_VAL) {
|
||||
gNandFlashInfo->SparePageSize = SPARE_AREA_SIZE_64B;
|
||||
} else {
|
||||
DEBUG ((EFI_D_ERROR, "Unknown Spare area size.\n"));
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
if (BLOCK_SIZE(NandInfo) == BLOCK_SIZE_128K_VAL) {
|
||||
gNandFlashInfo->BlockSize = BLOCK_SIZE_128K;
|
||||
} else {
|
||||
DEBUG ((EFI_D_ERROR, "Unknown Block size.\n"));
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
if (ORGANIZATION(NandInfo) == ORGANIZATION_X8) {
|
||||
gNandFlashInfo->Organization = 0;
|
||||
} else if (ORGANIZATION(NandInfo) == ORGANIZATION_X16) {
|
||||
gNandFlashInfo->Organization = 1;
|
||||
}
|
||||
|
||||
//Calculate total number of blocks.
|
||||
gNandFlashInfo->NumPagesPerBlock = DivU64x32(gNandFlashInfo->BlockSize, gNandFlashInfo->PageSize);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
VOID
|
||||
NandConfigureEcc (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//Define ECC size 0 and size 1 to 512 bytes
|
||||
MmioWrite32(GPMC_ECC_SIZE_CONFIG, (ECCSIZE0_512BYTES | ECCSIZE1_512BYTES));
|
||||
}
|
||||
|
||||
VOID
|
||||
NandEnableEcc (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//Clear all the ECC result registers and select ECC result register 1
|
||||
MmioWrite32(GPMC_ECC_CONTROL, (ECCCLEAR | ECCPOINTER_REG1));
|
||||
|
||||
//Enable ECC engine on CS0
|
||||
MmioWrite32(GPMC_ECC_CONFIG, (ECCENABLE | ECCCS_0 | ECC16B));
|
||||
}
|
||||
|
||||
VOID
|
||||
NandDisableEcc (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
//Turn off ECC engine.
|
||||
MmioWrite32(GPMC_ECC_CONFIG, ECCDISABLE);
|
||||
}
|
||||
|
||||
VOID
|
||||
NandCalculateEcc (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
UINTN EccResultRegister;
|
||||
UINTN EccResult;
|
||||
|
||||
//Capture 32-bit ECC result for each 512-bytes chunk.
|
||||
//In our case PageSize is 2K so read ECC1-ECC4 result registers and
|
||||
//generate total of 12-bytes of ECC code for the particular page.
|
||||
|
||||
EccResultRegister = GPMC_ECC1_RESULT;
|
||||
|
||||
for (Index = 0; Index < gNum512BytesChunks; Index++) {
|
||||
|
||||
EccResult = MmioRead32(EccResultRegister);
|
||||
|
||||
//Calculate ECC code from 32-bit ECC result value.
|
||||
//NOTE: Following calculation is not part of TRM. We got this information
|
||||
//from Beagleboard mailing list.
|
||||
gEccCode[Index * 3] = EccResult & 0xFF;
|
||||
gEccCode[(Index * 3) + 1] = (EccResult >> 16) & 0xFF;
|
||||
gEccCode[(Index * 3) + 2] = (((EccResult >> 20) & 0xF0) | ((EccResult >> 8) & 0x0F));
|
||||
|
||||
//Point to next ECC result register.
|
||||
EccResultRegister += 4;
|
||||
}
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
NandReadPage (
|
||||
IN UINTN BlockIndex,
|
||||
IN UINTN PageIndex,
|
||||
OUT VOID *Buffer,
|
||||
OUT UINT8 *SpareBuffer
|
||||
)
|
||||
{
|
||||
UINTN Address;
|
||||
UINTN Index;
|
||||
UINTN NumMainAreaWords = (gNandFlashInfo->PageSize/2);
|
||||
UINTN NumSpareAreaWords = (gNandFlashInfo->SparePageSize/2);
|
||||
UINT16 *MainAreaWordBuffer = Buffer;
|
||||
UINT16 *SpareAreaWordBuffer = (UINT16 *)SpareBuffer;
|
||||
UINTN Timeout = MAX_RETRY_COUNT;
|
||||
|
||||
//Generate device address in bytes to access specific block and page index
|
||||
Address = GetActualPageAddressInBytes(BlockIndex, PageIndex);
|
||||
|
||||
//Send READ command
|
||||
NandSendCommand(PAGE_READ_CMD);
|
||||
|
||||
//Send 5 Address cycles to access specific device address
|
||||
NandSendAddressCycles(Address);
|
||||
|
||||
//Send READ CONFIRM command
|
||||
NandSendCommand(PAGE_READ_CONFIRM_CMD);
|
||||
|
||||
//Poll till device is busy.
|
||||
while (Timeout) {
|
||||
if ((NandReadStatus() & NAND_READY) == NAND_READY) {
|
||||
break;
|
||||
}
|
||||
Timeout--;
|
||||
}
|
||||
|
||||
if (Timeout == 0) {
|
||||
DEBUG ((EFI_D_ERROR, "Read page timed out.\n"));
|
||||
return EFI_TIMEOUT;
|
||||
}
|
||||
|
||||
//Reissue READ command
|
||||
NandSendCommand(PAGE_READ_CMD);
|
||||
|
||||
//Enable ECC engine.
|
||||
NandEnableEcc();
|
||||
|
||||
//Read data into the buffer.
|
||||
for (Index = 0; Index < NumMainAreaWords; Index++) {
|
||||
*MainAreaWordBuffer++ = MmioRead16(GPMC_NAND_DATA_0);
|
||||
}
|
||||
|
||||
//Read spare area into the buffer.
|
||||
for (Index = 0; Index < NumSpareAreaWords; Index++) {
|
||||
*SpareAreaWordBuffer++ = MmioRead16(GPMC_NAND_DATA_0);
|
||||
}
|
||||
|
||||
//Calculate ECC.
|
||||
NandCalculateEcc();
|
||||
|
||||
//Turn off ECC engine.
|
||||
NandDisableEcc();
|
||||
|
||||
//Perform ECC correction.
|
||||
//Need to implement..
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
NandWritePage (
|
||||
IN UINTN BlockIndex,
|
||||
IN UINTN PageIndex,
|
||||
OUT VOID *Buffer,
|
||||
IN UINT8 *SpareBuffer
|
||||
)
|
||||
{
|
||||
UINTN Address;
|
||||
UINT16 *MainAreaWordBuffer = Buffer;
|
||||
UINT16 *SpareAreaWordBuffer = (UINT16 *)SpareBuffer;
|
||||
UINTN Index;
|
||||
UINTN NandStatus;
|
||||
UINTN Timeout = MAX_RETRY_COUNT;
|
||||
|
||||
//Generate device address in bytes to access specific block and page index
|
||||
Address = GetActualPageAddressInBytes(BlockIndex, PageIndex);
|
||||
|
||||
//Send SERIAL DATA INPUT command
|
||||
NandSendCommand(PROGRAM_PAGE_CMD);
|
||||
|
||||
//Send 5 Address cycles to access specific device address
|
||||
NandSendAddressCycles(Address);
|
||||
|
||||
//Enable ECC engine.
|
||||
NandEnableEcc();
|
||||
|
||||
//Data input from Buffer
|
||||
for (Index = 0; Index < (gNandFlashInfo->PageSize/2); Index++) {
|
||||
MmioWrite16(GPMC_NAND_DATA_0, *MainAreaWordBuffer++);
|
||||
|
||||
//After each write access, device has to wait to accept data.
|
||||
//Currently we may not be programming proper timing parameters to
|
||||
//the GPMC_CONFIGi_0 registers and we would need to figure that out.
|
||||
//Without following delay, page programming fails.
|
||||
gBS->Stall(1);
|
||||
}
|
||||
|
||||
//Calculate ECC.
|
||||
NandCalculateEcc();
|
||||
|
||||
//Turn off ECC engine.
|
||||
NandDisableEcc();
|
||||
|
||||
//Prepare Spare area buffer with ECC codes.
|
||||
SetMem(SpareBuffer, gNandFlashInfo->SparePageSize, 0xFF);
|
||||
CopyMem(&SpareBuffer[ECC_POSITION], gEccCode, gNum512BytesChunks * 3);
|
||||
|
||||
//Program spare area with calculated ECC.
|
||||
for (Index = 0; Index < (gNandFlashInfo->SparePageSize/2); Index++) {
|
||||
MmioWrite16(GPMC_NAND_DATA_0, *SpareAreaWordBuffer++);
|
||||
}
|
||||
|
||||
//Send PROGRAM command
|
||||
NandSendCommand(PROGRAM_PAGE_CONFIRM_CMD);
|
||||
|
||||
//Poll till device is busy.
|
||||
while (Timeout) {
|
||||
NandStatus = NandReadStatus();
|
||||
if ((NandStatus & NAND_READY) == NAND_READY) {
|
||||
break;
|
||||
}
|
||||
Timeout--;
|
||||
}
|
||||
|
||||
if (Timeout == 0) {
|
||||
DEBUG ((EFI_D_ERROR, "Program page timed out.\n"));
|
||||
return EFI_TIMEOUT;
|
||||
}
|
||||
|
||||
//Bit0 indicates Pass/Fail status
|
||||
if (NandStatus & NAND_FAILURE) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
NandEraseBlock (
|
||||
IN UINTN BlockIndex
|
||||
)
|
||||
{
|
||||
UINTN Address;
|
||||
UINTN NandStatus;
|
||||
UINTN Timeout = MAX_RETRY_COUNT;
|
||||
|
||||
//Generate device address in bytes to access specific block and page index
|
||||
Address = GetActualPageAddressInBytes(BlockIndex, 0);
|
||||
|
||||
//Send ERASE SETUP command
|
||||
NandSendCommand(BLOCK_ERASE_CMD);
|
||||
|
||||
//Send 3 address cycles to device to access Page address and Block address
|
||||
Address >>= 11; //Ignore column addresses
|
||||
|
||||
NandSendAddress(Address & 0xff);
|
||||
Address >>= 8;
|
||||
|
||||
NandSendAddress(Address & 0xff);
|
||||
Address >>= 8;
|
||||
|
||||
NandSendAddress(Address & 0xff);
|
||||
|
||||
//Send ERASE CONFIRM command
|
||||
NandSendCommand(BLOCK_ERASE_CONFIRM_CMD);
|
||||
|
||||
//Poll till device is busy.
|
||||
while (Timeout) {
|
||||
NandStatus = NandReadStatus();
|
||||
if ((NandStatus & NAND_READY) == NAND_READY) {
|
||||
break;
|
||||
}
|
||||
Timeout--;
|
||||
gBS->Stall(1);
|
||||
}
|
||||
|
||||
if (Timeout == 0) {
|
||||
DEBUG ((EFI_D_ERROR, "Erase block timed out for Block: %d.\n", BlockIndex));
|
||||
return EFI_TIMEOUT;
|
||||
}
|
||||
|
||||
//Bit0 indicates Pass/Fail status
|
||||
if (NandStatus & NAND_FAILURE) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
NandReadBlock (
|
||||
IN UINTN StartBlockIndex,
|
||||
IN UINTN EndBlockIndex,
|
||||
OUT VOID *Buffer,
|
||||
OUT VOID *SpareBuffer
|
||||
)
|
||||
{
|
||||
UINTN BlockIndex;
|
||||
UINTN PageIndex;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
|
||||
for (BlockIndex = StartBlockIndex; BlockIndex <= EndBlockIndex; BlockIndex++) {
|
||||
//For each block read number of pages
|
||||
for (PageIndex = 0; PageIndex < gNandFlashInfo->NumPagesPerBlock; PageIndex++) {
|
||||
Status = NandReadPage(BlockIndex, PageIndex, Buffer, SpareBuffer);
|
||||
if (EFI_ERROR(Status)) {
|
||||
return Status;
|
||||
}
|
||||
Buffer = ((UINT8 *)Buffer + gNandFlashInfo->PageSize);
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
NandWriteBlock (
|
||||
IN UINTN StartBlockIndex,
|
||||
IN UINTN EndBlockIndex,
|
||||
OUT VOID *Buffer,
|
||||
OUT VOID *SpareBuffer
|
||||
)
|
||||
{
|
||||
UINTN BlockIndex;
|
||||
UINTN PageIndex;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
|
||||
for (BlockIndex = StartBlockIndex; BlockIndex <= EndBlockIndex; BlockIndex++) {
|
||||
//Page programming.
|
||||
for (PageIndex = 0; PageIndex < gNandFlashInfo->NumPagesPerBlock; PageIndex++) {
|
||||
Status = NandWritePage(BlockIndex, PageIndex, Buffer, SpareBuffer);
|
||||
if (EFI_ERROR(Status)) {
|
||||
return Status;
|
||||
}
|
||||
Buffer = ((UINT8 *)Buffer + gNandFlashInfo->PageSize);
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
NandFlashReset (
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN BOOLEAN ExtendedVerification
|
||||
)
|
||||
{
|
||||
UINTN BusyStall = 50; // microSeconds
|
||||
UINTN ResetBusyTimeout = (1000000 / BusyStall); // 1 Second
|
||||
|
||||
//Send RESET command to device.
|
||||
NandSendCommand(RESET_CMD);
|
||||
|
||||
//Wait for 1ms before we check status register.
|
||||
gBS->Stall(1000);
|
||||
|
||||
//Check BIT#5 & BIT#6 in Status register to make sure RESET is done.
|
||||
while ((NandReadStatus() & NAND_RESET_STATUS) != NAND_RESET_STATUS) {
|
||||
|
||||
//In case of extended verification, wait for extended amount of time
|
||||
//to make sure device is reset.
|
||||
if (ExtendedVerification) {
|
||||
if (ResetBusyTimeout == 0) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
gBS->Stall(BusyStall);
|
||||
ResetBusyTimeout--;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
NandFlashReadBlocks (
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN UINT32 MediaId,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN BufferSize,
|
||||
OUT VOID *Buffer
|
||||
)
|
||||
{
|
||||
UINTN NumBlocks;
|
||||
UINTN EndBlockIndex;
|
||||
EFI_STATUS Status;
|
||||
UINT8 *SpareBuffer = NULL;
|
||||
|
||||
if (Buffer == NULL) {
|
||||
Status = EFI_INVALID_PARAMETER;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (Lba > LAST_BLOCK) {
|
||||
Status = EFI_INVALID_PARAMETER;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((BufferSize % gNandFlashInfo->BlockSize) != 0) {
|
||||
Status = EFI_BAD_BUFFER_SIZE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
NumBlocks = DivU64x32(BufferSize, gNandFlashInfo->BlockSize);
|
||||
EndBlockIndex = ((UINTN)Lba + NumBlocks) - 1;
|
||||
|
||||
SpareBuffer = (UINT8 *)AllocatePool(gNandFlashInfo->SparePageSize);
|
||||
if (SpareBuffer == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
//Read block
|
||||
Status = NandReadBlock((UINTN)Lba, EndBlockIndex, Buffer, SpareBuffer);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "Read block fails: %x\n", Status));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
if (SpareBuffer != NULL) {
|
||||
FreePool (SpareBuffer);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
NandFlashWriteBlocks (
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN UINT32 MediaId,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN BufferSize,
|
||||
IN VOID *Buffer
|
||||
)
|
||||
{
|
||||
UINTN BlockIndex;
|
||||
UINTN NumBlocks;
|
||||
UINTN EndBlockIndex;
|
||||
EFI_STATUS Status;
|
||||
UINT8 *SpareBuffer = NULL;
|
||||
|
||||
if (Buffer == NULL) {
|
||||
Status = EFI_INVALID_PARAMETER;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (Lba > LAST_BLOCK) {
|
||||
Status = EFI_INVALID_PARAMETER;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((BufferSize % gNandFlashInfo->BlockSize) != 0) {
|
||||
Status = EFI_BAD_BUFFER_SIZE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
NumBlocks = DivU64x32(BufferSize, gNandFlashInfo->BlockSize);
|
||||
EndBlockIndex = ((UINTN)Lba + NumBlocks) - 1;
|
||||
|
||||
SpareBuffer = (UINT8 *)AllocatePool(gNandFlashInfo->SparePageSize);
|
||||
if (SpareBuffer == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Erase block
|
||||
for (BlockIndex = (UINTN)Lba; BlockIndex <= EndBlockIndex; BlockIndex++) {
|
||||
Status = NandEraseBlock(BlockIndex);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "Erase block failed. Status: %x\n", Status));
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Program data
|
||||
Status = NandWriteBlock((UINTN)Lba, EndBlockIndex, Buffer, SpareBuffer);
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "Block write fails: %x\n", Status));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
if (SpareBuffer != NULL) {
|
||||
FreePool (SpareBuffer);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
NandFlashFlushBlocks (
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This
|
||||
)
|
||||
{
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
EFI_BLOCK_IO_MEDIA gNandFlashMedia = {
|
||||
SIGNATURE_32('n','a','n','d'), // MediaId
|
||||
FALSE, // RemovableMedia
|
||||
TRUE, // MediaPresent
|
||||
FALSE, // LogicalPartition
|
||||
FALSE, // ReadOnly
|
||||
FALSE, // WriteCaching
|
||||
0, // BlockSize
|
||||
2, // IoAlign
|
||||
0, // Pad
|
||||
0 // LastBlock
|
||||
};
|
||||
|
||||
EFI_BLOCK_IO_PROTOCOL BlockIo =
|
||||
{
|
||||
EFI_BLOCK_IO_INTERFACE_REVISION, // Revision
|
||||
&gNandFlashMedia, // *Media
|
||||
NandFlashReset, // Reset
|
||||
NandFlashReadBlocks, // ReadBlocks
|
||||
NandFlashWriteBlocks, // WriteBlocks
|
||||
NandFlashFlushBlocks // FlushBlocks
|
||||
};
|
||||
|
||||
EFI_STATUS
|
||||
NandFlashInitialize (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
gNandFlashInfo = (NAND_FLASH_INFO *)AllocateZeroPool (sizeof(NAND_FLASH_INFO));
|
||||
|
||||
//Initialize GPMC module.
|
||||
GpmcInit();
|
||||
|
||||
//Reset NAND part
|
||||
NandFlashReset(&BlockIo, FALSE);
|
||||
|
||||
//Detect NAND part and populate gNandFlashInfo structure
|
||||
Status = NandDetectPart ();
|
||||
if (EFI_ERROR(Status)) {
|
||||
DEBUG((EFI_D_ERROR, "Nand part id detection failure: Status: %x\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
//Count total number of 512Bytes chunk based on the page size.
|
||||
if (gNandFlashInfo->PageSize == PAGE_SIZE_512B) {
|
||||
gNum512BytesChunks = 1;
|
||||
} else if (gNandFlashInfo->PageSize == PAGE_SIZE_2K) {
|
||||
gNum512BytesChunks = 4;
|
||||
} else if (gNandFlashInfo->PageSize == PAGE_SIZE_4K) {
|
||||
gNum512BytesChunks = 8;
|
||||
}
|
||||
|
||||
gEccCode = (UINT8 *)AllocatePool(gNum512BytesChunks * 3);
|
||||
if (gEccCode == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
//Configure ECC
|
||||
NandConfigureEcc ();
|
||||
|
||||
//Patch EFI_BLOCK_IO_MEDIA structure.
|
||||
gNandFlashMedia.BlockSize = gNandFlashInfo->BlockSize;
|
||||
gNandFlashMedia.LastBlock = LAST_BLOCK;
|
||||
|
||||
//Publish BlockIO.
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&ImageHandle,
|
||||
&gEfiBlockIoProtocolGuid, &BlockIo,
|
||||
&gEfiDevicePathProtocolGuid, &gDevicePath,
|
||||
NULL
|
||||
);
|
||||
return Status;
|
||||
}
|
||||
|
106
Omap35xxPkg/Flash/Flash.h
Normal file
106
Omap35xxPkg/Flash/Flash.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2008-2009 Apple Inc. All rights reserved.<BR>
|
||||
|
||||
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 FLASH_H
|
||||
#define FLASH_H
|
||||
|
||||
#include <Uefi.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/IoLib.h>
|
||||
#include <Library/PcdLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/IoLib.h>
|
||||
|
||||
#include <Protocol/BlockIo.h>
|
||||
#include <Protocol/Cpu.h>
|
||||
#include <Omap3530/Omap3530.h>
|
||||
|
||||
#define PAGE_SIZE(x) ((x) & 0x01)
|
||||
#define PAGE_SIZE_2K_VAL (0x01UL)
|
||||
|
||||
#define SPARE_AREA_SIZE(x) (((x) >> 2) & 0x01)
|
||||
#define SPARE_AREA_SIZE_64B_VAL (0x1UL)
|
||||
|
||||
#define BLOCK_SIZE(x) (((x) >> 4) & 0x01)
|
||||
#define BLOCK_SIZE_128K_VAL (0x01UL)
|
||||
|
||||
#define ORGANIZATION(x) (((x) >> 6) & 0x01)
|
||||
#define ORGANIZATION_X8 (0x0UL)
|
||||
#define ORGANIZATION_X16 (0x1UL)
|
||||
|
||||
#define PAGE_SIZE_512B (512)
|
||||
#define PAGE_SIZE_2K (2048)
|
||||
#define PAGE_SIZE_4K (4096)
|
||||
#define SPARE_AREA_SIZE_16B (16)
|
||||
#define SPARE_AREA_SIZE_64B (64)
|
||||
|
||||
#define BLOCK_SIZE_16K (16*1024)
|
||||
#define BLOCK_SIZE_128K (128*1024)
|
||||
|
||||
#define BLOCK_COUNT (2048)
|
||||
#define LAST_BLOCK (BLOCK_COUNT - 1)
|
||||
|
||||
#define ECC_POSITION 2
|
||||
|
||||
//List of commands.
|
||||
#define RESET_CMD 0xFF
|
||||
#define READ_ID_CMD 0x90
|
||||
|
||||
#define READ_STATUS_CMD 0x70
|
||||
|
||||
#define PAGE_READ_CMD 0x00
|
||||
#define PAGE_READ_CONFIRM_CMD 0x30
|
||||
|
||||
#define BLOCK_ERASE_CMD 0x60
|
||||
#define BLOCK_ERASE_CONFIRM_CMD 0xD0
|
||||
|
||||
#define PROGRAM_PAGE_CMD 0x80
|
||||
#define PROGRAM_PAGE_CONFIRM_CMD 0x10
|
||||
|
||||
//Nand status register bit definition
|
||||
#define NAND_SUCCESS (0x0UL << 0)
|
||||
#define NAND_FAILURE (0x1UL << 0)
|
||||
|
||||
#define NAND_BUSY (0x0UL << 6)
|
||||
#define NAND_READY (0x1UL << 6)
|
||||
|
||||
#define NAND_RESET_STATUS (0x60UL << 0)
|
||||
|
||||
#define MAX_RETRY_COUNT 1500
|
||||
|
||||
|
||||
typedef struct {
|
||||
UINT8 ManufactureId;
|
||||
UINT8 DeviceId;
|
||||
UINT8 BlockAddressStart; //Start of the Block address in actual NAND
|
||||
UINT8 PageAddressStart; //Start of the Page address in actual NAND
|
||||
} NAND_PART_INFO_TABLE;
|
||||
|
||||
typedef struct {
|
||||
UINT8 ManufactureId;
|
||||
UINT8 DeviceId;
|
||||
UINT8 Organization; //x8 or x16
|
||||
UINT32 PageSize;
|
||||
UINT32 SparePageSize;
|
||||
UINT32 BlockSize;
|
||||
UINT32 NumPagesPerBlock;
|
||||
UINT8 BlockAddressStart; //Start of the Block address in actual NAND
|
||||
UINT8 PageAddressStart; //Start of the Page address in actual NAND
|
||||
} NAND_FLASH_INFO;
|
||||
|
||||
#endif //FLASH_H
|
48
Omap35xxPkg/Flash/Flash.inf
Normal file
48
Omap35xxPkg/Flash/Flash.inf
Normal file
@@ -0,0 +1,48 @@
|
||||
#/** @file
|
||||
#
|
||||
# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
|
||||
# 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 = NandFlash
|
||||
FILE_GUID = 4d00ef14-c4e0-426b-81b7-30a00a14aad6
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
|
||||
ENTRY_POINT = NandFlashInitialize
|
||||
|
||||
|
||||
[Sources.common]
|
||||
Flash.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
Omap35xxPkg/Omap35xxPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
PcdLib
|
||||
UefiLib
|
||||
UefiDriverEntryPoint
|
||||
MemoryAllocationLib
|
||||
IoLib
|
||||
|
||||
[Guids]
|
||||
|
||||
[Protocols]
|
||||
gEfiBlockIoProtocolGuid
|
||||
gEfiCpuArchProtocolGuid
|
||||
|
||||
[Pcd]
|
||||
gOmap35xxTokenSpaceGuid.PcdBeagleGpmcOffset
|
||||
|
||||
[depex]
|
||||
TRUE
|
Reference in New Issue
Block a user