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

📄 nand_flash.c

📁 freescale atk source code
💻 C
字号:
/*****************************************************************************
** nand_flash.c
**
** Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
**
** This file contains copyrighted material. Use of this file is
** restricted by the provisions of a Freescale Software License
** Agreement, which has either been electronically accepted by
** you or has been expressly executed between the parties.
**
** Description: Explanation for the usage of this file.
**
** Revision History:
** -----------------
*****************************************************************************/
#include "nand_flash.h"
#include "protocol.h"
#include "flash_lib.h"
#include "nfc_base.h"

/* global nand device 
 * handle
 */ 
nand_t* nand = NULL;

/* indication for bbt enable 
 * or not, define in the main.c
 * host will send command to 
 * set this flag  
 */ 
extern FL_BBT_FLAG flag_fl_bbt;

/* extern global nand  
 * device handle, define 
 * in the nand_ids.c 
 */ 
extern nand_t nand_type[];

/* indication for the follow
 * up operation or not.defined
 * in the main.c file.  
 * host will send command to 
 * set this flag  
 */ 
extern u8 go_on;

/* store the number of bad  
 * block met during operaton.
 * will use this value to adjust
 * the following up opeartion(read/prg) 
 * start end addr  
 */ 
static u32 bb_skip;

/* store the number of bad  
 * block met during operaton.
 * will use this value to adjust
 * the following up opeartion(compare) 
 * start end addr  
 */ 
static u32 cmp_block;

 /*!
 * Function to erase all blocks
 * @param	[out] addr - address
 */
static void adjust_addr(u32 *block)
{
	
	/*reset the bb_skip */
	if(go_on == 0) 
		bb_skip = 0;
	
	/* FIXME recount the start block 
	*  May meet bad block during last 
	*  programing, should ajust the
	*  following up programing start addr	
	*/	
	*block += bb_skip;
}

/*!
 * Function to read nand flash id
 * @param	[out] man_id - manufacture id
 * @param	[out] dev_id - device id
 */
void nand_read_id(u8 *man_id, u8 *dev_id)
{
	u32 tmp;
	nfc_send_read_id(&tmp);
	
	/* read the id */
	*man_id = (u8)tmp;
	*dev_id = (u8)(tmp>>8);
}

 /*!
 * Function to initialize nand
 * @param	none 
 */
s16 nand_init(void)
{
 	u8 man_id,dev_id;
 	u32 i;
  	
  	if(!nand) {
		nfc_base_init();
   		nand_read_id(&man_id, &dev_id);
   		for(i=0;nand_type[i].man_id !=0;i++) {
   			if( nand_type[i].man_id == man_id && nand_type[i].dev_id == dev_id ) {
     			nand = nand_type + i;
     			nfc_set_fms(nand->bus_width, nand->page_size, nand->oob_size);
    			break;
   			}
   		}
   	}
   	
   	if(nand) {
		if(flag_fl_bbt != FL_BBT_ENABLE) {
			return FLASH_ERROR_NO;
		} else {
			if(nand->bbt) {
				return FLASH_ERROR_NO;
			} else {
				// for 4G nand same layout with redboot and linux driver
				if((nand->page_size == 4096) && (nand->blk_count == 8192))
					nand->blk_count >>= 1;
				nand->bbt = malloc(nand->blk_count >> 2);
				if (nand->bbt) {
					memset(nand->bbt,0,nand->blk_count >> 2);
					if (nand_scan_bbt(nand) == 0 ) {
						return FLASH_ERROR_NO;
					}
				}
			}	
		} 
	}

	return FLASH_ERROR_INIT;
	
}

 /*!
 * Function to erase all blocks
 * @param	[in] addr - address
 * @param	[in] size - size
 */

s32 check_param(u32 addr, u32 size)
{
	u32 page_size = nand->page_size;
	u32 ppb = nand->ppb;
	u32 blk_size = page_size * ppb;
	u32 blk_count = nand->blk_count;
	
	if ( (addr / blk_size) > blk_count || size == 0 || ((addr + size) / blk_size) > blk_count )
		return FLASH_ERROR_OVER_ADDR;
	return 0;
}
 
//u32 atk_channel_send(const u8 *buf, u32 count);
 /*!
 * Function to read data from nand flash 
 * @param	[in] src - nand flash address
 * @param	[in] dest - destination address
 * @param	[in] len - byte size to be read
 * @param   	[in] callback - call back function to send data & progress
 */
s16 nand_read(u32 src, u32 dest, u32 len,dump_callback callback)
{

	s16 ret;
	u16 csum;
	u32 page_size = nand->page_size;
	u32 ppb = nand->ppb;
	u32 blk_count = nand->blk_count;
	u32 blk_size = page_size * ppb;
	u32 block = src / blk_size;
	u32 page  = (src % blk_size) / page_size;
	u32 offset = src % page_size;
	u32 readlen = 0;
	
	/* FIXME,adjust the start
	 * block address due to 
	 * the bad block meet in 
	 * pre-read phase	 	 
	 */
	adjust_addr(&block);
	
	/* param check */
	ret = check_param(src,len);
	if (0 != ret)
		return ret;
		
	do {
     		if (page >= ppb) {
       			block++;
       			page = 0;
     		}
     		/* check bad block first*/
		if ( page == 0) {
			if(!is_good_block(nand,block,0)){
				block++;
				bb_skip++;
         			continue;
       			}
     		} 
     		/* check the offset */
		if(offset == 0)
			readlen = min(len, page_size);
		else
		 	readlen = ((len + offset) > page_size) ? page_size - offset : len;
		 	
		/* read the page */
		ret = nand_read_page(block, page, dest, readlen, offset);
		
		if (FLASH_ERROR_NO != ret)
			return ret;
			
		/* send the dump status and data to host */
		if (callback != NULL) {
			csum = calculate_checksum((u8 *)dest, readlen);
			callback((u8 *)dest, FLASH_PARTLY, csum, readlen);
		}
		
		/* update the value */
		len -= readlen;
		dest += readlen;
		page++;
		offset = 0;
	} while (len && block < blk_count);
   
	/* check the blknum */
	if(block >= blk_count )
		ret = FLASH_ERROR_EOF;
		
	return ret;
}

 /*!
 * Function to Write data to nand flash
 * @param	[in] dest - nand flash address
 * @param	[in] src - data buffer address
 * @param	[in] len - byte to be written
 * @param   	[in] callback the call back function to notify the progress
 */
s16 nand_write(u32 dest, u32 src, u32 len, u8 file_format, response_callback callback)
{
	s16 ret;
	u32 page_size = nand->page_size;
	u32 ppb = nand->ppb;
	u32 blk_count = nand->blk_count;
	u32 blk_size = page_size * ppb;
	u32 block = dest/blk_size;
	u32 page  = 0;
	u32 writelen = 0;
	
	/* FIXME,adjust the start
	 * block address due to 
	 * the bad block meet in 
	 * pre-prog phase	 	 
	 */
	adjust_addr(&block);
	cmp_block = block;
		
	/* param check */
	ret = check_param(dest,len);
	if (0 != ret)
		return ret;
		
	do {
	
		if (page >= ppb) {
			block++;
			page = 0;
		}
		
		if (0 == page) {
			/* check bad block first*/
    			if(!is_good_block(nand, block,0)) {
         			block++;
         			bb_skip++;
         			continue;
       			}
       			/* erase the block */
			if (nand_erase_block(block) != FLASH_ERROR_NO) {
           			mark_bad_block(nand,block);
           			block++;
           			bb_skip++;
           			continue;
        		}
		}
		
		/* write the page */
		writelen = min(len, page_size);
		ret = nand_write_page(block, page, src, writelen,file_format);
		
		/* if ECC error */
		if (FLASH_ERROR_ECC == ret ) {
        		mark_bad_block(nand, block);
        		block++;
			bb_skip++;                        
        		page = 0;
         		continue;
     		}
		
     		/* if PROG error */
		if (FLASH_ERROR_PROG == ret) 
			return ret;
		
		/* send the prg status to host */
		if(callback != NULL)
			callback(FLASH_PARTLY, block, writelen);
		
		/* update the value */
		len -= writelen;
		src += writelen;
		page++;
	} while (len && block < blk_count);
	
	/* check the blknum */
	if(block >= blk_count )
		ret = FLASH_ERROR_EOF;
		
	return ret;
}

 /*!
 * Function to compare the content between source and dest
 * @param	[in] src - nand flash address
 * @param	[in] dest - target address
 * @param	[in] len - length to be compared
 * @param   	[in] callback - the call back function to notify the progress
 */
