📄 nand.c
字号:
pNandInfo->pageShift = (pNandInfo->bigBlock)?16:8;
pNandInfo->blkShift += pNandInfo->pageShift;
// Set number of column address bytes needed
pNandInfo->numColAddrBytes = pNandInfo->pageShift >> 3;
j = 0;
while( (pNandInfo->numBlocks >> j) > 1)
{
j++;
}
// Set number of row address bytes needed
if ( (pNandInfo->blkShift + j) <= 24 )
{
pNandInfo->numRowAddrBytes = 3 - pNandInfo->numColAddrBytes;
}
else if ((pNandInfo->blkShift + j) <= 32)
{
pNandInfo->numRowAddrBytes = 4 - pNandInfo->numColAddrBytes;
}
else
{
pNandInfo->numRowAddrBytes = 5 - pNandInfo->numColAddrBytes;
}
// Set the ECC bit mask
pNandInfo->ECCMask = 0x00000000;
for (j = 0; (((pNandInfo->bytesPerOp*8)>>j) > 0x1); j++)
{
pNandInfo->ECCMask |= (0x00010001<<j);
}
pNandInfo->ECCOffset = (pNandInfo->bigBlock)?2:0;
pNandInfo->ECCEnable = TRUE;
return E_PASS;
}
// *******************
// NAND Read Functions
// *******************
// Routine to read a page from NAND
Uint32 NAND_ReadPage(PNAND_INFO pNandInfo, Uint32 block, Uint32 page, Uint8 *dest)
{
Uint32 eccValue[4];
Uint32 spareValue[4];
Uint8 i;
// Write read command
flash_write_cmd(pNandInfo,NAND_LO_PAGE);
// Write address bytes
flash_write_addr_cycles(pNandInfo, block, page);
// Additional confirm command for big_block devices
if(pNandInfo->bigBlock)
flash_write_cmd(pNandInfo, NAND_READ_30H);
// Wait for data to be available
if(NAND_WaitForRdy(NAND_TIMEOUT) != E_PASS)
return E_FAIL;
// Starting the ECC in the NANDFCR register for CS region
NAND_ECCReadAndRestart(pNandInfo);
// Read the page data
for (i=0; i < pNandInfo->numOpsPerPage; i++)
{
// Actually read bytes
flash_read_bytes(pNandInfo, (void*)(dest), pNandInfo->bytesPerOp);
// Get the ECC Value
eccValue[i] = NAND_ECCReadAndRestart(pNandInfo);
//Increment pointer
dest += pNandInfo->bytesPerOp;
}
// Reset the page pointer
dest -= pNandInfo->bytesPerPage;
// Check ECCs
for (i=0; i<pNandInfo->numOpsPerPage; i++)
{
flash_read_bytes(pNandInfo, (void*)(spareValue), pNandInfo->spareBytesPerOp);
flash_swap_data(pNandInfo, (Uint32*)(spareValue+pNandInfo->ECCOffset));
// Verify ECC values
if(eccValue[i] != spareValue[pNandInfo->ECCOffset])
{
if ( (!pNandInfo->ECCEnable) &&
(NAND_ECCCorrection( pNandInfo,
spareValue[pNandInfo->ECCOffset],
eccValue[i],
dest+(i*pNandInfo->bytesPerOp) ) != E_PASS) )
{
printf("NAND ECC failure!\r\n");
return E_FAIL;
}
}
}
// Return status check result
return NAND_WaitForStatus(pNandInfo, NAND_TIMEOUT);
}
// ********************
// NAND Write Functions
// ********************
// Generic routine to write a page of data to NAND
Uint32 NAND_WritePage(PNAND_INFO pNandInfo, Uint32 block, Uint32 page, Uint8 *src) {
Uint32 eccValue[4];
Uint32 spareValue[4];
Uint8 i;
// Make sure the NAND page pointer is at start of page
flash_write_cmd(pNandInfo,NAND_LO_PAGE);
// Write program command
flash_write_cmd(pNandInfo, NAND_PGRM_START);
// Write address bytes
flash_write_addr_cycles(pNandInfo,block,page);
// Starting the ECC in the NANDFCR register for current CS region
NAND_ECCReadAndRestart(pNandInfo);
// Write data
for (i=0; i<pNandInfo->numOpsPerPage; i++)
{
flash_write_bytes(pNandInfo, (void*) src, pNandInfo->bytesPerOp);
// Read the ECC value
eccValue[i] = NAND_ECCReadAndRestart(pNandInfo);
// Increment the pointer
src += pNandInfo->bytesPerOp;
}
// Write spare bytes
spareValue[0] = 0xFFFFFFFF;
spareValue[1] = 0xFFFFFFFF;
spareValue[2] = 0xFFFFFFFF;
spareValue[3] = 0xFFFFFFFF;
for (i=0; i<pNandInfo->numOpsPerPage; i++)
{
// Swap the bytes for how the ROM needs them
flash_swap_data(pNandInfo, &(eccValue[i]));
// Place the ECC values where the ROM read routine expects them
spareValue[pNandInfo->ECCOffset] = eccValue[i];
// Actually write the Spare Bytes
flash_write_bytes(pNandInfo, (void*)(spareValue), pNandInfo->spareBytesPerOp);
}
// Write program end command
flash_write_cmd(pNandInfo, NAND_PGRM_END);
// Wait for the device to be ready
if (NAND_WaitForRdy(NAND_TIMEOUT) != E_PASS)
return E_FAIL;
// Return status check result
return NAND_WaitForStatus(pNandInfo, NAND_TIMEOUT);
}
// **********************************************************
// Verify data written by reading and comparing byte for byte
// **********************************************************
Uint32 NAND_VerifyPage(PNAND_INFO pNandInfo, Uint32 block, Uint32 page, Uint8* src, Uint8* dest)
{
Uint32 i;
if (NAND_ReadPage(pNandInfo, block, page, dest) != E_PASS)
return E_FAIL;
for (i=0; i< pNandInfo->bytesPerPage; i++)
{
// Check for data read errors
if (src[i] != dest[i])
{
printf("Data mismatch! Verification failed.\r\n");
printf("Block = %d\r\n", block);
printf("Page = %d\r\n", page);
printf("i = %d\r\n", i);
printf("src[i] = %d\r\n", src[i]);
printf("dest[i] = %d\r\n", dest[i]);
return E_FAIL;
}
}
return E_PASS;
}
// *******************************
// NAND Flash erase block function
// *******************************
Uint32 NAND_EraseBlocks(PNAND_INFO pNandInfo, Uint32 startBlkNum, Uint32 blkCnt)
{
Uint32 i;
// Do bounds checking
if ( (startBlkNum + blkCnt - 1) >= pNandInfo->numBlocks )
return E_FAIL;
// Output info about what we are doing
printf("Erasing blocks 0x%8.8X through 0x%8.8X.\r\n", startBlkNum, (startBlkNum + blkCnt - 1) );
for (i = 0; i < blkCnt; i++)
{
// Start erase command
flash_write_cmd(pNandInfo, NAND_BERASEC1);
// Write the row addr bytes only
flash_write_row_addr_bytes(pNandInfo, (startBlkNum+i), 0);
// Confirm erase command
flash_write_cmd(pNandInfo, NAND_BERASEC2);
// Wait for the device to be ready
if (NAND_WaitForRdy(NAND_TIMEOUT) != E_PASS)
return E_FAIL;
// verify the op succeeded by reading status from flash
if (NAND_WaitForStatus(pNandInfo,NAND_TIMEOUT) != E_PASS)
return E_FAIL;
}
return E_PASS;
}
// *******************************************************************
// NAND Protect and Unprotect commands (not all devices support these)
// *******************************************************************
// NAND Flash unprotect command
Uint32 NAND_UnProtectBlocks(PNAND_INFO pNandInfo, Uint32 startBlkNum, Uint32 blkCnt)
{
Uint32 endBlkNum;
endBlkNum = startBlkNum + blkCnt - 1;
// Do bounds checking
if (endBlkNum >= pNandInfo->numBlocks)
return E_FAIL;
// Output info about what we are doing
printf("Unprotecting blocks 0x%8.8X through 0x%8.8X.\r\n", startBlkNum, endBlkNum);
flash_write_cmd(pNandInfo, NAND_UNLOCK_START);
flash_write_row_addr_bytes(pNandInfo, startBlkNum, 0);
flash_write_cmd(pNandInfo, NAND_UNLOCK_END);
flash_write_row_addr_bytes(pNandInfo, endBlkNum, 0);
return E_PASS;
}
// NAND Flash protect command
void NAND_ProtectBlocks(PNAND_INFO pNandInfo)
{
printf("Protecting the entire NAND flash.\r\n");
flash_write_cmd(pNandInfo, NAND_LOCK);
}
// Generic function to write a UBL or Application header and the associated data
Uint32 NAND_WriteHeaderAndData( PNAND_INFO pNandInfo, NAND_BOOT *nandBoot, Uint8 *srcBuf)
{
Uint32 endBlockNum;
Uint32 *ptr;
Uint32 blockNum;
Uint32 count;
Uint32 countMask;
Uint32 numBlks;
// Get total number of blocks needed
numBlks = 0;
while ( (numBlks * pNandInfo->pagesPerBlock) < (nandBoot->numPage + 1) )
{
numBlks++;
}
printf("Number of blocks needed for writing: 0x%8.8X\r\n",numBlks);
// Check whether writing UBL or APP (based on destination block)
blockNum = nandBoot->block;
if (blockNum == START_UBL_BLOCK_NUM)
{
endBlockNum = END_UBL_BLOCK_NUM;
}
else if (blockNum == START_APP_BLOCK_NUM)
{
endBlockNum = END_APP_BLOCK_NUM;
}
else
{
return E_FAIL; /* Block number is out of range */
}
NAND_WRITE_RETRY:
if (blockNum > endBlockNum)
{
return E_FAIL;
}
printf("Attempting to start in block number 0x%8.8X\r\n", blockNum);
// Unprotect all needed blocks of the Flash
//if (NAND_UnProtectBlocks(pNandInfo,blockNum,numBlks) != E_PASS)
//{
// blockNum++;
// printf("Unprotect failed.\r\n");
// goto NAND_WRITE_RETRY;
//}
// Erase the block where the header goes and the data starts
if (NAND_EraseBlocks(pNandInfo,blockNum,numBlks) != E_PASS)
{
blockNum++;
printf("Erase failed.\r\n");
goto NAND_WRITE_RETRY;
}
// Setup header to be written
ptr = (Uint32 *) pNandInfo->writeBuff;
ptr[0] = nandBoot->magicNum;
ptr[1] = nandBoot->entryPoint;
ptr[2] = nandBoot->numPage;
ptr[3] = blockNum; //always start data in current block
ptr[4] = 1; //always start data in page 1 (this header goes in page 0)
ptr[5] = nandBoot->ldAddress;
// Write the header to page 0 of the current blockNum
printf("Writing header...");
if (NAND_WritePage(pNandInfo, blockNum, 0, pNandInfo->writeBuff) != E_PASS)
{
blockNum++;
printf("Page Write failed.\r\n");
goto NAND_WRITE_RETRY;
}
waitloop(200);
// Verify the page just written
if (NAND_VerifyPage(pNandInfo, blockNum, 0, pNandInfo->writeBuff, pNandInfo->readBuff) != E_PASS)
{
blockNum++;
printf("Page Verify failed.\r\n");
goto NAND_WRITE_RETRY;
}
printf("Successful!\r\n");
count = 1;
// The following assumes power of 2 page_cnt - *should* always be valid
countMask = (Uint32)pNandInfo->pagesPerBlock - 1;
printf("Writing data...");
do {
// Write the UBL or APP data on a per page basis
if (NAND_WritePage(pNandInfo, blockNum, (count & countMask), srcBuf) != E_PASS)
{
blockNum++;
printf("Page Write failed.\r\n");
goto NAND_WRITE_RETRY;
}
waitloop(200);
// Verify the page just written
if (NAND_VerifyPage(pNandInfo, blockNum, (count & countMask), srcBuf, pNandInfo->readBuff) != E_PASS)
{
blockNum++;
printf("Page Verify failed.\r\n");
goto NAND_WRITE_RETRY;
}
count++;
srcBuf += pNandInfo->bytesPerPage;
if (!(count & countMask))
{
blockNum++;
}
} while (count <= nandBoot->numPage);
printf("Successful!\r\n");
//NAND_ProtectBlocks(pNandInfo);
return E_PASS;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -