📄 nand.c
字号:
/* --------------------------------------------------------------------------
FILE : nand.c
PURPOSE : NAND driver file
PROJECT : DaVinci CCS NAND Flashing Utility
AUTHOR : Daniel Allred
DATE : 04-Jun-2007
HISTORY
v1.00 - DJA - 04-Jun-2007
Completion (with support for DM6441 and DM6441_LV)
----------------------------------------------------------------------------- */
#include "nandwriter.h"
#include "dm644x.h"
#include "stdio.h"
#include "nand.h"
// Table of ROM supported NAND devices
const NAND_DEVICE_INFO gNandDevInfo[] =
{ // devID, numBlocks, pagesPerBlock, bytesPerPage
{0x6E, 256, 16, 256+8}, /* 1 MB */
{0x68, 256, 16, 256+8}, /* 1 MB */
{0xEC, 256, 16, 256+8}, /* 1 MB */
{0xE8, 256, 16, 256+8}, /* 1 MB */
{0xEA, 512, 16, 256+8}, /* 2 MB */
{0xE3, 512, 16, 512+16}, /* 4 MB */
{0xE5, 512, 16, 512+16}, /* 4 MB */
{0xE6, 1024, 16, 512+16}, /* 8 MB */
{0x39, 1024, 16, 512+16}, /* 8 MB */
{0x6B, 1024, 16, 512+16}, /* 8 MB */
{0x73, 1024, 32, 512+16}, /* 16 MB */
{0x33, 1024, 32, 512+16}, /* 16 MB */
{0x75, 2048, 32, 512+16}, /* 32 MB */
{0x35, 2048, 32, 512+16}, /* 32 MB */
{0x43, 1024, 32, 512+16}, /* 16 MB 0x1243 */
{0x45, 2048, 32, 512+16}, /* 32 MB 0x1245 */
{0x53, 1024, 32, 512+16}, /* 16 MB 0x1253 */
{0x55, 2048, 32, 512+16}, /* 32 MB 0x1255 */
{0x36, 4096, 32, 512+16}, /* 64 MB */
{0x46, 4096, 32, 512+16}, /* 64 MB 0x1346 */
{0x56, 4096, 32, 512+16}, /* 64 MB 0x1356 */
{0x76, 4096, 32, 512+16}, /* 64 MB */
{0x74, 8192, 32, 512+16}, /* 128 MB 0x1374 */
{0x79, 8192, 32, 512+16}, /* 128 MB */
{0x71, 16384, 32, 512+16}, /* 256 MB */
{0xF1, 1024, 64, 2048+64}, /* 128 MB - Big Block */
{0xA1, 1024, 64, 2048+64}, /* 128 MB - Big Block */
{0xAA, 2048, 64, 2048+64}, /* 256 MB - Big Block */
{0xDA, 2048, 64, 2048+64}, /* 256 MB - Big Block */
{0xDC, 4096, 64, 2048+64}, /* 512 MB - Big Block */
{0xAC, 4096, 64, 2048+64}, /* 512 MB - Big Block */
{0xB1, 1024, 64, 2048+64}, /* 128 MB - Big Block 0x22B1 */
{0xC1, 1024, 64, 2048+64}, /* 128 MB - Big Block 0x22C1 */
{0x00, 0, 0, 0} /* Dummy null entry to indicate end of table*/
};
// ***************************************
// Generic Low-level NAND access functions
// ***************************************
VUint8 *flash_make_addr (Uint32 baseAddr, Uint32 offset)
{
return ((VUint8 *) ( baseAddr + offset ));
}
void flash_write_data(PNAND_INFO pNandInfo, Uint32 offset, Uint32 data)
{
volatile FLASHPtr addr;
FLASHData dataword;
dataword.l = data;
addr.cp = flash_make_addr (pNandInfo->flashBase, offset);
switch (pNandInfo->busWidth)
{
case BUS_8BIT:
*addr.cp = dataword.c;
break;
case BUS_16BIT:
*addr.wp = dataword.w;
break;
}
}
void flash_write_cmd (PNAND_INFO pNandInfo, Uint32 cmd)
{
flash_write_data(pNandInfo, NAND_CLE_OFFSET, cmd);
}
void flash_write_addr (PNAND_INFO pNandInfo, Uint32 addr)
{
flash_write_data(pNandInfo, NAND_ALE_OFFSET, addr);
}
void flash_write_bytes(PNAND_INFO pNandInfo, void* pSrc, Uint32 numBytes)
{
volatile FLASHPtr destAddr, srcAddr;
Uint32 i;
srcAddr.cp = (VUint8*) pSrc;
destAddr.cp = flash_make_addr (pNandInfo->flashBase, NAND_DATA_OFFSET );
switch (pNandInfo->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;
}
}
void flash_write_addr_cycles(PNAND_INFO pNandInfo, Uint32 block, Uint32 page)
{
flash_write_addr_bytes(pNandInfo, pNandInfo->numColAddrBytes, 0x00000000);
flash_write_row_addr_bytes(pNandInfo, block, page);
}
void flash_write_addr_bytes(PNAND_INFO pNandInfo, Uint32 numAddrBytes, Uint32 addr)
{
Uint32 i;
for (i=0; i<numAddrBytes; i++)
{
flash_write_addr(pNandInfo, ( (addr >> (8*i) ) & 0xff) );
}
}
void flash_write_row_addr_bytes(PNAND_INFO pNandInfo, Uint32 block, Uint32 page)
{
Uint32 row_addr;
row_addr = (block << (pNandInfo->blkShift - pNandInfo->pageShift)) | page;
flash_write_addr_bytes(pNandInfo, pNandInfo->numRowAddrBytes, row_addr);
}
Uint32 flash_read_data (PNAND_INFO pNandInfo)
{
volatile FLASHPtr addr;
FLASHData cmdword;
cmdword.l = 0x0;
addr.cp = flash_make_addr (pNandInfo->flashBase, NAND_DATA_OFFSET );
switch (pNandInfo->busWidth)
{
case BUS_8BIT:
cmdword.c = *addr.cp;
break;
case BUS_16BIT:
cmdword.w = *addr.wp;
break;
}
return cmdword.l;
}
void flash_read_bytes(PNAND_INFO pNandInfo, void* pDest, Uint32 numBytes)
{
volatile FLASHPtr destAddr, srcAddr;
Uint32 i;
destAddr.cp = (VUint8*) pDest;
srcAddr.cp = flash_make_addr (pNandInfo->flashBase, NAND_DATA_OFFSET );
switch (pNandInfo->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;
}
}
void flash_swap_data(PNAND_INFO pNandInfo, 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 (pNandInfo->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;
}
}
// **********************
// Status Check functions
// **********************
// Poll bit of NANDFSR to indicate ready
Uint32 NAND_WaitForRdy(Uint32 timeout) {
VUint32 cnt;
cnt = timeout;
waitloop(200);
while( !(AEMIF->NANDFSR & NAND_NANDFSR_READY) && ((cnt--) > 0) )
if(cnt <= 0)
{
printf("NAND_WaitForRdy() Timeout!\r\n");
return E_FAIL;
}
return E_PASS;
}
// Wait for the status to be ready in NAND register
// There were some problems reported in DM320 with Ready/Busy pin
// not working with all NANDs. So this check has also been added.
Uint32 NAND_WaitForStatus(PNAND_INFO pNandInfo, Uint32 timeout) {
VUint32 cnt;
Uint32 status;
cnt = timeout;
do
{
flash_write_cmd(pNandInfo, NAND_STATUS);
status = flash_read_data(pNandInfo) & (NAND_STATUS_ERROR | NAND_STATUS_BUSY);
cnt--;
}
while((cnt>0) && !status);
if(cnt == 0)
{
printf("NANDWaitForStatus() Timeout!\r\n");
return E_FAIL;
}
return E_PASS;
}
// ****************************************************
// Read the current ECC calculation and restart process
// ****************************************************
Uint32 NAND_ECCReadAndRestart (PNAND_INFO pNandInfo)
{
VUint32 retval,temp;
// Flush data writes (by reading CS3 data region)
temp = *((VUint32*)(((VUint8*)pNandInfo->flashBase) + 0x02000000));
// Read and mask appropriate (based on CSn space flash is in) ECC regsiter
retval = ((VUint32*)(&(AEMIF->NANDF1ECC)))[pNandInfo->CSOffset] & pNandInfo->ECCMask;
// Write appropriate bit to start ECC calcualtions
AEMIF->NANDFCR |= (1<<(8 + (pNandInfo->CSOffset)));
// Flush NANDFCR write (by reading another CFG register)
temp = AEMIF->ERCSR;
return retval;
}
Uint32 NAND_ECCCorrection(PNAND_INFO pNandInfo, Uint32 ECCold, Uint32 ECCnew, Uint8 *data)
{
Uint16 ECCxorVal, byteAddr, bitAddr;
if (!pNandInfo->ECCEnable)
return E_FAIL;
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 & pNandInfo->ECCMask) )
{
// Single Bit error - can be corrected
ECCxorVal = (Uint16) ((ECCold & 0xFFFF0000) >> 16) ^ ((ECCnew & 0xFFFF0000) >> 16);
byteAddr = (ECCxorVal >> 3);
bitAddr = (ECCxorVal & 0x7);
printf("Single bit flip at byte %d, bit %d.", byteAddr, bitAddr);
data[byteAddr] ^= (0x1 << bitAddr);
return E_PASS;
}
else
{
// Multiple Bit error - nothing we can do
return E_FAIL;
}
}
// *******************
// NAND Init Functions
// *******************
// Initialze NAND interface and find the details of the NAND used
PNAND_INFO NAND_Open(Uint32 baseCSAddr)
{
Uint32 width, *CSRegs;
PNAND_INFO pNandInfo;
// Alloc the main NAND structue
pNandInfo = (PNAND_INFO) ubl_alloc_mem(sizeof(NAND_INFO));
pNandInfo->writeBuff = (Uint8 *) ubl_alloc_mem(MAX_PAGE_SIZE);
pNandInfo->readBuff = (Uint8 *) ubl_alloc_mem(MAX_PAGE_SIZE);
// Set NAND flash base address
pNandInfo->flashBase = baseCSAddr;
//Get the CSOffset (can be 0 through 3 - corresponds with CS2 through CS5)
pNandInfo->CSOffset = ( (pNandInfo->flashBase & (0x0FFFFFFF)) >> 25) - 1;
// Setting the nand_width = 0(8 bit NAND) or 1(16 bit NAND).
width = ( ( (SYSTEM->BOOTCFG) & 0x00000020) >> 5);
pNandInfo->busWidth = (width)?BUS_16BIT:BUS_8BIT;
// Setup AEMIF registers for NAND
CSRegs = (Uint32*) &(AEMIF->AB1CR);
CSRegs[pNandInfo->CSOffset] = 0x3FFFFFFC | width; // Set correct ABxCR reg
AEMIF->NANDFCR |= (0x1 << (pNandInfo->CSOffset)); // NAND enable for CSx
NAND_ECCReadAndRestart(pNandInfo);
// Send reset command to NAND
flash_write_cmd( pNandInfo, NAND_RESET );
if ( NAND_WaitForRdy(NAND_TIMEOUT) != E_PASS )
return NULL;
if ( NAND_GetDetails(pNandInfo) != E_PASS)
return NULL;
return pNandInfo;
}
// Get details of the NAND flash used from the id and the table of NAND devices
Uint32 NAND_GetDetails(PNAND_INFO pNandInfo)
{
Uint32 manfID,deviceID,i,j;
// Issue device read ID command
flash_write_cmd( pNandInfo, NAND_RDID);
flash_write_addr( pNandInfo, NAND_RDIDADD);
// Read ID bytes
manfID = flash_read_data( pNandInfo ) & 0xFF;
deviceID = flash_read_data( pNandInfo ) & 0xFF;
j = flash_read_data( pNandInfo ) & 0xFF;
j = flash_read_data( pNandInfo ) & 0xFF;
i=0;
while (gNandDevInfo[i].devID != 0x00)
{
if(deviceID == gNandDevInfo[i].devID)
{
pNandInfo->manfID = (Uint8) manfID;
printf( "\tManufacturer ID = 0x%8.8X\r\n", pNandInfo->manfID);
pNandInfo->devID = (Uint8) gNandDevInfo[i].devID;
printf( "\tDevice ID = 0x%8.8X\r\n", pNandInfo->devID);
pNandInfo->pagesPerBlock = gNandDevInfo[i].pagesPerBlock;
printf( "\tPages Per Block = %d\r\n", pNandInfo->pagesPerBlock);
pNandInfo->numBlocks = gNandDevInfo[i].numBlocks;
printf( "\tNumber of Blocks = %d\r\n", pNandInfo->numBlocks);
pNandInfo->bytesPerPage = NANDFLASH_PAGESIZE(gNandDevInfo[i].bytesPerPage);
printf( "\tBytes Per Page = %d\r\n", pNandInfo->bytesPerPage);
printf( "\tTotal size = %dM\r\n", (pNandInfo->pagesPerBlock * pNandInfo->bytesPerPage * pNandInfo->numBlocks) >> 20);
break;
}
i++;
}
if (gNandDevInfo[i].devID == 0x00) return E_FAIL;
// Assign the big_block flag
pNandInfo->bigBlock = (pNandInfo->bytesPerPage>MAX_BYTES_PER_OP)?TRUE:FALSE;
// Assign the bytes per operation value
pNandInfo->bytesPerOp = (pNandInfo->bytesPerPage>MAX_BYTES_PER_OP)?MAX_BYTES_PER_OP:pNandInfo->bytesPerPage;
// Assign the number of operations per page value
pNandInfo->numOpsPerPage = (pNandInfo->bytesPerOp < MAX_BYTES_PER_OP)?1:(pNandInfo->bytesPerPage >> MAX_BYTES_PER_OP_SHIFT);
// Assign the number of spare bytes per operation
pNandInfo->spareBytesPerOp = pNandInfo->bytesPerOp >> SPAREBYTES_PER_OP_SHIFT;
// Setup address shift values
j = 0;
while( (pNandInfo->pagesPerBlock >> j) > 1)
{
j++;
}
pNandInfo->blkShift = j;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -