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

📄 mx_nand512.c

📁 Nand Flash (SAMSUNG_K9K1G08U0B) boot loader for i.Mx31 (freescale).
💻 C
字号:
#include <nand/mx_nand512_define.h>
#include <nand/flashreport.h>
#include "MX31_HABTools.h"

/*******************************************************************************/
// MX21 Register - Memory MAP
/*
#define SYS_FMCR  (0x10027800+0x14)
#define CRM_PCCR0 (0x10027000+0x20)
#define NFC_BASE_ADDR	    (0xDF003000)	
*/

//MX31
#define CCM_RCSR 			(0x53F80000+0x0C)
#define CCM_PDR0 			(0x53F80000+0x04)
#define NFC_BASE_ADDR	    (0xB8000000)	

//MX27
		
#define NFC_MAB0_BASE       (NFC_BASE_ADDR+0x000)	//  main area buffer0
#define NFC_MAB1_BASE       (NFC_BASE_ADDR+0x200)	//  main area buffer1 
#define NFC_MAB2_BASE       (NFC_BASE_ADDR+0x400)	//  main area buffer2 
#define NFC_MAB3_BASE       (NFC_BASE_ADDR+0x600)	//  main area buffer3 
#define NFC_SAB0_BASE       (NFC_BASE_ADDR+0x800)	//  spare area buffer0 
#define NFC_SAB1_BASE       (NFC_BASE_ADDR+0x810)	//  spare area buffer1 
#define NFC_SAB2_BASE       (NFC_BASE_ADDR+0x820)	//  spare area buffer2 
#define NFC_SAB3_BASE       (NFC_BASE_ADDR+0x830)	//  spare area buffer3 
	
#define NFC_REG_BASE        (NFC_BASE_ADDR+0xE00)   //  nfc register area 
#define NFC_BUFSIZE         (NFC_REG_BASE+0x00)	  
#define NFC_BLK_ADD_LOCK    (NFC_REG_BASE+0x02)	    
#define NFC_RAM_BUF_ADDR    (NFC_REG_BASE+0x04)	  
#define NFC_NAND_FLASH_ADDR (NFC_REG_BASE+0x06)	  
#define NFC_NAND_FLASH_CMD  (NFC_REG_BASE+0x08)	  
#define NFC_CONFIGURATION   (NFC_REG_BASE+0x0A)	  
#define NFC_ECC_STAT_RES    (NFC_REG_BASE+0x0C)	  
#define NFC_ECC_RSLT_MA     (NFC_REG_BASE+0x0E)	  
#define NFC_ECC_RSLT_SA     (NFC_REG_BASE+0x10)	  
#define NFC_NF_WR_PROT      (NFC_REG_BASE+0x12)	  
#define NFC_ULOCK_START_BLK (NFC_REG_BASE+0x14)	  
#define NFC_ULOCK_END_BLK   (NFC_REG_BASE+0x16)	  
#define NFC_NF_WR_PROT_STAT (NFC_REG_BASE+0x18)	  
#define NFC_NF_CONFIG1      (NFC_REG_BASE+0x1A)	  
#define NFC_NF_CONFIG2      (NFC_REG_BASE+0x1C)	  
/*******************************************************************************/

#define NAND512_CMD_READ              (0x00)
#define NAND512_CMD_READ1             (0x01)
#define NAND512_CMD_READ2             (0x50)       
#define NAND512_CMD_READ_CONFIRM      (0x30)
#define NAND512_CMD_PAGE_PROG         (0x80)
#define NAND512_CMD_PAGE_PROG_CONFIRM (0x10)
#define NAND512_CMD_ERASE             (0x60)
#define NAND512_CMD_ERASE_CONFIRM     (0xD0)
#define NAND512_CMD_READID            (0x90)
#define NAND512_CMD_RESET             (0xFFFF)
#define NAND512_CMD_READ_STATUS       (0x70)

#define NAND_STATUS_READY          (0x40)
#define NAND_STATUS_NOT_PROTECT    (0x80)
#define NAND_STATUS_PROG_ERROR     (0x01)

/* MX21
#define NF_FMS_2KB                 (0x20)
#define NF_16BIT                   (0x10)
*/

#define NF_FMS_2KB                 (0x40000000)
#define NF_16BIT                   (0x80000000)