s16 nand_compare(u32 src, u32 dest, u32 len,response_callback callback)
{

	u32 page_size = nand->page_size;
	u32 ppb = nand->ppb;
	u32 blk_count = nand->blk_count;
	u32 blk_size = page_size * ppb;
	u32 block = src/blk_size;
	u32 page  = 0;
	u32 readlen;
	s16 ret;
	
	/* FIXME,adjust the start
	 * block address of compare
	 * to the most recently prog
	 * start block	 	 	 
	 */
	block = cmp_block;
		
	do {
		if (page >= ppb) {
       			block++;
       			page = 0;
     		}
		if (page == 0) {
			if(!is_good_block(nand, block, 0)) {
				block++;
         			continue;
       			}
		}
		/* set the read size */
		readlen = min(len, page_size);

		/* compare the page */
		ret = nand_compare_page(block, page, dest, readlen);
		
		if (FLASH_ERROR_NO != ret)
			return ret;
			
		/* send the verify status to host */
		if(callback != NULL)
			callback(FLASH_VERIFY, block, readlen);

		/* update the value */
     		len -= readlen;
     		dest += readlen;
     		page++;
   	} while (len && block < blk_count);
   	
	/* check the blknum */
	if(block >= blk_count )
		ret = FLASH_ERROR_EOF;
		
   	return ret;
}

 /*!
 * Function to erase flash content between start address and endadress
 * @param 	[in] start - start address to be erased
 * @param	[in] end - end address to be erased
 */
s16 nand_erase_conditional(u32 start, u32 end,response_callback callback)
{

	s16 ret;
	u32 i,j,k;
	u32 page_size = nand->page_size;
	u32 ppb = nand->ppb;
	u32 blk_count = nand->blk_count;
	u32 blk_size = page_size * ppb;

	/* param check */
	ret = check_param(start,end - start);
	if (0 != ret)
		return ret;

	i = start / blk_size;
	k = (end - 1) / blk_size;
	j = 0;
	for(; i<= k; i++) {
		//if (is_good_block(nand, i, 0)) 
		{
       		ret = nand_erase_block(i);
       		if(FLASH_ERROR_NO != ret) {
       			j++;
       		} else {
       			if(callback)
         				callback(FLASH_ERASE, i, blk_size);
       		}
     	}
   	}
	/*FIX ME ,This is for the Linux bbt upate*/
	if ((k >= blk_count -4) && (nand->bbt)) {
		free(nand->bbt);
		nand->bbt = NULL;
		nand_init();
	}
	
   	/*partial erease*/
   	if (j > 0)
   		return FLASH_ERROR_PART_ERASE;

   	return ret;
}

 /*!
 * Function to check bad block
 * @param 	[in] nd - nand structure
 * @param	[in] nrblk - number of blocks
 * @param	[in] allowbbt - allow write bbt or not
 */
u8 is_good_block(nand_t* nd, u32 nrblk,int allowbbt)
{
	if(flag_fl_bbt == FL_BBT_ENABLE) {
		return (!nand_isbad_bbt(nd,nrblk,allowbbt));
	} else {
		return (nand_block_is_good(nrblk));
	}
	
}

 /*!
 * Function to mark bad block
 * @param 	[in] nd - nand structure
 * @param	[in] nrblk - number of blocks
 */
s16 mark_bad_block(nand_t *nd,u32 nrblk)
{
	if(flag_fl_bbt == FL_BBT_ENABLE) {
		return (nand_bbt_markbad(nd,nrblk));
	} else {
		return (nand_mark_bad_block(nrblk));
	}
}

⌨️ 快捷键说明

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