⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 flashwriternand.c

📁 手机中写FLASH的代码
💻 C
📖 第 1 页 / 共 2 页
字号:
}

///////////////////////////////////////////////////////////////////////////
//
//  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) &image;
	
	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 + -