#define NFC_BUSY  (!( *(volatile u16 *)NFC_NF_CONFIG2 & 0x8000 ))

nand_t nand_type[] = {
//  manuf  device io    badblock row   num   num     
//  id     id     width marker   addr  of    of     
//                      offset   cycle block page    
  { 0xEC,  0x76,  8,    5,       3,    4096, 32 }, // K9F1208U0M
  { 0xEC,  0x36,  8,    5,       3,    4096, 32 }, // K9K1208Q0C
  { 0xEC,  0x75,  8,    5,       2,    2048, 32 }, // K9F5608U0D
  { 0xEC,  0x79,  8,    5,       3,    8192, 32 }, // K9K1G08U0B
  { 0xEC,  0x78,  8,    5,       3,    8192, 32 }, // K9K1G08R0B
  { 0xEC,  0x45,  16,   11,      2,    2048, 32 }, // K9F5616Q0C  
  { 0x98,  0x79,  8,    5,       3,    8192, 32 }  // TC58DVG02A1FT00
};

nand_t *gNAND;	
extern U32 _gchannel;
	

void nfc_memcpy(u32 SourceAddress, u32 TargetAddress, u32 ByteSize)
{
  u32 i;
  for(i=0; i<ByteSize; i+=4)
    *(volatile u32 *)(TargetAddress+i) = *(volatile u32 *)(SourceAddress+i);
}

u8 nfc_wait(void)
{
  while(NFC_BUSY); /* Wait for Basic Operation Complete */
  return 0;
}

void nfc_address_input(u16 address)
{
   *(volatile u16 *)NFC_NAND_FLASH_ADDR = address;
   *(volatile u16 *)NFC_NF_CONFIG2 = 0x0002;
   nfc_wait();
}

void nfc_address_cycle(u32 Address, u8 NumOfCycle)
{
  u8 i;

  for(i=0; i<NumOfCycle; i++)
    nfc_address_input( (u16)( (Address>>(i*8))&0xFF ) );
}

void nfc_command_input(u16 command)
{
   *(volatile u16 *)NFC_NAND_FLASH_CMD  = command;
   *(volatile u16 *)NFC_NF_CONFIG2      = 0x0001;    
   nfc_wait();
}

void nfc_flash_data_input(void)
{
   *(volatile u16 *)NFC_NF_CONFIG2 = 0x0004;
   nfc_wait();
}

void nfc_flash_data_output(void)
{
   *(volatile u16 *)NFC_NF_CONFIG2 = 0x0008;
   nfc_wait();
}

u8 nfc_ecc_uncorrectable_error(void)
{
   return ( *(volatile u32 *)NFC_ECC_STAT_RES & 0xA ) ? 1 : 0;
}

void NAND_ReadID(u8 *man_id, u8 *dev_id)
{
  u32 tmp;

  nfc_command_input(0x90);
  nfc_address_input(0);
  
  *(volatile u16 *)NFC_NF_CONFIG2 = 0x0010; // FDO = ID Read

  nfc_wait();

  tmp  = *(volatile u32 *)(NFC_MAB3_BASE);

  *man_id = (u8)tmp;
  *dev_id = (u8)(tmp>>8);
}

