📄 flashwriternand.c
字号:
}
///////////////////////////////////////////////////////////////////////////
//
// NAND_ReadPage
//
// Read the content of the Page.
//
// startPageAddr: Starting page address
// pPageBuff : Buffer for the data portion
// pPageInfoBuff: Buffer for Page Info structure
// dwNumPages : Number of Pages
//
///////////////////////////////////////////////////////////////////////////
BOOL NAND_ReadPage(ULONG startPageAddr, LPBYTE pPageBuff,
PPageInfo pPageInfoBuff, ULONG dwNumPages)
{
BYTE eccBuf[4];
BYTE eccStored[4];
// Sanity check
if (!pPageBuff && !pPageInfoBuff || dwNumPages > 1)
{
return FALSE;
}
// Enable the chip
if (pPageBuff)
{ // Issue Read Command
NAND_SendFullCommand(CMD_READ, startPageAddr, 0x00);
// Read the data
NAND_SimpleRead(pPageBuff, PAGE_SIZE);
// We calculate the ECC using Samsung's algorithm
EccGenNFC( pPageBuff, (LPBYTE) &eccStored[0] );
}
// Issue Read Command to Read the Spare Area
NAND_SendFullCommand(CMD_READ2, startPageAddr, 0x00);
// Read the PageInfo data (we only need to read first 12 bytes)
NAND_SimpleRead((LPBYTE) pPageInfoBuff, sizeof(PageInfo));
// Read the ECC buffer
NAND_SimpleRead((LPBYTE) &eccBuf[0], 3);
if (pPageBuff)
{
// Copmare with the ECC generated from the HW
if(eccBuf[0] != eccStored[0]
|| eccBuf[1] != eccStored[1]
|| eccBuf[2] != eccStored[2] )
{
// Now try to correct them
if (flash_CompareEcc(eccBuf, eccStored, pPageBuff) != UNCORRECTED_ERROR)
{
return FALSE;
}
}
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////////
//
// NAND_WritePage
//
// Write dwNumPages pages to the startPageAddr
//
////////////////////////////////////////////////////////////////////////////
BOOL NAND_WritePage(ULONG startPageAddr,
LPBYTE pPageBuff,
PPageInfo pPageInfoBuff,
ULONG dwNumPages)
{
BYTE eccBuf[4];
BYTE eccBuf2[4];
PageInfo si;
if((!pPageBuff && !pPageInfoBuff) || dwNumPages != 1)
{ //buffers unallocated or Pages greater than 1 ( multiple Page writing not supported)
return FALSE;
}
// Remove flash write protection
NAND_WriteProtection(FALSE);
if(pPageBuff)
{
// Issue command
// Set Pointer to 'A' area (0~255)
NF_CMD(CMD_READ);
// Send Write Command and Full Write Address
NAND_SendFullCommand(CMD_WRITE, startPageAddr, 0x00);
// Write the data
NAND_SimpleWrite(pPageBuff, PAGE_SIZE);
// Calculate the ECC using NFC Hardware
EccGenNFC( pPageBuff, (LPBYTE) eccBuf );
// Finish up the write operation
if(!NAND_FinishCommand(CMD_WRITE2))
{
return FALSE;
}
}
// Write into the spare area
// Issue command
// Set Pointer to 'B' area (256~263)
NF_CMD(CMD_READ2);
// Send Write Command and Full Write Address
NAND_SendFullCommand(CMD_WRITE, startPageAddr, 0x00);
// Write the PageInfo data to the media
NAND_SimpleWrite((LPBYTE) pPageInfoBuff, sizeof(PageInfo));
if(pPageBuff)
{
// Write the ECC value to the flash
NAND_SimpleWrite((LPBYTE) &eccBuf[0], 3);
}
// Finish up the write operation
if( !NAND_FinishCommand(CMD_WRITE2) )
{
return FALSE;
}
// Enable flash write protection
NAND_WriteProtection(TRUE);
// Write the command
NAND_SendFullCommand(CMD_READ2, startPageAddr, 0x00);
// Read the PageInfo data (we only need to read first 12 bytes)
NAND_SimpleRead((LPBYTE) &si, sizeof(PageInfo));
// Verify the ECC values
// Read the ECC buffer
NAND_SimpleRead((LPBYTE) &eccBuf2[0], 3);
if (pPageInfoBuff && memcmp( &si, pPageInfoBuff, sizeof(PageInfo)))
{
return FALSE;
}
if (pPageBuff && memcmp( eccBuf2, eccBuf, 3 ))
{
return FALSE;
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////////////
//
// NAND_CheckBadBlock
// Check Bad Block
// Return:
// TRUE: Valid Block
// FALSE: Invalid Block
//
//////////////////////////////////////////////////////////////////////////////////////
BOOL NAND_IsBadBlock(ULONG blockID)
{
PageInfo si;
ULONG dwPageID = blockID << 5;
// Check if the block is invalid
// Start with the 1st page of the block
if (NAND_ReadPage(dwPageID, NULL, &si, 1))
{
if (si.BadBlockFlag != (BYTE) ~(BADBLOCKMARK))
{ //Bad Block Found
return TRUE;
} else if (NAND_ReadPage((dwPageID +1), NULL, &si, 1))
{ // The 1st page shows valid; check the 2nd page
if (si.BadBlockFlag != (BYTE) ~(BADBLOCKMARK))
{ //Bad Block Found at other Page
return TRUE;
} else
{ // The block is Good
return FALSE;
}
} else
{ // Read Failure = Bad Block
return TRUE;
}
} else
{ // Read Failure = Bad Block
return TRUE;
}
}
//////////////////////////////////////////////////////////////////////////////////////
//
// NAND_MarkBlockBad
//
// Mark the block as a bad block. We need to write a 00 to the 517th byte
//
//////////////////////////////////////////////////////////////////////////////////////
BOOL NAND_MarkBlockBad(ULONG blockID)
{
ULONG dwStartPage = blockID << 5;
PageInfo si;
// Setup the Page info
si.BlockReserved = BLOCK_RESERVED | BLOCK_READONLY;
si.BadBlockFlag = BADBLOCKMARK;
// Complete the write
if(!NAND_WritePage(dwStartPage, NULL, &si, 1) )
{
//Failed to mark the block bad
return FALSE;
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////////////
//
// DownloadToNandFlash
//
// Description:
// Copies RAM Memory region to Nand Flash region
//
// Arguments:
// ULONG *startWriteAddress - Base address of the data to be copied
// USHORT *startReadAddress - Base address of the destination address
// ULONG sizeOfFile - Number of bytes to copy
//
// Return:
// Nand Flash Programming Status
//
// Assumptions:
// Nand Flash addresses are always on a halfword boundary, and the byte count
// is always even.
//
//////////////////////////////////////////////////////////////////////////////////////
void DownloadToNANDFlash(ULONG startWriteAddress, //R0 Nand Flash Address
ULONG startReadAddress, //R1 SDRAM Address
ULONG sizeOfFile, //R2
ULONG statusAddress, //R3 status address
enum NANDFlashType flash_id)
{
ULONG dwFirstBlock;
ULONG dwLastBlock;
ULONG block_count;
ULONG dwPage = startWriteAddress;
ULONG dwPagesNeeded = FILE_TO_PAGE_SIZE(sizeOfFile);
ULONG dwLoadAddress = startReadAddress;
ULONG dwLoadBlockAddress = startReadAddress;
// Disable flash write protection
NAND_WriteProtection(FALSE);
//Create block aligned data
dwFirstBlock = dwPage / PAGES_PER_BLOCK;
dwLastBlock = (dwPage + dwPagesNeeded - 1) / PAGES_PER_BLOCK;
// Erase the blocks
for (block_count=dwFirstBlock; block_count<=dwLastBlock; block_count++)
{
// Check if the block is valid
if (NAND_IsBadBlock(block_count))
{
//OK mark this as bad in a table or something and tell the user it is bad
//NAND_MarkBlockBad(block_count);
printf("Bad Block found at address %08X\n", block_count<<14);
dwLastBlock++;
} else
{
if(!NAND_EraseBlock(block_count))
{ // Erase Failure
NAND_MarkBlockBad(block_count);
printf("Bad Block found at address %08X\n", block_count<<14);
dwLastBlock++;
} else // start writing
{
// Store the disk image directly from RAM
// write each Page
dwPage = BLOCK_TO_PAGE(block_count);
while ((dwPage < BLOCK_TO_PAGE(block_count+1)) && dwPagesNeeded )
{
if (!NAND_WritePage(dwPage, (LPBYTE)dwLoadAddress, &block_reserved, 1) )
{ //Failed to write NAND Page
//failed while writing in a block so start over
//the entire block on the next block!
//Point at next block
dwPage = BLOCK_TO_PAGE(block_count+1);
NAND_MarkBlockBad(block_count);
printf("Bad Block found at address %08X\n", block_count<<14);
//Reset the data pointer
dwLoadAddress = dwLoadBlockAddress;
dwLastBlock++;
} else
{ //Wrote NAND Page
dwPage++;
dwLoadAddress += PAGE_SIZE;
dwPagesNeeded--;
}
} //end while
//point at new data
dwLoadBlockAddress = dwLoadAddress;
} //end erase
printf("Flashed 0x%08X bytes of 0x%08X total bytes\n",
(startWriteAddress + dwLoadAddress - startReadAddress),
sizeOfFile);
} //end Bad block check
} //end for
// Enable flash write protection
NAND_WriteProtection(TRUE);
}
//
//OMAP Specific HW Calls
//
void InitHW1610()
{
volatile ULONG *pGpioDirControl4 = (ULONG *) 0xFFFBBC34;
volatile ULONG *pFuncMuxCtrlD = (ULONG *) 0xFFFE1038;
volatile ULONG *pFuncMuxCtrl10 = (ULONG *) 0xFFFE1098;
volatile ULONG *pCompModeCtrl0 = (ULONG *) 0xFFFE100C;
ULONG temp;
//GPIO62 is Flash RdynBsy input
temp = *pGpioDirControl4;
temp = temp | 0x4000;
*pGpioDirControl4 = temp;
temp = *pFuncMuxCtrl10;
temp |= 0x00000048;
temp |= 0x08000000;
temp &= 0xFFFFFFF8; // GPIO62 Mode 0
*pFuncMuxCtrl10 = temp;
temp = *pFuncMuxCtrlD;
temp |= 0x80;
*pFuncMuxCtrlD = temp;
//Set the IO
*pCompModeCtrl0 = 0xEAEF;
}
BOOL IsHelenDeviceID()
{
ULONG tmp;
tmp = READ_REGISTER_ULONG(0xFFFE2004);
if (tmp == 0x16AEC || tmp == 0x16C26)
{
return TRUE;
} else
{
return FALSE;
}
}
void InitNANDHardware()
{
ULONG MPUBootMode, MPUVersion;
// Initialize register pointers
if (IsHelenDeviceID()) //1610 based platform?
{
InitHW1610();
pNFReg = (USHORT *) 0x0A000000; //0x0A000000 (control the EMIFS bus)
pNFCMD = (USHORT *) 0x0A000002; //Bit 0=CLE
pNFADDR = (USHORT *) 0x0A000004; //Bit 1=ALE
pNFDATA = (USHORT *) (pNFReg + 0); //EMIFS bus = Data (I/O)
pNFSTAT = (USHORT *) 0xfffbbc2c; //NAND WAIT pin (GPIO_62 on 1610 Innovator and H2 Sample)
gStatus_Mask = 0x4000; //Bit 14 is Flash Ready/Wait Pin
} else //730 platform
{
MPUBootMode = READ_REGISTER_ULONG(MIF_CONFIG_REG) & BM;
MPUVersion = READ_REGISTER_ULONG(P_CONF_BASE) & PERSEUS_DIE_ID0_OFFSET;
if(MPUVersion) { // ES1.1
if(MPUBootMode) // MPU Boot Mode = 1, CS0 & CS3 swapped
pNFReg = (USHORT *) 0x00000000; // CS0
else
pNFReg = (USHORT *) 0x0c000000; // CS3
}
else // ES1.0
pNFReg = (USHORT *) 0x08000000; // CS2
pNFCMD = (USHORT *) (pNFReg + 0x01); //Bit 0=CLE
pNFADDR = (USHORT *) (pNFReg + 0x02); //Bit 1=ALE
pNFDATA = (USHORT *) (pNFReg + 0); //EMIFS bus = Data (I/O)
pNFSTAT = (USHORT *) 0xfffbd000; //NAND WAIT pin (GPIO_74 of P2)
gStatus_Mask = 0x0400; //Bit 10 is Flash Ready/Wait pin
}
reset_NAND();
}
//
// Initialization of OMAP hardware, this normally occurs in a CCS Gel script
// Added here to support standalone downloads via the onboard Boot ROM
//
void init_OMAPHW()
{
int i;
//This basically will do what the CCS GEL files normally do
//Setting the busses twice here and in CCS gel will crash the early 1610's.
#ifndef USING_CCS
//Set a faster clock so people don't think my program sucks
//96 MHz = 12 MHz *8 this seems pretty modest should work with older devices)
WRITE_REGISTER_USHORT(0xFFFECF00, 0x2410);
while ((READ_REGISTER_USHORT(0xFFFECF00) & 0x01) != 0x01); //Wait for PLL to lock
//EMIFS setup
WRITE_REGISTER_ULONG(0xFFFECC14, 0xFFFB); // EMIFS (nCS1) configuration
WRITE_REGISTER_ULONG(0xFFFECC18, 0xFFFB); // EMIFS (nCS2) configuration
WRITE_REGISTER_ULONG(0xFFFECC1C, 0xFFF9); // EMIFS (nCS3) configuration
#ifdef USES_SDR
//SDR Setup
WRITE_REGISTER_ULONG(0xFFFECC80, 0x06); //Mobile SDRAM
WRITE_REGISTER_ULONG(0xFFFECC20, 0x32B4); // EMIFF (nCS4) configuration
WRITE_REGISTER_ULONG(0xFFFECC84, 0x07); // Manual CMD Addr, CKE high
WRITE_REGISTER_ULONG(0xFFFECC84, 0x00; // Manual CMD Addr NOP command
for (i = 0; i< 5; i++); // Delay Loop
WRITE_REGISTER_ULONG(0xFFFECC84, 0x01); // Precharge Command
WRITE_REGISTER_ULONG(0xFFFECC84, 0x02); // Auto-refresh command
WRITE_REGISTER_ULONG(0xFFFECC84, 0x02); // Auto-refresh command
WRITE_REGISTER_ULONG(0xFFFECC70, 0x0037); // MRS (nCS4) initialization
#else
// DDR setup
WRITE_REGISTER_ULONG(0xFFFECC80, 0x07); // DDR Operation addr Mobile DDR, HPHB mode
WRITE_REGISTER_ULONG(0xFFFECC20, 0x1200B4); // SDRAM Config
WRITE_REGISTER_ULONG(0xFFFECC84, 0x07); // Manual CMD Addr, CKE high
WRITE_REGISTER_ULONG(0xFFFECC84, 0x00); // Manual CMD Addr NOP command
for (i = 0; i< 5; i++); // Delay Loop
WRITE_REGISTER_ULONG(0xFFFECC84, 0x01); // Precharge Command
WRITE_REGISTER_ULONG(0xFFFECC84, 0x02); // Auto-refresh command
WRITE_REGISTER_ULONG(0xFFFECC70, 0x33);
WRITE_REGISTER_ULONG(0xFFFECC78, 0x00); // EMRS1 self refresh all banks
WRITE_REGISTER_ULONG(0xFFFECCC0, 0x06);
WRITE_REGISTER_ULONG(0xFFFECCCC, 0x06);
WRITE_REGISTER_ULONG(0xFFFECC64, 0x06);
#endif //SDR or DDR
WRITE_REGISTER_USHORT(0xFFFECE08, (READ_REGISTER_USHORT(0xFFFECE08) | 0x4)); // Enable ARM peripheral clock
WRITE_REGISTER_USHORT(0xFFFECE14, (READ_REGISTER_USHORT(0xFFFECE14) | 0x1)); // Release OMAP CLKM reset to Helen peripherals
//Set Access Width
WRITE_REGISTER_ULONG(0xFFFEC900, 0x0003FF2F); // two-cycle access width for apif bus
WRITE_REGISTER_ULONG(0xFFFECA00, 0x0000FF22); // two-cycle access width for armrhea private bus
WRITE_REGISTER_ULONG(0xFFFED300, 0x0000FF22); // two-cycle access width for armrhea public bus
// Disable ARM9 Watchdog Timer
WRITE_REGISTER_ULONG(0xFFFEC808, 0x00F5);
WRITE_REGISTER_ULONG(0xFFFEC808, 0x00A0);
// Disable Helen2 Watchdog
WRITE_REGISTER_ULONG(0xFFFEB048, 0xAAAA);
while ((READ_REGISTER_ULONG(0xFFFEB034) & 0x10) == 0x10 );
WRITE_REGISTER_ULONG(0xFFFEB048, 0x5555);
while ((READ_REGISTER_ULONG(0xFFFEB034) & 0x10) == 0x10 );
#endif //CCS or standalone
}
/////////////////////////////////////////////////////////////////////////////////////////////////
//
//Main
//
// Purpose:
// Generates some messaging about the tool, Detects Flash devices, Detects OMAP device,
/////////////////////////////////////////////////////////////////////////////////////////////////
ULONG main(void)
{
enum NANDFlashType nand_flash_id;
//point REad Address at whereever the image section is mapped into
gp_vars->ReadAddress = (ULONG) ℑ
printinfo(gp_vars->Size, gp_vars->ReadAddress, gp_vars->WriteAddress);
InitNANDHardware();
//NAND must sit at 0x08000000 but we use offsets of 0 and up since it is different HW
nand_flash_id = IdentifyNandFlash();
if (nand_flash_id == NANDFLASH_NOT_FOUND)
{
printf("No Flash devices have been found");
} else
{
InitEcc();
printNANDflashtype(nand_flash_id);
DownloadToNANDFlash(gp_vars->WriteAddress,
gp_vars->ReadAddress,
gp_vars->Size,
(ULONG) gp_vars,
nand_flash_id);
printf("Flash writing completed!\n");
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -