www.pudn.com > nand_flash_arithmetic.rar > NandFlash.c


/*************************************************************************/ 
/*                                                                       */ 
/* FILE NAME                                      VERSION                */ 
/*                                                                       */ 
/* source\flash.c                                  1.0                   */ 
/*                                                                       */ 
/* DESCRIPTION                                                           */ 
/*                                                                       */ 
/*                                                                       */ 
/*                                                                       */ 
/* DATA STRUCTURES                                                       */ 
/*                                                                       */ 
/* FUNCTIONS : Flash Fujitsu program code                            */ 
/*                                                                       */ 
/* DEPENDENCIES                                                          */ 
/*                                                                       */ 
/*                                                                       */ 
/*                                                                       */ 
/*                                Copyrigth (C) 2001 AIJISYSTEM CO.,LTD  */ 
/*************************************************************************/ 
 
#include  
#include  
#include "common.h" 
 
#define SAMSUNG 
//#define TOSHIBA 
 
#define PAGE_CNT 32 
#define PAGE_SIZE 512 
#define BLOCK_COUNT 4096  
#define BLOCK_SIZE 0x4000 
 
#define BASE_ADDR	(ulong)0x64000000 
 
volatile ulong *data_reg = (ulong *)0x64000000; 
volatile ulong *spare_data_reg = (ulong *)0x64000320; 
volatile ulong *cle_reg = (ulong *)0x64000300; 
volatile ulong *ale_reg = (ulong *)0x64000304; 
volatile ulong *status_reg = (ulong *)0x64000308; 
volatile ulong *ecc_read_reg = (ulong *)0x6400030c; 
volatile ushort *flash_cfg_reg = (ushort *)0x6400031c; 
volatile ulong *clear_status_reg = (ulong *)0x80000c84; 
 
// WatchDog resetÀ» ¹æÁöÇϱâ À§ÇÑ register 
//volatile ushort *AutoKick_reg = (ushort *)0x3000600;  //MSM3000, 3100, 5000, 5105 
//volatile ushort *AutoKick_reg = (ushort *)0x3000700;  //MSM5100 watch dog address 
//volatile ushort *AutoKick_reg = (ushort *)0x30006d0;  //MSM6050 
//volatile ushort *AutoKick_reg = (ushort *)0x3001080;  //MSM5500 
volatile ushort *AutoKick_reg = (ushort *)0x80000700;  //MSM6100 
 
// Host program°ú data & command¸¦ ÁÖ°í¹Þ±â À§ÇÑ structure 
extern FLASH_INFO Flash_Info; 
 
uchar TempBuf[BLOCK_SIZE]; 
uchar FillBuf[PAGE_SIZE]; 
ulong Current_Block_No = 2; 
ulong Current_Page_No = 0; 
ulong BIB_Block_No = 1; 
ulong LastAddr = 0; 
 
ulong crc = 0; 
ulong image_size = 0; 
/* The CRC table size is based on how many bits at a time we are going 
** to process through the table.  Given that we are processing the data 
** 8 bits at a time, this gives us 2^8 (256) entries. 
*/ 
#define CRC_TAB_SIZE    256             /* 2^CRC_TAB_BITS      */ 
 
/* CRC table for 30 bit CRC, with generator polynomial 0x6030b9c7, 
** calculated 8 bits at a time, MSB first. 
*/ 
const ulong crc30_table[ CRC_TAB_SIZE ] = { 
  0x00000000, 0x2030b9c7, 0x2051ca49, 0x0061738e, 
  0x20932d55, 0x00a39492, 0x00c2e71c, 0x20f25edb, 
  0x2116e36d, 0x01265aaa, 0x01472924, 0x217790e3, 
  0x0185ce38, 0x21b577ff, 0x21d40471, 0x01e4bdb6, 
  0x221d7f1d, 0x022dc6da, 0x024cb554, 0x227c0c93, 
  0x028e5248, 0x22beeb8f, 0x22df9801, 0x02ef21c6, 
  0x030b9c70, 0x233b25b7, 0x235a5639, 0x036aeffe, 
  0x2398b125, 0x03a808e2, 0x03c97b6c, 0x23f9c2ab, 
  0x240a47fd, 0x043afe3a, 0x045b8db4, 0x246b3473, 
  0x04996aa8, 0x24a9d36f, 0x24c8a0e1, 0x04f81926, 
  0x051ca490, 0x252c1d57, 0x254d6ed9, 0x057dd71e, 
  0x258f89c5, 0x05bf3002, 0x05de438c, 0x25eefa4b, 
  0x061738e0, 0x26278127, 0x2646f2a9, 0x06764b6e, 
  0x268415b5, 0x06b4ac72, 0x06d5dffc, 0x26e5663b, 
  0x2701db8d, 0x0731624a, 0x075011c4, 0x2760a803, 
  0x0792f6d8, 0x27a24f1f, 0x27c33c91, 0x07f38556, 
  0x2824363d, 0x08148ffa, 0x0875fc74, 0x284545b3, 
  0x08b71b68, 0x2887a2af, 0x28e6d121, 0x08d668e6, 
  0x0932d550, 0x29026c97, 0x29631f19, 0x0953a6de, 
  0x29a1f805, 0x099141c2, 0x09f0324c, 0x29c08b8b, 
  0x0a394920, 0x2a09f0e7, 0x2a688369, 0x0a583aae, 
  0x2aaa6475, 0x0a9addb2, 0x0afbae3c, 0x2acb17fb, 
  0x2b2faa4d, 0x0b1f138a, 0x0b7e6004, 0x2b4ed9c3, 
  0x0bbc8718, 0x2b8c3edf, 0x2bed4d51, 0x0bddf496, 
  0x0c2e71c0, 0x2c1ec807, 0x2c7fbb89, 0x0c4f024e, 
  0x2cbd5c95, 0x0c8de552, 0x0cec96dc, 0x2cdc2f1b, 
  0x2d3892ad, 0x0d082b6a, 0x0d6958e4, 0x2d59e123, 
  0x0dabbff8, 0x2d9b063f, 0x2dfa75b1, 0x0dcacc76, 
  0x2e330edd, 0x0e03b71a, 0x0e62c494, 0x2e527d53, 
  0x0ea02388, 0x2e909a4f, 0x2ef1e9c1, 0x0ec15006, 
  0x0f25edb0, 0x2f155477, 0x2f7427f9, 0x0f449e3e, 
  0x2fb6c0e5, 0x0f867922, 0x0fe70aac, 0x2fd7b36b, 
  0x3078d5bd, 0x10486c7a, 0x10291ff4, 0x3019a633, 
  0x10ebf8e8, 0x30db412f, 0x30ba32a1, 0x108a8b66, 
  0x116e36d0, 0x315e8f17, 0x313ffc99, 0x110f455e, 
  0x31fd1b85, 0x11cda242, 0x11acd1cc, 0x319c680b, 
  0x1265aaa0, 0x32551367, 0x323460e9, 0x1204d92e, 
  0x32f687f5, 0x12c63e32, 0x12a74dbc, 0x3297f47b, 
  0x337349cd, 0x1343f00a, 0x13228384, 0x33123a43, 
  0x13e06498, 0x33d0dd5f, 0x33b1aed1, 0x13811716, 
  0x14729240, 0x34422b87, 0x34235809, 0x1413e1ce, 
  0x34e1bf15, 0x14d106d2, 0x14b0755c, 0x3480cc9b, 
  0x3564712d, 0x1554c8ea, 0x1535bb64, 0x350502a3, 
  0x15f75c78, 0x35c7e5bf, 0x35a69631, 0x15962ff6, 
  0x366fed5d, 0x165f549a, 0x163e2714, 0x360e9ed3, 
  0x16fcc008, 0x36cc79cf, 0x36ad0a41, 0x169db386, 
  0x17790e30, 0x3749b7f7, 0x3728c479, 0x17187dbe, 
  0x37ea2365, 0x17da9aa2, 0x17bbe92c, 0x378b50eb, 
  0x185ce380, 0x386c5a47, 0x380d29c9, 0x183d900e, 
  0x38cfced5, 0x18ff7712, 0x189e049c, 0x38aebd5b, 
  0x394a00ed, 0x197ab92a, 0x191bcaa4, 0x392b7363, 
  0x19d92db8, 0x39e9947f, 0x3988e7f1, 0x19b85e36, 
  0x3a419c9d, 0x1a71255a, 0x1a1056d4, 0x3a20ef13, 
  0x1ad2b1c8, 0x3ae2080f, 0x3a837b81, 0x1ab3c246, 
  0x1b577ff0, 0x3b67c637, 0x3b06b5b9, 0x1b360c7e, 
  0x3bc452a5, 0x1bf4eb62, 0x1b9598ec, 0x3ba5212b, 
  0x3c56a47d, 0x1c661dba, 0x1c076e34, 0x3c37d7f3, 
  0x1cc58928, 0x3cf530ef, 0x3c944361, 0x1ca4faa6, 
  0x1d404710, 0x3d70fed7, 0x3d118d59, 0x1d21349e, 
  0x3dd36a45, 0x1de3d382, 0x1d82a00c, 0x3db219cb, 
  0x1e4bdb60, 0x3e7b62a7, 0x3e1a1129, 0x1e2aa8ee, 
  0x3ed8f635, 0x1ee84ff2, 0x1e893c7c, 0x3eb985bb, 
  0x3f5d380d, 0x1f6d81ca, 0x1f0cf244, 0x3f3c4b83, 
  0x1fce1558, 0x3ffeac9f, 0x3f9fdf11, 0x1faf66d6 
}; 
 
void Main(void) 
{ 
	switch(Flash_Info.Command) 
	{ 
		case FPROGRAM: Program(); 
				break; 
		case FERASEALL:  
				Flash_Info.Result = 1; 
				//EraseAll(); 
				break; 
		case FERASESEC:  
				Flash_Info.Result = 1; 
				//EraseSector(); 
				break; 
		case FREADID: ReadChipID(); 
				break; 
		case FREADMEM: ReadMem(); 
				break; 
		case FWRITE_BIB: WriteBIB(); 
				break; 
		case FINIT: InitFlash(); 
				break; 
		default : 
			Flash_Info.Result = 0; 
	} 
} 
 
// Flash program function 
void  Program(void) 
{ 
	ulong len, flen, i, fillsize, wSize; 
	volatile ulong status; 
	uchar *srcP, *bsrcP; 
 
    Flash_Info.Result = 0; 
	Flash_Info.TargetAddr &= 0x3FFFFFF; 
	wSize = 0; 
 
	if(Flash_Info.TargetAddr != LastAddr) { 
		fillsize = Flash_Info.TargetAddr - LastAddr; 
		for(i = 0; i < PAGE_SIZE; i++) 
			FillBuf[i] = 0xff; 
 
	    while(fillsize && (Current_Block_No < BLOCK_COUNT)) 
	    { 
	    	if(!(Current_Page_No%PAGE_CNT)) { 
	    		if(!PrepareBlock()) 
	    			return; 
	    	} 
	    	 
	    	if(Current_Block_No >= BLOCK_COUNT) 
	    		return; 
	    		 
			status = WriteChar(FillBuf, Current_Page_No); 
			if(!status) // error 
					return; 
			 
			ReadChar(TempBuf, Current_Page_No*PAGE_SIZE, PAGE_SIZE); 
			if(!Verification((ulong *)TempBuf, PAGE_SIZE, (ulong *)FillBuf)) 
				return; 
			 
			Current_Page_No++; 
			crc = crc_30_step (crc, FillBuf, (ushort)PAGE_SIZE*8); 
			image_size +=PAGE_SIZE; 
			fillsize -= PAGE_SIZE; 
 
			AutoKick(); 
	    } 
	} 
 
	AutoKick(); 
	 
	srcP = (uchar *)Flash_Info.Buf; 
	len = Flash_Info.Length; 
     
    while(len && (Current_Block_No < BLOCK_COUNT)) 
    { 
    	if(!(Current_Page_No%PAGE_CNT)) { 
    		if(!PrepareBlock()) 
    			return; 
    	} 
    	 
    	if(Current_Block_No >= BLOCK_COUNT) 
    		return; 
    		 
		if(len > PAGE_SIZE) 
			flen = PAGE_SIZE; 
		else { 
			flen = len; 
			bsrcP = srcP+len; 
			for(i=len; imagic1 = MAGIC1; 
	bib->magic2 = MAGIC2; 
	bib->version = BIB_VERSION; 
	bib->crc = crc; 
	bib->startaddr = 0x0; 
	bib->length = image_size; 
	bib_size = sizeof(struct boot_info_block); 
	 
	for(i=bib_size; i> 1; 
		no_of_shifts++; 
	} 
 
	/* Set the block address in Nand_Flash_Addr */ 
	nand_cntlr_block_addr = block << (9 + no_of_shifts); 
	*ale_reg = nand_cntlr_block_addr; 
 
	/* Issue the block erase command */ 
	*cle_reg = ERASE_CMD; 
 
	/* Wait for erase command to be executed */ 
	while(*status_reg & ERASE_CMD) 
	; 
 
	/* Check status after erase */ 
	status = *status_reg; 
	if( (status & FS_NAND_OP_ERR_MASK != 0) || 
		(status & FS_NAND_OP_RESULT_MASK != 0) ) 
	{ 
		return 0; 
	} 
 
	return 1; 
} 
 
// Read Manufacturer & Device ID 
void ReadChipID(void) 
{ 
    ulong manId,devId; 
 
	*cle_reg = RESET_CMD; 
 
	*cle_reg = ID_CMD; 
 
	/* Wait for completion. */ 
	while(*status_reg & ID_CMD) 
	{ 
		*AutoKick_reg = 1; 
		*AutoKick_reg = 0; 
	}	 
	 
	manId = *status_reg; 
	 
	 
	devId = (manId >> 15) & 0xff; 
	manId = (manId >> 23) & 0xff; 
 
	Flash_Info.Result = (devId << 8) + manId; 
} 
 
ulong PrepareBlock(void) 
{ 
 
	while(!Bad_Block_Check(++Current_Block_No)) 
		; 
		 
	if(Current_Block_No >= BLOCK_COUNT) 
		return 0; 
 
	if(!OneBlockErase(Current_Block_No)) 
		return 0; 
		 
	Current_Page_No = Current_Block_No*PAGE_CNT; 
 
	return 1; 
} 
 
int BlankCheck(ulong *targetP,ulong targetSize)  
{ 
	ulong i; 
	 
	for(i=0; i PAGE_SIZE) 
			flen = PAGE_SIZE; 
		else 
			flen = len;	 
 
		*ale_reg = targetAddr & 0x01FFFE00; 
		*cle_reg = READ_DATA; 
 
		while(*status_reg & READ_DATA) { 
			*AutoKick_reg = 1; 
			*AutoKick_reg = 0; 
		} 
			 
		status = *status_reg; 
		 
		if( (status & FS_NAND_OP_ERR_MASK != 0) ||  
			(status & FS_NAND_ECC_SELF_ERR_MASK != 0) ||  
			(status & FS_NAND_READ_ECC_ERR_MASK != 0) ) 
				return 0;		 
		 
//		for(j=0; j= 8; len -= 8, buf_ptr++) { 
    crc_30 = crc30_table[ ((crc_30 >> (30 - 8)) ^ *buf_ptr) & 0xff ] 
                ^ (crc_30 << 8); 
  } 
 
  /* Finish calculating the CRC over the trailing data bits 
  ** 
  ** XOR the MS bit of data with the MS bit of the CRC. 
  ** Shift the CRC and data left 1 bit. 
  ** If the XOR result is 1, XOR the generating polynomial in with the CRC. 
  */ 
  if (len != 0) { 
 
    data = ((ulong) (*buf_ptr)) << (30-8); /* Align data MSB with CRC MSB */ 
 
    while (len-- != 0) { 
      if ( ((crc_30 ^ data) & (1L << 29)) != 0 ) {       /* Is MSB of XOR a 1 */ 
 
        crc_30 <<= 1;                   /* Left shift CRC          */ 
        crc_30 ^= CRC_30_POLYNOMIAL;    /* XOR polynomial into CRC */ 
 
      } else { 
 
        crc_30 <<= 1;                   /* Left shift CRC          */ 
 
      } 
 
      data <<= 1;                       /* Left shift data         */ 
    } 
  } 
 
  crc_30 = ~crc_30;                     /* 1's complement the CRC     */ 
 
  return( crc_30 & 0x3FFFFFFF );        /* mask the result to 30 bits */ 
 
} /* end of crc_30_calc */ 
 
 
#ifdef SAMSUNG 
// Samsung nand flash 
int Bad_Block_Check(ulong block) 
{ 
  ulong page_address, status, spare_byte; 
  ulong page_no =0; 
  int block_size_shift; 
  ushort no_of_shifts = 1; 
  ushort no_pages_to_check; 
 
  block_size_shift = PAGE_CNT; 
  while( block_size_shift != 2 ) 
  { 
    block_size_shift = block_size_shift >> 1; 
    no_of_shifts++; 
  } 
 
  /* Set the first page number */ 
  page_no = block << no_of_shifts; 
 
  /* Check the first two pages of the samsung block */ 
  for( no_pages_to_check=0; no_pages_to_check < 2 ; no_pages_to_check++ ) 
  { 
 
    /* Read the 6th spare byte */ 
    page_address = (page_no << 9) + 5; 
 
	*ale_reg = page_address; 
	*cle_reg = READ_FLAG; 
 
	while(*status_reg & READ_FLAG) ; 
		 
	status = *status_reg; 
	 
	if(status & FS_NAND_OP_ERR_MASK) 
		return 0;		 
		 
	spare_byte = *spare_data_reg; 
 
	*AutoKick_reg = 1; 
	*AutoKick_reg = 0; 
 
    if( (spare_byte & 0xFF ) != 0xFF ) 
    { 
      return 0; 
    } 
 
    /* Check the second page in the block */ 
    page_no++; 
 
  } 
 
  /* After the spare byte is read the nand device needs to be 
     reset before any other operation is performed */ 
 
  /* Software reset the controller. */ 
  *cle_reg = RESET_CTRL; 
 
  /* Reset NAND flash memory */ 
  *cle_reg = RESET_CMD; 
 
  /* Configure NAND flash */ 
  *flash_cfg_reg = FS_NAND_CNFG_VAL; 
 
  /* Wait for completion. */ 
  while(*status_reg & PROGRAM_CMD) 
    ; 
 
  /* Do a id check. */ 
  *cle_reg = ID_CMD; 
 
  /* Wait for completion. */ 
  while(*status_reg & ID_CMD) 
    ; 
 
  return 1; 
 
} /* End of samsung_nand_bad_block_check */  
#endif 
 
 
#ifdef TOSHIBA 
int Bad_Block_Check(ulong block) 
{ 
 
  int i; 
  ulong page_address, status, page_no, first_page_no; 
  ulong sram_buffer=0x0; 
  int block_size_shift; 
  ushort no_of_shifts = 1; 
  int block_size=PAGE_CNT; 
  int page_size=PAGE_SIZE; 
  ulong ecc; 
 
  block_size_shift=PAGE_CNT; 
  while ( block_size_shift != 2 ) 
  { 
    block_size_shift = block_size_shift >> 1; 
    no_of_shifts++; 
  } 
 
  /*Reset sram memory */ 
  for (i = 0; i < page_size/4; i++) 
  	*(data_reg + i) = 0; 
 
  /* Set the first page number */ 
  first_page_no = block << no_of_shifts; 
 
  for (  page_no = first_page_no ; page_no < first_page_no+block_size ; page_no++ ) 
  { 
    page_address = page_no << 9; 
 
    *ale_reg = page_address; 
 
    *cle_reg = READ_DATA; 
 
    status = *status_reg; 
 
    while ( status & READ_DATA != 0) 
    { 
      status = *status_reg; 
    } 
 
    status = *status_reg; 
    if ( (status & FS_NAND_OP_ERR_MASK != 0) || 
         (status & FS_NAND_ECC_SELF_ERR_MASK != 0) ||  
         (status & FS_NAND_READ_ECC_ERR_MASK != 0) ) 
    { 
      return 0; 
    } 
 
    /* TESTING ecc malfunction !!*/ 
    ecc = *ecc_read_reg;    
    if ( ((ecc & FS_NAND_READ_ECC_ERR_MASK)  != 0) || ((ecc & FS_NAND_ECC_UC_ERR_MASK) != 0 )) 
    { 
      /*printf("fs_nand_common_fnc: fs_nand_read_page - error bad ecc 0: 0x%08x", ecc);*/ 
	  status = *status_reg; 
      if ( (status & FS_NAND_OP_ERR_MASK != 0) || 
           (status & FS_NAND_ECC_SELF_ERR_MASK != 0) ||  
           (status & FS_NAND_READ_ECC_ERR_MASK != 0) ) 
      { 
        /* printf("ecc was bad and status was also bad\n");*/ 
      } 
    } 
 
    /* Reading the sram buffer in chunks of 4 bytes */ 
    for (i = 0; i < page_size/4; i++) 
    { 
      sram_buffer = *(data_reg + i); 
      if ( (sram_buffer & 0xFFFFFFFF ) != 0xFFFFFFFF ) 
        return 0; 
      sram_buffer=0x0; 
    } 
 
  }  
 
  return 1; 
 
} /* End of toshiba_nand_bad_block_check */ 
 
#endif