void NAND_Init(void)
{
  u8  man_id;
  u8  dev_id;
  u16 i;

/* MX21 
  *(volatile u32 *)SYS_FMCR  &= ~NF_16BIT;   // Set to 8-bit NAND
  *(volatile u32 *)SYS_FMCR  &= ~NF_FMS_2KB; // Set to 512B Page Size
  *(volatile u32 *)CRM_PCCR0 |= 0x00080000;  // enable NFC Clock
*/

//MX31
  *(volatile u32 *)CCM_RCSR  &= ~NF_16BIT;   // Set to 8-bit NAND
  *(volatile u32 *)CCM_RCSR  &= ~NF_FMS_2KB;   // Set to 512B Page Size
  *(volatile u32 *)CCM_PDR0 |= 5 << 8;  // set NFC_PODF = 5 (133MHz/6 = 22.2MHz)

//MX27

  *(volatile u16 *)NFC_RAM_BUF_ADDR    = 3;      // select Buffer 3
  *(volatile u16 *)NFC_ULOCK_START_BLK = 0x0000;
  *(volatile u16 *)NFC_ULOCK_END_BLK   = 0xFFFF;
  *(volatile u16 *)NFC_NF_WR_PROT      = 0x0004;
  *(volatile u16 *)NFC_CONFIGURATION   = 0x0002; // unlock the internal RAM buffer
  *(volatile u16 *)NFC_NF_CONFIG2      = 0x8000; // clear all operation
  *(volatile u16 *)NFC_NF_CONFIG1      = 0x0008; // enable ECC and disable spare only    

   NAND_ReadID(&man_id, &dev_id);
    
   gNAND = nand_type;
   i = sizeof(nand_type) / sizeof(nand_t);
   while(i--)
	 if( nand_type[i].man_id == man_id && nand_type[i].dev_id == dev_id )
	 {
	   gNAND = nand_type + i;
	   break;
	 }

   if( gNAND->io_width == 16 )
//MX21     *(volatile u32 *)SYS_FMCR  |=  NF_16BIT;   // Set to 16-bit NAND
//MX31
	*(volatile u32 *)CCM_RCSR  |=  NF_16BIT;   // Set to 16-bit NAND

}


u8 NAND_ReadStatus(void)
{
  nfc_command_input(NAND512_CMD_READ_STATUS);
  *(volatile u16 *)NFC_NF_CONFIG2 = 0x0020; // FDO -> Read Status
  nfc_wait();
  
  return (u8)((*(volatile u32 *)(NFC_MAB3_BASE)) & 0xFF) ;
}

u8 NAND_BlockIsGood(u32 BlockNum)
{
   u16 tmp;
   
   u32 ttt;
   
   nfc_command_input(NAND512_CMD_READ);
   nfc_address_input(0);   // one column cycle for 512B-Page Size NAND
   nfc_address_cycle(BlockNum*NAND_NUM_OF_PAGES, NAND_NUM_OF_ROW_ADDR_CYCLES);
   nfc_flash_data_output();
   
   
   ttt = (NFC_SAB3_BASE+(NAND_BADBLOCK_MARKER_OFFSET/2));
   tmp = *(volatile u16 *)(NFC_SAB3_BASE+((NAND_BADBLOCK_MARKER_OFFSET/2)*2)) ;

   if(NAND_BADBLOCK_MARKER_OFFSET%2)
      return ((tmp&0xFF00)==0xFF00) ;
   else
      return ((tmp&0x00FF)==0x00FF) ;
}

u8 NAND_MarkBadBlock(u32 BlockNum)
{
  u8 i;
  
  for(i=0; i<16; i+=2)
    *(volatile u16 *)(NFC_SAB3_BASE+i) = 0;

  nfc_command_input(NAND512_CMD_PAGE_PROG);
  nfc_address_input(0);   // one column cycle for 512B-Page Size NAND
  nfc_address_cycle(BlockNum*NAND_NUM_OF_PAGES, NAND_NUM_OF_ROW_ADDR_CYCLES);
  nfc_flash_data_input();
  nfc_command_input(NAND512_CMD_PAGE_PROG_CONFIRM);

  return 0;
}

u8 NAND_EraseBlock(u32 BlockNum)
{
  nfc_command_input(NAND512_CMD_ERASE);
  nfc_address_cycle(BlockNum*NAND_NUM_OF_PAGES, NAND_NUM_OF_ROW_ADDR_CYCLES);
  nfc_command_input(NAND512_CMD_ERASE_CONFIRM);

  if( NAND_ReadStatus() & NAND_STATUS_PROG_ERROR )
  {	
    return NAND_ERROR_ERASE;
  }
  else
    return NAND_ERROR_NO;
}

u8 NAND_ReadPage(u32 BlockNum, u32 PageNum, u32 TargetAddress, u32 ByteSize)
{
  nfc_command_input(NAND512_CMD_READ);
  nfc_address_input(0);   // one column cycle for 512B-Page Size NAND
  nfc_address_cycle(BlockNum*NAND_NUM_OF_PAGES+PageNum, NAND_NUM_OF_ROW_ADDR_CYCLES);
  nfc_flash_data_output();

  if(nfc_ecc_uncorrectable_error())
    return NAND_ERROR_ECC;
    
  nfc_memcpy(NFC_MAB3_BASE, TargetAddress, ByteSize);
  
  return NAND_ERROR_NO;  // No Error
}

u8 NAND_StatusReady(void)
{
  return ( NAND_STATUS_READY  & NAND_ReadStatus() ) ? 1 : 0;
}
 
void NAND_Wait(void)
{
  while(!NAND_StatusReady());
}




u8 NAND_WritePage(u32 BlockNum, u32 PageNum, u32 SourceAddress, u32 ByteSize)
{
  u8 i;
  for(i=0; i<16; i+=2)
    *(volatile u16 *)(NFC_SAB3_BASE+i) = 0xFFFF;
  nfc_memcpy(SourceAddress, NFC_MAB3_BASE, ByteSize);

  nfc_command_input(NAND512_CMD_PAGE_PROG);  
  nfc_address_input(0);   // one column cycle for 512B-Page Size NAND
  nfc_address_cycle(BlockNum*NAND_NUM_OF_PAGES+PageNum, NAND_NUM_OF_ROW_ADDR_CYCLES);
  nfc_flash_data_input();
  nfc_command_input(NAND512_CMD_PAGE_PROG_CONFIRM);

  if( NAND_ReadStatus() & NAND_STATUS_PROG_ERROR )
  {
    return NAND_ERROR_PROG; // Program Error
  }
  
  NAND_Wait();
  
  nfc_command_input(NAND512_CMD_READ);
  nfc_address_input(0);   // one column cycle for 512B-Page Size NAND
  nfc_address_cycle(BlockNum*NAND_NUM_OF_PAGES+PageNum, NAND_NUM_OF_ROW_ADDR_CYCLES);
  nfc_flash_data_output();

  if(nfc_ecc_uncorrectable_error())
    return NAND_ERROR_ECC;

  return NAND_ERROR_NO;   // No Error
}

u8 NAND_ComparePage(u32 BlockNum, u32 PageNum, u32 TargetAddress, u32 ByteSize)
{
  u32 i;
  u32 error = 0;

  nfc_command_input(NAND512_CMD_READ);
  nfc_address_input(0);   // one column cycle for 512B-Page Size NAND
  nfc_address_cycle(BlockNum*NAND_NUM_OF_PAGES+PageNum, NAND_NUM_OF_ROW_ADDR_CYCLES);
  nfc_flash_data_output();

  if(nfc_ecc_uncorrectable_error())
    return NAND_ERROR_ECC;
  
  for(i=0; i<ByteSize; i+=2)
    if( (*(volatile u16 *)(NFC_MAB3_BASE+i)) != (*(volatile u16 *)(TargetAddress+i)) ) {
      FlashReport_Error(REPORT_ERROR_VERIFY, TargetAddress+i);
      error++;
  }

  if(error)
    return NAND_ERROR_VERIFY;
    
  return NAND_ERROR_NO;   // No Error
}

u8 NAND_Read(u32 FlashAddress, u32 TargetAddress, u32 ByteSize)
{
   u32 ByteDone = 0;
   u32 BlockNum = FlashAddress/(NAND_NUM_OF_PAGES*NAND_MAIN_BYTESIZE); // FlashAddress must equal to start of block
   u32 PageNum  = 0;
   u32 ReadSize;
   u32 tmp;

   while(ByteSize > ByteDone)
   {
     if( PageNum >= NAND_NUM_OF_PAGES ) { // if end of a block
       BlockNum++;                        // go to next block
       PageNum=0;
     }
       
     if( PageNum == 0 )                  // if Start of Block
       if(!NAND_BlockIsGood(BlockNum))   // if Block is not Good
       {
         BlockNum++;                     
         continue;
       }
     
     ReadSize = ((ByteSize-ByteDone)>NAND_MAIN_BYTESIZE) ? NAND_MAIN_BYTESIZE : (ByteSize-ByteDone);
     tmp = NAND_ReadPage(BlockNum, PageNum, TargetAddress+ByteDone, ReadSize);
     if( tmp != NAND_ERROR_NO ) { // if error
       FlashReport_Error(REPORT_ERROR_STOP, 0);
       return tmp;
     }
     
     ByteDone+=ReadSize;
     PageNum++;
   }
   
   return 0; // complete for no error
}

u8 NAND_Write(u32 FlashAddress, u32 SourceAddress, u32 ByteSize)
{
   u32 tmp;
   u32 ByteDone = 0;
   u32 BlockNum = FlashAddress/(NAND_NUM_OF_PAGES*NAND_MAIN_BYTESIZE); // FlashAddress must equal to start of block
   u32 PageNum  = 0;
   u32 WriteSize;

   while(ByteSize>ByteDone)
   {
     if( PageNum >= NAND_NUM_OF_PAGES ) { // if end of a block
       BlockNum++;                        // go to next block
       PageNum=0;
       FlashReport_ProgramByteDone(ByteDone);       
     }

     if( PageNum == 0 ) {                 //  if Start of Block
       
       NAND_Wait();
       
       if(!NAND_BlockIsGood(BlockNum)) { // if Block is not Good
         BlockNum++;                     
         continue;
       }
      
       NAND_Wait();
      
       if( NAND_EraseBlock(BlockNum) != NAND_ERROR_NO ) // if Block Erase Error
         {

#ifdef HABTOOLKIT_FLASH_LIB
	HAB_flash_status(FLASH_ERASE, ByteDone, _gchannel);
#endif         
         
         
           NAND_MarkBadBlock(BlockNum);
           BlockNum++;   // Skip this block                    
           continue;
         }
         
       
     }
     
     NAND_Wait();
      
     WriteSize = ((ByteSize-ByteDone)>NAND_MAIN_BYTESIZE) ? NAND_MAIN_BYTESIZE : (ByteSize-ByteDone);
     
     tmp = NAND_WritePage(BlockNum, PageNum, SourceAddress+ByteDone, WriteSize);
     if( tmp == NAND_ERROR_ECC ) // if ECC error
     {
         NAND_Wait();
         NAND_MarkBadBlock(BlockNum);
         BlockNum++;                        // Skip this block
         PageNum = 0;
         ByteDone = ByteDone - (PageNum*NAND_MAIN_BYTESIZE) ;
         continue;
     }
     if( tmp == NAND_ERROR_PROG ) // if PROG error
     {
         FlashReport_Error(REPORT_ERROR_PROGEAM, 
                           BlockNum*NAND_MAIN_BYTESIZE*NAND_NUM_OF_PAGES+PageNum*NAND_MAIN_BYTESIZE);
         FlashReport_ProgramComplete();
         return tmp;
     }
     
     // Preparation for Next Page
     ByteDone+=WriteSize;
     PageNum++;
   }
   
   FlashReport_ProgramByteDone(ByteDone);
   FlashReport_ProgramComplete();
   return 0; // complete for no error
}

u8 NAND_Compare(u32 FlashAddress, u32 TargetAddress, u32 ByteSize)
{
   u32 ByteDone = 0;
   u32 BlockNum = FlashAddress/(NAND_NUM_OF_PAGES*NAND_MAIN_BYTESIZE); // FlashAddress must equal to start of block
   u32 PageNum  = 0;
   u32 ReadSize;
   u32 tmp;

   while(ByteSize > ByteDone)
   {
     if( PageNum >= NAND_NUM_OF_PAGES ) { // if end of a block
       FlashReport_VerifyByteDone(ByteDone);
       BlockNum++;                        // go to next block
       PageNum=0;
     }
       
     if( PageNum == 0 )                  // if Start of Block
       if(!NAND_BlockIsGood(BlockNum))   // if Block is not Good
       {
         BlockNum++;                     
         continue;
       }
     
     ReadSize = ((ByteSize-ByteDone)>NAND_MAIN_BYTESIZE) ? NAND_MAIN_BYTESIZE : (ByteSize-ByteDone);
     tmp = NAND_ComparePage(BlockNum, PageNum, TargetAddress+ByteDone, ReadSize);
     if( tmp != NAND_ERROR_NO ) { // if error
       FlashReport_Error(REPORT_ERROR_STOP, 0);
       return tmp;
     }
     
     ByteDone+=ReadSize;
     PageNum++;
   }

   FlashReport_VerifyByteDone(ByteDone);
   FlashReport_VerifyComplete();

   return 0; // complete for no error
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -