📄 nandboot.c
字号:
row_addr = (block << (gNandInfo.blkShift - gNandInfo.pageShift)) | page;
flash_write_addr_bytes( gNandInfo.numRowAddrBytes, row_addr );
}
static Uint32 flash_read_data()
{
volatile FLASHPtr addr;
FLASHData cmdword;
cmdword.l = 0x0;
addr.cp = flash_make_addr (gNandInfo.flashBase, NAND_DATA_OFFSET );
switch (gNandInfo.busWidth)
{
case BUS_8BIT:
cmdword.c = *addr.cp;
break;
case BUS_16BIT:
cmdword.w = *addr.wp;
break;
}
return cmdword.l;
}
static void flash_read_bytes(void* pDest, Uint32 numBytes)
{
volatile FLASHPtr destAddr, srcAddr;
Uint32 i;
destAddr.cp = (VUint8*) pDest;
srcAddr.cp = flash_make_addr (gNandInfo.flashBase, NAND_DATA_OFFSET );
switch (gNandInfo.busWidth)
{
case BUS_8BIT:
for(i=0;i<( numBytes );i++)
*destAddr.cp++ = *srcAddr.cp;
break;
case BUS_16BIT:
for(i=0;i<( numBytes >> 1);i++)
*destAddr.wp++ = *srcAddr.wp;
break;
}
}
static void flash_swap_data(Uint32* data)
{
Uint32 i,temp = *data;
volatile FLASHPtr dataAddr, tempAddr;
dataAddr.cp = flash_make_addr((Uint32) data, 3);
tempAddr.cp = flash_make_addr((Uint32) &temp,0);
switch (gNandInfo.busWidth)
{
case BUS_8BIT:
for(i=0; i<4; i++)
*dataAddr.cp-- = *tempAddr.cp++;
break;
case BUS_16BIT:
for(i=0; i<2; i++)
*dataAddr.wp-- = *tempAddr.wp++;
break;
}
}
// Basic NAND init
static Uint32 NAND_Init()
{
Uint32 width, *CSRegs;
// Set NAND flash base address
gNandInfo.flashBase = (Uint32)(NAND_DATA_ADDR);
//Get the CSOffset (can be 0 through 3 - corresponds with CS2 through CS5)
gNandInfo.CSOffset = ( (gNandInfo.flashBase & (0x0FFFFFFF)) >> 25) - 1;
// Setting the nand_width = 0(8 bit NAND) or 1(16 bit NAND). AEMIF CS2 bus Width
// is fixed in the DM6437 to be 8-bit.
width = ((SYSTEM->BOOTCFG)&(SYS_BOOTCFG_8_16_MASK))>>16;
gNandInfo.busWidth = (width)?BUS_16BIT:BUS_8BIT;
// Setup AEMIF registers for NAND
CSRegs = (Uint32*) &(NAND_AB1CR);
CSRegs[gNandInfo.CSOffset] = 0x3FFFFFFC | width; // Set correct ABxCR reg
NAND_NANDFCR |= (0x1 << (gNandInfo.CSOffset)); // NAND enable for CSx
NAND_ECCReadAndRestart();
// Send reset command to NAND
NAND_clearEIRR();
flash_write_cmd( NAND_RESET );
if ( NAND_WaitForRdy() != BOOT_SUCCESS )
return BOOT_FAIL;
return NAND_GetDetails();
}
// Detailed NAND device discovery
// Get details of the NAND flash used from the id and the table of NAND devices
static Uint32 NAND_GetDetails()
{
Uint32 manfID,deviceID,i,j;
// Issue device read ID command
flash_write_cmd( NAND_RDID);
flash_write_addr( NAND_RDIDADD);
// Read ID bytes
manfID = flash_read_data( ) & 0xFF;
deviceID = flash_read_data( ) & 0xFF;
j = flash_read_data( ) & 0xFF;
j = flash_read_data( ) & 0xFF;
i=0;
while (gNandDevInfo[i].devID != 0x00)
{
if(deviceID == gNandDevInfo[i].devID)
{
gNandInfo.manfID = (Uint8) manfID;
gNandInfo.devID = (Uint8) gNandDevInfo[i].devID;
gNandInfo.pagesPerBlock = gNandDevInfo[i].pagesPerBlock;
gNandInfo.numBlocks = gNandDevInfo[i].numBlocks;
gNandInfo.bytesPerPage = NANDFLASH_PAGESIZE(gNandDevInfo[i].bytesPerPage);
break;
}
i++;
}
gNandInfo.manfID = (Uint8) manfID;
gNandInfo.devID = (Uint8) gNandDevInfo[i].devID;
gNandInfo.pagesPerBlock = gNandDevInfo[i].pagesPerBlock;
gNandInfo.numBlocks = gNandDevInfo[i].numBlocks;
gNandInfo.bytesPerPage = NANDFLASH_PAGESIZE(gNandDevInfo[i].bytesPerPage);
// Device not supported
if(gNandDevInfo[i].devID == 0x00)
return BOOT_FAIL;
// Assign the big_block flag
gNandInfo.bigBlock = (gNandInfo.bytesPerPage>MAX_BYTES_PER_OP)?TRUE:FALSE;
// Assign the bytes per operation value
gNandInfo.bytesPerOp = (gNandInfo.bytesPerPage>MAX_BYTES_PER_OP)?MAX_BYTES_PER_OP:gNandInfo.bytesPerPage;
// Assign the number of operations per page value
gNandInfo.numOpsPerPage = (gNandInfo.bytesPerOp < MAX_BYTES_PER_OP)?1:(gNandInfo.bytesPerPage >> MAX_BYTES_PER_OP_SHIFT);
// Assign the number of spare bytes per operation
gNandInfo.spareBytesPerOp = gNandInfo.bytesPerOp >> SPAREBYTES_PER_OP_SHIFT;
// Setup address shift values
j = 0;
while( (gNandInfo.pagesPerBlock >> j) > 1)
{
j++;
}
gNandInfo.blkShift = j;
gNandInfo.pageShift = (gNandInfo.bigBlock)?16:8;
gNandInfo.blkShift += gNandInfo.pageShift;
// Set number of column address bytes needed
gNandInfo.numColAddrBytes = gNandInfo.pageShift >> 3;
j = 0;
while( (gNandInfo.numBlocks >> j) > 1)
{
j++;
}
// Set number of row address bytes needed
if ( (gNandInfo.blkShift + j) <= 24 )
{
gNandInfo.numRowAddrBytes = 3 - gNandInfo.numColAddrBytes;
}
else if ((gNandInfo.blkShift + j) <= 32)
{
gNandInfo.numRowAddrBytes = 4 - gNandInfo.numColAddrBytes;
}
else
{
gNandInfo.numRowAddrBytes = 5 - gNandInfo.numColAddrBytes;
}
// Set the ECC bit mask
gNandInfo.ECCMask = 0x00000000;
for (j = 0; (((gNandInfo.bytesPerOp*8)>>j) > 0x1); j++)
{
gNandInfo.ECCMask |= (0x00010001<<j);
}
gNandInfo.ECCOffset = (gNandInfo.bigBlock)?2:0;
return BOOT_SUCCESS;
}
static Uint32 NAND_ECCReadAndRestart ()
{
VUint32 retval,temp;
// Dummy read of CS3 memory region (used to flush CS2 writes)
temp = *((VUint32*)(((VUint8*)gNandInfo.flashBase) + 0x02000000));
// Read and mask appropriate (based on CSn space flash is in) ECC regsiter
retval = ((VUint32*)(&(NAND_NANDF1ECC)))[gNandInfo.CSOffset] & gNandInfo.ECCMask;
// Write appropriate bit to start ECC calcualtions
NAND_NANDFCR |= (1<<(8 + (gNandInfo.CSOffset)));
// Dummy read on CFG bus to guarantee ECC bit is set before we do anything else
temp = NAND_ERCSR;
return retval;
}
// NAND_ECCCorrection - correct single bit errors
static Uint32 NAND_ECCCorrection(Uint32 ECCold, Uint32 ECCnew, Uint8 *data)
{
Uint16 ECCxorVal, byteAddr, bitAddr;
ECCxorVal = (Uint16) ((ECCold & 0xFFFF0000) >> 16) ^ // write ECCo
((ECCold & 0x0000FFFF) >> 0 ) ^ // write ECCe
((ECCnew & 0xFFFF0000) >> 16) ^ // read ECCo
((ECCnew & 0x0000FFFF) >> 0 ); // read ECCe
if ( ECCxorVal == (0x0000FFFF & gNandInfo.ECCMask) )
{
// Single Bit error - can be corrected
ECCxorVal = (Uint16) ((ECCold & 0xFFFF0000) >> 16) ^ ((ECCnew & 0xFFFF0000) >> 16);
byteAddr = (ECCxorVal >> 3);
bitAddr = (ECCxorVal & 0x7);
data[byteAddr] ^= (0x1 << bitAddr);
return BOOT_SUCCESS;
}
else
{
// Multiple Bit error - nothing we can do
return BOOT_FAIL;
}
}
// NAND_ReadPage
static Uint32 NAND_ReadPage(Uint32 block, Uint32 page, Uint8 *dest) {
Uint32 eccValue[MAX_NUM_ECCS];
Uint32 spareValue[MAX_SPARE_BYTES_PER_OP];
Uint8 i;
// Write read command
flash_write_cmd( NAND_LO_PAGE );
// Write address bytes
flash_write_addr_cycles( block, page );
// Additional confirm command for big_block devices
if(gNandInfo.bigBlock) flash_write_cmd( NAND_READ_30H );
// Wait for data to be available
if(NAND_WaitForRdy() != BOOT_SUCCESS)
return BOOT_FAIL;
// Starting the ECC in the NANDFCR register for CS2(bit no.8)
NAND_ECCReadAndRestart();
// Read the page data
for (i=0; i < gNandInfo.numOpsPerPage; i++)
{
// Actually read bytes
flash_read_bytes( (void*)(dest), gNandInfo.bytesPerOp );
// Get the ECC Value
eccValue[i] = NAND_ECCReadAndRestart();
//Increment pointer
dest += gNandInfo.bytesPerOp;
}
// Reset page pointer
dest -= gNandInfo.bytesPerPage;
// Read spare are to see if this is Bad Block
for (i=0; i<gNandInfo.numOpsPerPage; i++)
{
flash_read_bytes( (void*)(spareValue), gNandInfo.spareBytesPerOp );
flash_swap_data( (Uint32*)(spareValue+gNandInfo.ECCOffset) );
// Check for BAD Block Indicator
if (spareValue[BAD_BLOCK_FLAG_OFFSET] == BAD_BLOCK_FLAG) {
return BOOT_FAIL;
}
// Verify ECC value
if(eccValue[i] != spareValue[gNandInfo.ECCOffset])
{
if (NAND_ECCCorrection(spareValue[gNandInfo.ECCOffset],
eccValue[i],
dest + (i*gNandInfo.bytesPerOp) ) != BOOT_SUCCESS)
{
return BOOT_FAIL;
}
}
}
// Return status check result
return NAND_WaitForStatus();
}
/* Wait for the status to be ready
Polling for the pad_wait_i(bit 0) of NANDFSR */
static Uint32 NAND_WaitForRdy() {
Uint32 status;
VUint32 cnt = NAND_BOOT_TIMEOUT;
// waitloop(1000);
status = (NAND_NANDEIRR & NANDEIRR_RB_READY) == NANDEIRR_RB_READY;
while((!(status)) && (cnt > 0)){
status = (NAND_NANDEIRR & NANDEIRR_RB_READY) == NANDEIRR_RB_READY;
--cnt;
}
// Clear Interrupt
NAND_clearEIRR();
if(cnt <= 0)
return BOOT_FAIL;
return BOOT_SUCCESS;
}
/* Wait for the status to be ready in register
There were some problems reported in DM320 with Ready/Busy pin
not working with all NANDs. So this check has also been added */
static Uint32 NAND_WaitForStatus()
{
volatile Uint32 cnt;
Uint32 status;
cnt = NAND_BOOT_TIMEOUT;
do{
flash_write_cmd(NAND_STATUS);
status = flash_read_data() & (NAND_STATUS_ERROR | NAND_STATUS_BUSY);
cnt--;
} while((cnt>0) && !status);
if(cnt == 0)
return BOOT_FAIL;
return BOOT_SUCCESS;
}
void LPSCTransition(Uint8 module, Uint8 state)
{
while (PSC->PTSTAT & 0x00000001);
PSC->MDCTL[module] = ((PSC->MDCTL[module]) & (0xFFFFFFE0)) | (state);
PSC->PTCMD |= 0x00000001;
while ((PSC->PTSTAT) & 0x00000001);
while (((PSC->MDSTAT[module]) & 0x1F) != state);
}
//--------------------------------------------------------------------
// Revision History:
// 2007-May-11 - Updated with new NAND basic functions and support
// table
// 2007-June-21 - Added Bad Block Avoidance
//--------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -