mirror of
https://github.com/linux-sunxi/u-boot-sunxi.git
synced 2024-02-12 11:16:03 +08:00
1315 lines
29 KiB
C
Executable File
1315 lines
29 KiB
C
Executable File
#include <common.h>
|
||
#include <malloc.h>
|
||
#include "nand_bsp.h"
|
||
|
||
#define OOB_BUF_SIZE 32
|
||
#define NAND_BOOT0_BLK_START 0
|
||
#define NAND_BOOT0_BLK_CNT 2
|
||
#define NAND_UBOOT_BLK_START (NAND_BOOT0_BLK_START+NAND_BOOT0_BLK_CNT)
|
||
#define NAND_UBOOT_BLK_CNT 5
|
||
#define NAND_BOOT0_PAGE_CNT_PER_COPY 64
|
||
|
||
static char nand_para_store[256];
|
||
|
||
int msg(const char * str, ...)
|
||
{
|
||
NAND_Print(str);
|
||
}
|
||
|
||
|
||
int NAND_PhyInit(void)
|
||
{
|
||
int ret;
|
||
|
||
debug("PHY_Init\n");
|
||
ret = PHY_Init();
|
||
if (ret)
|
||
{
|
||
printf("NB1 : nand phy init fail\n");
|
||
return ret;
|
||
}
|
||
|
||
debug("SCN_AnalyzeNandSystem\n");
|
||
ret = SCN_AnalyzeNandSystem();
|
||
if (ret)
|
||
{
|
||
printf("NB1 : nand scan fail\n");
|
||
return ret;
|
||
}
|
||
//modify ValidBlkRatio
|
||
//NAND_SetValidBlkRatio(nand_good_blk_ratio);
|
||
|
||
debug("NB1 : nand phy init ok\n");
|
||
return(PHY_ChangeMode(1));
|
||
}
|
||
|
||
|
||
int NAND_PhyExit(void)
|
||
{
|
||
debug("PHY_Exit\n");
|
||
|
||
PHY_Exit();
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
int NAND_LogicWrite(uint nSectNum, uint nSectorCnt, void * pBuf)
|
||
{
|
||
#ifdef NAND_CACHE_OPEN
|
||
return (NAND_CacheWrite(nSectNum, nSectorCnt, pBuf));
|
||
#else
|
||
return (LML_Write(nSectNum, nSectorCnt, pBuf));
|
||
#endif
|
||
}
|
||
|
||
|
||
int NAND_LogicRead(uint nSectNum, uint nSectorCnt, void * pBuf)
|
||
{
|
||
#ifdef NAND_CACHE_OPEN
|
||
return NAND_CacheRead(nSectNum,nSectorCnt,pBuf);
|
||
#else
|
||
return LML_Read(nSectNum,nSectorCnt,pBuf);
|
||
#endif
|
||
|
||
}
|
||
|
||
|
||
int NAND_LogicInit(void)
|
||
{
|
||
int result;
|
||
|
||
debug("NB1 : enter NFB_Init\n");
|
||
|
||
//Format nand flash for logical access
|
||
result = FMT_Init();
|
||
if(result < 0)
|
||
{
|
||
printf("NB1 : format init fail\n");
|
||
return -5;
|
||
}
|
||
|
||
result = FMT_FormatNand();
|
||
if(result < 0)
|
||
{
|
||
printf("NB1 : format fail\n");
|
||
return -6;
|
||
}
|
||
|
||
result = FMT_Exit();
|
||
if(result < 0)
|
||
{
|
||
return -7;
|
||
}
|
||
|
||
//Init nand flash logical module
|
||
result = LML_Init();
|
||
if(result < 0)
|
||
{
|
||
return -8;
|
||
}
|
||
#ifdef NAND_CACHE_OPEN
|
||
result = NAND_CacheOpen();
|
||
#endif
|
||
|
||
return result;
|
||
}
|
||
|
||
|
||
int NAND_LogicExit(void)
|
||
{
|
||
int result;
|
||
|
||
#ifdef NAND_CACHE_OPEN
|
||
NAND_CacheClose();
|
||
#endif
|
||
|
||
//exit nand flahs logic module
|
||
result = LML_Exit();
|
||
if(result < 0)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
//exit nand flash physical module
|
||
//result = NAND_PhyExit();
|
||
//if(result < 0)
|
||
//{
|
||
// return -2;
|
||
//}
|
||
return result;
|
||
}
|
||
|
||
|
||
uint max_badblk(uint v0, uint v1)
|
||
{
|
||
uint val;
|
||
|
||
if(v0 > v1)
|
||
val = v0;
|
||
else
|
||
val = v1;
|
||
|
||
return val;
|
||
}
|
||
|
||
int cal_real_chip(uint global_bank, uint chip_connect_info)
|
||
{
|
||
uint chip;
|
||
uint i,cnt;
|
||
|
||
cnt = 0;
|
||
chip = global_bank;
|
||
|
||
for (i = 0; i < 8; i++ )
|
||
{
|
||
if (chip_connect_info & (1 << i))
|
||
{
|
||
cnt++;
|
||
if (cnt == (chip+1))
|
||
{
|
||
chip = i;
|
||
return chip;
|
||
}
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
|
||
int mark_bad_block( uint chip_num, uint blk_num)
|
||
{
|
||
unsigned char oob_buf[OOB_BUF_SIZE];
|
||
unsigned char* page_buf;
|
||
int page_index[4];
|
||
uint page_with_bad_block, page_per_block;
|
||
uint i;
|
||
int mark_err_flag = -1;
|
||
struct boot_physical_param para;
|
||
|
||
|
||
//cal nand parameters
|
||
//page_buf = (unsigned char*)(MARK_BAD_BLK_BUF_ADR);
|
||
page_buf = (unsigned char*)malloc(32 * 1024);
|
||
if(!page_buf)
|
||
{
|
||
printf("malloc memory for page buf fail\n");
|
||
return -1;
|
||
}
|
||
|
||
page_with_bad_block = NAND_GetBadBlockFlagPos();
|
||
page_per_block = NAND_GetPageCntPerBlk();
|
||
page_index[0] = 0;
|
||
page_index[1] = 0xEE;
|
||
page_index[2] = 0xEE;
|
||
page_index[3] = 0xEE;
|
||
|
||
switch(page_with_bad_block & 0x03)
|
||
{
|
||
case 0x00:
|
||
//the bad block flag is in the first page, same as the logical information, just read 1 page is ok
|
||
break;
|
||
|
||
case 0x01:
|
||
//the bad block flag is in the first page or the second page, need read the first page and the second page
|
||
page_index[1] = 1;
|
||
break;
|
||
|
||
case 0x02:
|
||
//the bad block flag is in the last page, need read the first page and the last page
|
||
page_index[1] = page_per_block - 1;
|
||
break;
|
||
|
||
case 0x03:
|
||
//the bad block flag is in the last 2 page, so, need read the first page, the last page and the last-1 page
|
||
page_index[1] = page_per_block - 1;
|
||
page_index[2] = page_per_block - 2;
|
||
break;
|
||
}
|
||
|
||
for(i =0; i<4; i++)
|
||
{
|
||
oob_buf[0] = 0x0;
|
||
oob_buf[1] = 0x1;
|
||
oob_buf[2] = 0x2;
|
||
oob_buf[3] = 0x3;
|
||
oob_buf[4] = 0x89;
|
||
oob_buf[5] = 0xab;
|
||
oob_buf[6] = 0xcd;
|
||
oob_buf[7] = 0xef;
|
||
|
||
para.chip = chip_num;
|
||
para.block = blk_num;
|
||
para.page = page_index[i];
|
||
para.mainbuf = page_buf;
|
||
para.oobbuf = oob_buf;
|
||
|
||
if(para.page == 0xEE)
|
||
continue;
|
||
|
||
PHY_SimpleWrite( ¶ );
|
||
PHY_SimpleRead( ¶ );
|
||
|
||
if(oob_buf[0] !=0xff)
|
||
mark_err_flag = 0;
|
||
}
|
||
|
||
free(page_buf);
|
||
|
||
return mark_err_flag;
|
||
}
|
||
|
||
|
||
|
||
int NAND_VersionCheck(void)
|
||
{
|
||
struct boot_physical_param boot0_readop_temp;
|
||
struct boot_physical_param *boot0_readop = NULL;
|
||
uint block_index;
|
||
uint cnt1;
|
||
int version_match_flag = -1;
|
||
//uint chip_type;
|
||
int i;
|
||
unsigned char oob_buf[32];
|
||
uint* main_data;
|
||
unsigned char nand_version[4];
|
||
uint nand_version_value;
|
||
|
||
/********************************************************************************
|
||
* nand_version[2] = 0xFF; //the sequnece mode version <
|
||
* nand_version[2] = 0x01; //the first interleave mode version, care ecc
|
||
* 2010-06-05
|
||
* nand_version[2] = 0x02; //the current version, don't care ecc
|
||
* 2010-07-13
|
||
* NOTE: need update the nand version in update_boot0 at the same time
|
||
********************************************************************************/
|
||
NAND_GetVersion(nand_version);
|
||
|
||
|
||
printf("check nand version start.\n");
|
||
printf("Current nand driver version is 0x%x \n", *((__u32 *)(nand_version)));
|
||
|
||
boot0_readop = &boot0_readop_temp;
|
||
//printf("boot0_readop addr: 0x%x\n", (__u32)boot0_readop);
|
||
|
||
//init boot0_readop
|
||
boot0_readop->block = 0x0;
|
||
boot0_readop->chip = 0;
|
||
boot0_readop->mainbuf = (void*)malloc(32 * 1024);
|
||
//printf("%s %d boot0_readop addr: 0x%x, mainbuf: 0x%x\n", __FILE__, __LINE__, (__u32)boot0_readop, (__u32)boot0_readop->mainbuf);
|
||
if(!boot0_readop->mainbuf)
|
||
{
|
||
printf("malloc memory for boot0 read operation fail\n");
|
||
return -1;
|
||
}
|
||
|
||
boot0_readop->oobbuf = oob_buf;
|
||
boot0_readop->page = 0;
|
||
boot0_readop->sectorbitmap = 0;
|
||
|
||
main_data = boot0_readop->mainbuf;
|
||
|
||
//scan boot0 area blocks
|
||
for(block_index=0;block_index<1 + 1;block_index++)
|
||
{
|
||
|
||
boot0_readop->block = block_index;
|
||
boot0_readop->page = 0;
|
||
cnt1 = 0;
|
||
|
||
//printf("%s %d mainbuf: 0x%x\n", __FILE__, __LINE__, (__u32)boot0_readop->mainbuf);
|
||
PHY_SimpleRead_1K(boot0_readop);
|
||
|
||
//check the current block is a bad block
|
||
if(oob_buf[0] != 0xFF)
|
||
{
|
||
printf("block %u is bad block.\n",block_index);
|
||
continue;
|
||
}
|
||
|
||
|
||
//check the current block is a all 0xFF block
|
||
for(i=0; i<256; i++)
|
||
{
|
||
if(*(main_data+i) == 0xffffffff)
|
||
cnt1++;
|
||
}
|
||
|
||
if(cnt1 == 256)
|
||
{
|
||
printf("block %u is cleared block.\n",block_index);
|
||
continue;
|
||
}
|
||
|
||
if((oob_buf[1] == 0x00) || (oob_buf[1] == 0xFF))
|
||
{
|
||
printf("Media version is valid in block %u, version info is 0x%x \n", block_index, *((__u32 *)(oob_buf)));
|
||
if(oob_buf[2] == nand_version[2])
|
||
{
|
||
printf("nand driver version match ok in block %u.\n",block_index);
|
||
version_match_flag = 0;
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
printf("nand driver version match fail in block %u.\n",block_index);
|
||
version_match_flag = 1;
|
||
break;
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
printf("Media version is invalid in block %u version info is %x \n", block_index, *((__u32 *)(oob_buf)));
|
||
}
|
||
|
||
}
|
||
|
||
if(block_index == (1 + 1))
|
||
{
|
||
printf("can't find valid version info in boot blocks. \n");
|
||
version_match_flag = -1;
|
||
}
|
||
|
||
free(main_data);
|
||
return version_match_flag;
|
||
}
|
||
|
||
|
||
int NAND_EraseBootBlocks(void)
|
||
{
|
||
|
||
struct boot_physical_param para;
|
||
int i;
|
||
int ret;
|
||
|
||
printf("Ready to erase boot blocks.\n");
|
||
|
||
for( i = 0; i < 7; i++ )
|
||
{
|
||
para.chip = 0;
|
||
para.block = i;
|
||
ret = PHY_SimpleErase( ¶ ) ;
|
||
if(ret)
|
||
printf("erasing block %u failed.\n", i );
|
||
}
|
||
|
||
printf("has cleared the boot blocks.\n");
|
||
|
||
return 0;
|
||
|
||
}
|
||
|
||
|
||
int NAND_EraseChip(void)
|
||
{
|
||
struct boot_physical_param para_read;
|
||
int i,j,k,m;
|
||
int ret;
|
||
int cnt0, cnt1;
|
||
int mark_err_flag;
|
||
uint bad_block_flag;
|
||
uint chip_cnt, chip_connect, page_size, page_per_block, blk_cnt_per_chip;
|
||
int page_index[4];
|
||
uint chip;
|
||
unsigned char oob_buf_read[OOB_BUF_SIZE];
|
||
unsigned char* page_buf_read;
|
||
int error_flag = 0;
|
||
|
||
page_buf_read = (unsigned char*)malloc(32 * 1024);
|
||
if(!page_buf_read)
|
||
{
|
||
printf("malloc memory for page read fail\n");
|
||
return -1;
|
||
}
|
||
printf("Ready to erase chip.\n");
|
||
// get nand info to cal
|
||
printf("nfb phy init ok.\n");
|
||
|
||
|
||
page_size = NAND_GetPageSize();
|
||
page_per_block = NAND_GetPageCntPerBlk();
|
||
blk_cnt_per_chip = NAND_GetBlkCntPerChip();
|
||
chip_cnt = NAND_GetChipCnt();
|
||
debug("chip_cnt=%d\n", chip_cnt);
|
||
chip_connect = NAND_GetChipConnect();
|
||
debug("chip_cnt = %x, chip_connect = %x\n",chip_cnt,chip_connect);
|
||
|
||
page_index[0] = 0;
|
||
page_index[1] = 1;
|
||
page_index[2] = page_per_block - 2;
|
||
page_index[0] = page_per_block - 1;
|
||
|
||
|
||
for( i = 0; i < chip_cnt; i++ )
|
||
{
|
||
//select chip
|
||
chip = cal_real_chip( i, chip_connect );
|
||
printf("erase chip %u \n", chip);
|
||
|
||
//scan for bad blocks, only erase good block, all 0x00 blocks is defined bad blocks
|
||
for( j = 0; j < blk_cnt_per_chip; j++ )
|
||
{
|
||
|
||
if(j%0x100==0)
|
||
printf("erase block %u\n", j);
|
||
para_read.chip = chip;
|
||
para_read.block = j;
|
||
para_read.mainbuf = page_buf_read;
|
||
para_read.oobbuf = oob_buf_read;
|
||
|
||
bad_block_flag = 0;
|
||
|
||
for(k = 0; k<4; k++)
|
||
{
|
||
cnt0 =0;
|
||
cnt1 =0;
|
||
para_read.page = page_index[k];
|
||
if( para_read.page== 0xEE)
|
||
break;
|
||
|
||
ret = PHY_SimpleRead_2CH(& para_read );
|
||
|
||
//check the current block is a all 0x00 block
|
||
|
||
for(m=0; m<8; m++) //check user data, 8 byte
|
||
{
|
||
if(oob_buf_read[m] == ((unsigned char)0x0) )
|
||
cnt1++;
|
||
else
|
||
break;
|
||
}
|
||
for(m=0; m<page_size; m++) //check main data
|
||
{
|
||
if(page_buf_read[m] == ((unsigned char)0x0) )
|
||
cnt0++;
|
||
else
|
||
break;
|
||
}
|
||
|
||
if((cnt0 == page_size)&&(cnt1 == 8))
|
||
{
|
||
bad_block_flag = 1;
|
||
printf("find a all 0x00 block %u\n", j);
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
if(bad_block_flag)
|
||
continue;
|
||
|
||
ret = PHY_SimpleErase_2CH( ¶_read );
|
||
if( ret != 0 )
|
||
{
|
||
printf("erasing block %u failed.\n", j );
|
||
mark_err_flag = mark_bad_block( i, j );
|
||
if( mark_err_flag!= 0 )
|
||
{
|
||
error_flag++;
|
||
printf("error in marking bad block flag in chip %u, block %u, mark error flag %u.\n", i, j, mark_err_flag);
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
printf("has cleared the chip.\n");
|
||
if(error_flag)
|
||
printf("the nand is Bad.\n");
|
||
else
|
||
printf("the nand is OK.\n");
|
||
|
||
free(page_buf_read);
|
||
|
||
return 0;
|
||
|
||
}
|
||
|
||
|
||
int NAND_BadBlockScan(void)
|
||
{
|
||
int i, j, k;
|
||
uint page_with_bad_block, page_per_block, block_cnt_per_chip, chip_cnt, chip_connect_mode;
|
||
int page_index[4];
|
||
uint bad_block_cnt[8];
|
||
uint bad_block_num = 0;
|
||
uint good_block_num = 0;
|
||
int good_block_ratio = -1, default_good_block_ratio =-1;
|
||
uint chip;
|
||
unsigned char oob_buf[OOB_BUF_SIZE];
|
||
unsigned char* page_buf;
|
||
struct boot_physical_param para;
|
||
|
||
for(i=0; i<8; i++)
|
||
bad_block_cnt[i] = 0;
|
||
|
||
debug("Ready to scan bad blocks.\n");
|
||
|
||
//cal nand parameters
|
||
//page_buf = (unsigned char*)(BAD_BLK_SCAN_BUF_ADR);
|
||
page_buf = (unsigned char*)malloc(32 * 1024);
|
||
if(!page_buf)
|
||
{
|
||
printf("malloc memory for page buf fail\n");
|
||
return -1;
|
||
}
|
||
|
||
page_with_bad_block = NAND_GetBadBlockFlagPos();
|
||
page_per_block = NAND_GetPageCntPerBlk();
|
||
block_cnt_per_chip = NAND_GetBlkCntPerChip();
|
||
chip_cnt = NAND_GetChipCnt();
|
||
chip_connect_mode = NAND_GetChipConnect();
|
||
default_good_block_ratio = NAND_GetValidBlkRatio();
|
||
|
||
|
||
//read the first, second, last, last-1 page for check bad blocks
|
||
page_index[0] = 0;
|
||
page_index[1] = 0xEE;
|
||
page_index[2] = 0xEE;
|
||
page_index[3] = 0xEE;
|
||
|
||
switch(page_with_bad_block & 0x03)
|
||
{
|
||
case 0x00:
|
||
//the bad block flag is in the first page, same as the logical information, just read 1 page is ok
|
||
break;
|
||
|
||
case 0x01:
|
||
//the bad block flag is in the first page or the second page, need read the first page and the second page
|
||
page_index[1] = 1;
|
||
break;
|
||
|
||
case 0x02:
|
||
//the bad block flag is in the last page, need read the first page and the last page
|
||
page_index[1] = page_per_block - 1;
|
||
break;
|
||
|
||
case 0x03:
|
||
//the bad block flag is in the last 2 page, so, need read the first page, the last page and the last-1 page
|
||
page_index[1] = page_per_block - 1;
|
||
page_index[2] = page_per_block - 2;
|
||
break;
|
||
}
|
||
|
||
//scan bad blocks
|
||
for( i = 0; i < chip_cnt; i++ ){
|
||
|
||
chip = cal_real_chip( i, chip_connect_mode );
|
||
printf("scan CE %u\n", chip);
|
||
bad_block_cnt[chip] = 0;
|
||
|
||
for( j = 0; j < block_cnt_per_chip; j++ )
|
||
{
|
||
para.chip = chip;
|
||
para.block = j;
|
||
para.mainbuf = page_buf;
|
||
para.oobbuf = oob_buf;
|
||
|
||
for(k = 0; k<4; k++)
|
||
{
|
||
// read pages for check
|
||
para.page = page_index[k];
|
||
if(para.page == 0xEE)
|
||
continue;
|
||
PHY_SimpleRead_2CH(¶ );
|
||
|
||
// find bad blocks
|
||
if(oob_buf[0] != 0xff)
|
||
{
|
||
printf("find defined bad block in chip %u, block %u.\n", i, j);
|
||
bad_block_cnt[chip]++;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// cal bad block num
|
||
if(chip_cnt == 0x1) //for one CE
|
||
{
|
||
if(chip_connect_mode == 0x1)
|
||
{
|
||
bad_block_num = bad_block_cnt[0]<<1;
|
||
}
|
||
else
|
||
{
|
||
printf("chip connect parameter %x error \n", chip_connect_mode);
|
||
free(page_buf);
|
||
|
||
return -1;
|
||
}
|
||
}
|
||
else if(chip_cnt == 2) //for two CE
|
||
{
|
||
if(chip_connect_mode == 0x3)
|
||
{
|
||
bad_block_num = (bad_block_cnt[0] + bad_block_cnt[1])<<1;
|
||
}
|
||
else if(chip_connect_mode == 0x5)
|
||
{
|
||
bad_block_num = (bad_block_cnt[0] + bad_block_cnt[2])<<1;
|
||
}
|
||
else if(chip_connect_mode == 0x81)
|
||
{
|
||
bad_block_num = (bad_block_cnt[0] + bad_block_cnt[7])<<1;
|
||
}
|
||
else
|
||
{
|
||
printf("chip connect parameter %x error \n", chip_connect_mode);
|
||
free(page_buf);
|
||
|
||
return -1;
|
||
}
|
||
}
|
||
else if(chip_cnt == 4) //for four CE
|
||
{
|
||
if(chip_connect_mode == 0xf)
|
||
{
|
||
bad_block_num = max_badblk((bad_block_cnt[0] + bad_block_cnt[2]),(bad_block_cnt[1] + bad_block_cnt[3]))<<1;
|
||
}
|
||
else if(chip_connect_mode == 0x55)
|
||
{
|
||
bad_block_num = max_badblk((bad_block_cnt[0] + bad_block_cnt[2]),(bad_block_cnt[4] + bad_block_cnt[6]))<<1;
|
||
}
|
||
else
|
||
{
|
||
printf("chip connect parameter %x error \n",chip_connect_mode);
|
||
free(page_buf);
|
||
|
||
return -1;
|
||
}
|
||
|
||
}
|
||
else if(chip_cnt == 8) //for eight CE
|
||
{
|
||
if(chip_connect_mode == 0xff)
|
||
{
|
||
bad_block_num = max_badblk((bad_block_cnt[0] + bad_block_cnt[2]),(bad_block_cnt[1] + bad_block_cnt[3]));
|
||
bad_block_num = 2*max_badblk(bad_block_num, max_badblk((bad_block_cnt[4] + bad_block_cnt[6]),(bad_block_cnt[5] + bad_block_cnt[7])));
|
||
|
||
}
|
||
else
|
||
{
|
||
printf("chip connect parameter %x error \n",chip_connect_mode);
|
||
free(page_buf);
|
||
|
||
return -1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
printf("chip cnt parameter %x error \n",chip_connect_mode);
|
||
free(page_buf);
|
||
|
||
return -1;
|
||
}
|
||
|
||
|
||
//cal good block num required per 1024 blocks
|
||
good_block_num = (1024*(block_cnt_per_chip - bad_block_num))/block_cnt_per_chip -50;
|
||
for(i=0; i<chip_cnt; i++)
|
||
{
|
||
chip = cal_real_chip( i, chip_connect_mode );
|
||
printf(" %d bad blocks in CE %u \n", bad_block_cnt[chip], chip);
|
||
}
|
||
printf("cal bad block num is %u \n", bad_block_num);
|
||
printf("cal good block num is %u \n", good_block_num);
|
||
|
||
//cal good block ratio
|
||
for(i=0; i<5; i++)
|
||
{
|
||
if(good_block_num >= (default_good_block_ratio - 32*i))
|
||
{
|
||
good_block_ratio = (default_good_block_ratio - 32*i);
|
||
printf("good block ratio is %u \n",good_block_ratio);
|
||
break;
|
||
}
|
||
}
|
||
free(page_buf);
|
||
|
||
return good_block_ratio;
|
||
}
|
||
|
||
|
||
int NAND_UbootInit(int boot_mode)
|
||
{
|
||
int ret = 0;
|
||
int enable_bad_block_scan_flag = 0;
|
||
uint good_block_ratio=0;
|
||
|
||
debug("NAND_UbootInit start\n");
|
||
|
||
ret = NAND_PhyInit();
|
||
|
||
debug("NAND_PhyInit end: 0x%x\n", ret);
|
||
|
||
if(!boot_mode)
|
||
{
|
||
/* scan bad blocks */
|
||
if( enable_bad_block_scan_flag)
|
||
{
|
||
good_block_ratio = NAND_BadBlockScan();
|
||
if(good_block_ratio <= 0)
|
||
{
|
||
return -1;
|
||
}
|
||
}
|
||
NAND_GetParam(nand_para_store, 256);
|
||
}
|
||
|
||
/* logic init */
|
||
ret |= NAND_LogicInit();
|
||
|
||
debug("NAND_UbootInit end: 0x%x\n", ret);
|
||
|
||
return ret;
|
||
|
||
}
|
||
|
||
|
||
int NAND_UbootExit(void)
|
||
{
|
||
int ret = 0;
|
||
|
||
debug("NAND_UbootExit \n");
|
||
|
||
ret = NAND_LogicExit();
|
||
ret |= NAND_PhyExit();
|
||
|
||
return ret;
|
||
}
|
||
|
||
|
||
|
||
uint NAND_UbootRead(uint start, uint sectors, void *buffer)
|
||
{
|
||
int ret = 0;
|
||
|
||
if(NAND_LogicRead(start, sectors, buffer))
|
||
ret = sectors;
|
||
|
||
return ret;
|
||
|
||
}
|
||
|
||
uint NAND_UbootWrite(uint start, uint sectors, void *buffer)
|
||
{
|
||
int ret = 0;
|
||
|
||
if(NAND_LogicWrite(start, sectors, buffer))
|
||
ret = sectors;
|
||
|
||
return ret;
|
||
}
|
||
|
||
int NAND_Uboot_Erase(int erase_flag)
|
||
{
|
||
int version_match_flag;
|
||
|
||
debug("erase_flag = %d\n", erase_flag);
|
||
NAND_PhyInit();
|
||
NAND_EraseBootBlocks();
|
||
if(erase_flag)
|
||
{
|
||
debug("erase by flag %d\n", erase_flag);
|
||
NAND_EraseChip();
|
||
}
|
||
else
|
||
{
|
||
version_match_flag = NAND_VersionCheck();
|
||
debug("nand version = %x\n", version_match_flag);
|
||
if (version_match_flag > 0)
|
||
{
|
||
NAND_EraseChip();
|
||
}
|
||
}
|
||
NAND_PhyExit();
|
||
|
||
return 0;
|
||
}
|
||
|
||
__s32 burn_boot0_1k_mode( __u32 read_retry_type, __u32 Boot0_buf )
|
||
{
|
||
__u32 i, j, k;
|
||
__u32 length;
|
||
__u32 pages_per_block;
|
||
__u32 copies_per_block;
|
||
__u8 oob_buf[32];
|
||
struct boot_physical_param para;
|
||
|
||
debug("burn boot0 normal mode!\n");
|
||
|
||
for(i=0;i<32;i++)
|
||
oob_buf[i] = 0xff;
|
||
|
||
NAND_GetVersion(oob_buf);
|
||
if((oob_buf[0]!=0xff)||(oob_buf[1]!= 0x00))
|
||
{
|
||
debug("get flash driver version error!");
|
||
goto error;
|
||
}
|
||
|
||
/* <20><><EFBFBD><EFBFBD> page count */
|
||
pages_per_block = NAND_GetPageCntPerBlk();
|
||
if(pages_per_block%64)
|
||
{
|
||
debug("get page cnt per block error %x!", pages_per_block);
|
||
goto error;
|
||
}
|
||
|
||
/* cal copy cnt per bock */
|
||
copies_per_block = pages_per_block / NAND_BOOT0_PAGE_CNT_PER_COPY;
|
||
|
||
/* burn boot0 copys */
|
||
for( i = NAND_BOOT0_BLK_START; i < (NAND_BOOT0_BLK_START + NAND_BOOT0_BLK_CNT); i++ )
|
||
{
|
||
debug("boot0 %x \n", i);
|
||
|
||
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||
para.chip = 0;
|
||
para.block = i;
|
||
if( PHY_SimpleErase( ¶ ) <0 )
|
||
{
|
||
debug("Fail in erasing block %d.\n", i );
|
||
continue;
|
||
}
|
||
|
||
/* <20>ڿ<EFBFBD><DABF><EFBFBD><EFBFBD><EFBFBD>дboot0<74><30><EFBFBD><EFBFBD> */
|
||
for( j = 0; j < copies_per_block; j++ )
|
||
{
|
||
|
||
for( k = 0; k < NAND_BOOT0_PAGE_CNT_PER_COPY; k++ )
|
||
{
|
||
para.chip = 0;
|
||
para.block = i;
|
||
para.page = j * NAND_BOOT0_PAGE_CNT_PER_COPY + k;
|
||
para.mainbuf = (void *) (Boot0_buf + k * 1024);
|
||
para.oobbuf = oob_buf;
|
||
if( PHY_SimpleWrite_1K( ¶ ) <0)
|
||
{
|
||
debug("Warning. Fail in writing page %d in block %d.\n", j * NAND_BOOT0_PAGE_CNT_PER_COPY + k, i );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return 0;
|
||
|
||
error:
|
||
return -1;
|
||
}
|
||
|
||
__s32 burn_boot0_lsb_mode(__u32 read_retry_type, __u32 Boot0_buf )
|
||
{
|
||
__u32 i, j, k;
|
||
__u8 oob_buf[32];
|
||
__u32 page_size;
|
||
struct boot_physical_param para;
|
||
|
||
debug("burn boot0 lsb mode!\n");
|
||
|
||
for(i=0;i<32;i++)
|
||
oob_buf[i] = 0xff;
|
||
|
||
/* get nand driver version */
|
||
NAND_GetVersion(oob_buf);
|
||
if((oob_buf[0]!=0xff)||(oob_buf[1]!= 0x00))
|
||
{
|
||
debug("get flash driver version error!");
|
||
goto error;
|
||
}
|
||
|
||
/* lsb enable */
|
||
debug("lsb enalbe \n");
|
||
debug("read retry mode: 0x%x\n", read_retry_type);
|
||
if( NFC_LSBInit(read_retry_type) )
|
||
{
|
||
debug("lsb init failed.\n");
|
||
goto error;
|
||
}
|
||
NFC_LSBEnable(0, read_retry_type);
|
||
|
||
|
||
|
||
/* <20><><EFBFBD><EFBFBD> page count */
|
||
page_size = NAND_GetPageSize();
|
||
{
|
||
if(page_size %1024)
|
||
{
|
||
debug("get flash page size error!");
|
||
goto error;
|
||
}
|
||
}
|
||
|
||
|
||
/* burn boot0 */
|
||
for( i = NAND_BOOT0_BLK_START; i < (NAND_BOOT0_BLK_START + NAND_BOOT0_BLK_CNT); i++ )
|
||
{
|
||
debug("down boot0 %x \n", i);
|
||
|
||
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||
para.chip = 0;
|
||
para.block = i;
|
||
if( PHY_SimpleErase( ¶ ) <0 )
|
||
{
|
||
debug("Fail in erasing block %d.\n", i );
|
||
continue;
|
||
}
|
||
|
||
/* <20>ڿ<EFBFBD><DABF><EFBFBD><EFBFBD><EFBFBD>дboot0<74><30><EFBFBD><EFBFBD>, lsb mode<64>£<EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD>ֻ<EFBFBD><D6BB>дǰ4<C7B0><34>page */
|
||
for( k = 0; k < 4; k++ )
|
||
{
|
||
para.chip = 0;
|
||
para.block = i;
|
||
para.page = k;
|
||
para.mainbuf = (void *) (Boot0_buf + k * page_size);
|
||
para.oobbuf = oob_buf;
|
||
if( PHY_SimpleWrite_Seq( ¶ ) <0 )
|
||
{
|
||
debug("Warning. Fail in writing page %d in block %d.\n", k, i );
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
//check boot0
|
||
for( i = NAND_BOOT0_BLK_START; i < (NAND_BOOT0_BLK_START + NAND_BOOT0_BLK_CNT); i++ )
|
||
{
|
||
struct boot_physical_param para;
|
||
__u32 k;
|
||
|
||
debug("verify boot0 %x \n", i);
|
||
|
||
/* <20>ڿ<EFBFBD><DABF><EFBFBD><EFBFBD><EFBFBD>дboot0<74><30><EFBFBD><EFBFBD>, lsb mode<64>£<EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD>ֻ<EFBFBD><D6BB>дǰ4<C7B0><34>page */
|
||
for( k = 0; k < 4; k++ )
|
||
{
|
||
para.chip = 0;
|
||
para.block = i;
|
||
para.page = k;
|
||
para.mainbuf = (void *) (Boot0_buf + k * page_size);
|
||
para.oobbuf = oob_buf;
|
||
if( PHY_SimpleRead_Seq( ¶ ) <0 )
|
||
{
|
||
debug("Warning. Fail in reading page %d in block %d.\n", k, i );
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
/* lsb disable */
|
||
NFC_LSBDisable(0, read_retry_type);
|
||
NFC_LSBExit(read_retry_type);
|
||
debug("lsb disalbe \n");
|
||
|
||
return 0;
|
||
|
||
error:
|
||
return -1;
|
||
}
|
||
|
||
int NAND_BurnBoot0(uint length, void *buffer)
|
||
{
|
||
__u32 read_retry_type = 0, read_retry_mode;
|
||
int blk_index, page_index;
|
||
int page_cnt_per_block;
|
||
|
||
read_retry_type = NAND_GetReadRetryType();
|
||
read_retry_mode = (read_retry_type>>16)&0xff;
|
||
if( (read_retry_type>0)&&(read_retry_mode < 0x10))
|
||
{
|
||
if( burn_boot0_lsb_mode(read_retry_type, (__u32)buffer) )
|
||
goto error;
|
||
}
|
||
else
|
||
{
|
||
if( burn_boot0_1k_mode(read_retry_type, (__u32)buffer) )
|
||
goto error;
|
||
}
|
||
|
||
return 0;
|
||
|
||
error:
|
||
return -1;
|
||
|
||
}
|
||
|
||
|
||
__s32 burn_uboot_in_one_blk(__u32 UBOOT_buf, __u32 length)
|
||
{
|
||
__u32 i, j, k;
|
||
__u8 oob_buf[32];
|
||
__u32 page_size, pages_per_block, pages_per_copy, page_index;
|
||
struct boot_physical_param para;
|
||
|
||
debug("burn uboot normal mode!\n");
|
||
//debug("uboot_buf: 0x%x \n", UBOOT_buf);
|
||
|
||
for(i=0;i<32;i++)
|
||
oob_buf[i] = 0xff;
|
||
|
||
/* get nand driver version */
|
||
NAND_GetVersion(oob_buf);
|
||
if((oob_buf[0]!=0xff)||(oob_buf[1]!= 0x00))
|
||
{
|
||
debug("get flash driver version error!");
|
||
goto error;
|
||
}
|
||
|
||
|
||
/* <20><><EFBFBD><EFBFBD> page count */
|
||
page_size = NAND_GetPageSize();
|
||
{
|
||
if(page_size %1024)
|
||
{
|
||
debug("get flash page size error!");
|
||
goto error;
|
||
}
|
||
}
|
||
|
||
/* <20><><EFBFBD><EFBFBD> page count */
|
||
pages_per_block = NAND_GetPageCntPerBlk();
|
||
if(pages_per_block%64)
|
||
{
|
||
debug("get page cnt per block error %x!", pages_per_block);
|
||
goto error;
|
||
}
|
||
|
||
debug("pages_per_block: 0x%x\n", pages_per_block);
|
||
|
||
/* <20><><EFBFBD><EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>page */
|
||
if(length%page_size)
|
||
{
|
||
debug("uboot length check error!\n");
|
||
goto error;
|
||
}
|
||
pages_per_copy = length/page_size;
|
||
if(pages_per_copy>pages_per_block)
|
||
{
|
||
debug("pages_per_copy check error!\n");
|
||
goto error;
|
||
}
|
||
|
||
debug("pages_per_copy: 0x%x\n", pages_per_copy);
|
||
|
||
//while((*(volatile unsigned int *)0) != 0x1234);
|
||
/* burn uboot */
|
||
for( i = NAND_UBOOT_BLK_START; i < (NAND_UBOOT_BLK_START + NAND_UBOOT_BLK_CNT); i++ )
|
||
{
|
||
debug("uboot %x \n", i);
|
||
|
||
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||
para.chip = 0;
|
||
para.block = i;
|
||
if( PHY_SimpleErase( ¶ ) <0 )
|
||
{
|
||
debug("Fail in erasing block %d.\n", i );
|
||
continue;
|
||
}
|
||
|
||
/* <20>ڿ<EFBFBD><DABF><EFBFBD><EFBFBD><EFBFBD>дboot0<74><30><EFBFBD><EFBFBD>, lsb mode<64>£<EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD>ֻ<EFBFBD><D6BB>дǰ4<C7B0><34>page */
|
||
for( k = 0; k < pages_per_copy; k++ )
|
||
{
|
||
para.chip = 0;
|
||
para.block = i;
|
||
para.page = k;
|
||
para.mainbuf = (void *) (UBOOT_buf + k * page_size);
|
||
para.oobbuf = oob_buf;
|
||
//debug("burn uboot: block: 0x%x, page: 0x%x, mainbuf: 0x%x, maindata: 0x%x \n", para.block, para.page, (__u32)para.mainbuf, *((__u32 *)para.mainbuf));
|
||
if( PHY_SimpleWrite( ¶ ) <0 )
|
||
{
|
||
debug("Warning. Fail in writing page %d in block %d.\n", k, i );
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
memset(oob_buf, 0, 32);
|
||
//check uboot
|
||
for( i = NAND_UBOOT_BLK_START; i < (NAND_UBOOT_BLK_START + NAND_UBOOT_BLK_CNT); i++ )
|
||
{
|
||
debug("verify uboot blk %x \n", i);
|
||
|
||
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||
|
||
for( k = 0; k < pages_per_copy; k++ )
|
||
{
|
||
para.chip = 0;
|
||
para.block = i;
|
||
para.page = k;
|
||
para.mainbuf = (void *) (UBOOT_buf + k * page_size);
|
||
para.oobbuf = oob_buf;
|
||
//debug("burn uboot: block: 0x%x, page: 0x%x, mainbuf: 0x%x, maindata: 0x%x \n", para.block, para.page, (__u32)para.mainbuf, *((__u32 *)para.mainbuf));
|
||
|
||
if( PHY_SimpleRead( ¶ ) <0 )
|
||
{
|
||
debug("Warning. Fail in read page %d in block %d.\n", k, i );
|
||
}
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
|
||
error:
|
||
return -1;
|
||
}
|
||
|
||
__s32 burn_uboot_in_many_blks(__u32 UBOOT_buf, __u32 length)
|
||
{
|
||
__u32 i, j, k;
|
||
__u8 oob_buf[32];
|
||
__u32 page_size, pages_per_block, pages_per_copy, page_index;
|
||
struct boot_physical_param para;
|
||
|
||
debug("burn uboot normal mode!\n");
|
||
|
||
for(i=0;i<32;i++)
|
||
oob_buf[i] = 0xff;
|
||
|
||
/* get nand driver version */
|
||
NAND_GetVersion(oob_buf);
|
||
if((oob_buf[0]!=0xff)||(oob_buf[1]!= 0x00))
|
||
{
|
||
debug("get flash driver version error!");
|
||
goto error;
|
||
}
|
||
|
||
|
||
/* <20><><EFBFBD><EFBFBD> page count */
|
||
page_size = NAND_GetPageSize();
|
||
{
|
||
if(page_size %1024)
|
||
{
|
||
debug("get flash page size error!");
|
||
goto error;
|
||
}
|
||
}
|
||
|
||
/* <20><><EFBFBD><EFBFBD> page count */
|
||
pages_per_block = NAND_GetPageCntPerBlk();
|
||
if(pages_per_block%64)
|
||
{
|
||
printf("get page cnt per block error %x!", pages_per_block);
|
||
goto error;
|
||
}
|
||
|
||
/* <20><><EFBFBD><EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>page */
|
||
if(length%page_size)
|
||
{
|
||
printf("uboot length check error!\n");
|
||
goto error;
|
||
}
|
||
pages_per_copy = length/page_size;
|
||
if(pages_per_copy<=pages_per_block)
|
||
{
|
||
printf("pages_per_copy check error!\n");
|
||
goto error;
|
||
}
|
||
|
||
|
||
/* burn uboot */
|
||
page_index = 0;
|
||
for( i = NAND_UBOOT_BLK_START; i < (NAND_UBOOT_BLK_START + NAND_UBOOT_BLK_CNT); i++ )
|
||
{
|
||
debug("uboot %x \n", i);
|
||
|
||
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||
para.chip = 0;
|
||
para.block = i;
|
||
if( PHY_SimpleErase( ¶ ) <0 )
|
||
{
|
||
printf("Fail in erasing block %d.\n", i );
|
||
continue;
|
||
}
|
||
|
||
/* <20>ڿ<EFBFBD><DABF><EFBFBD><EFBFBD><EFBFBD>дboot0<74><30><EFBFBD><EFBFBD>, lsb mode<64>£<EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD>ֻ<EFBFBD><D6BB>дǰ4<C7B0><34>page */
|
||
for( k = 0; k < pages_per_block; k++ )
|
||
{
|
||
para.chip = 0;
|
||
para.block = i;
|
||
para.page = k;
|
||
para.mainbuf = (void *) (UBOOT_buf + page_index* page_size);
|
||
para.oobbuf = oob_buf;
|
||
if( PHY_SimpleWrite( ¶ ) <0 )
|
||
{
|
||
printf("Warning. Fail in writing page %d in block %d.\n", k, i );
|
||
}
|
||
page_index++;
|
||
|
||
if(page_index >= pages_per_copy)
|
||
break;
|
||
}
|
||
|
||
if(page_index >= pages_per_copy)
|
||
break;
|
||
|
||
}
|
||
|
||
if(page_index >= pages_per_copy)
|
||
return 0;
|
||
else
|
||
goto error;
|
||
|
||
error:
|
||
return -1;
|
||
}
|
||
|
||
|
||
int NAND_BurnUboot(uint length, void *buffer)
|
||
{
|
||
int ret = 0;
|
||
int blk_index, page_index;
|
||
__u32 page_size, pages_per_block, block_size;
|
||
|
||
/* <20><><EFBFBD><EFBFBD> page count */
|
||
page_size = NAND_GetPageSize();
|
||
{
|
||
if(page_size %1024)
|
||
{
|
||
printf("get flash page size error!\n");
|
||
goto error;
|
||
}
|
||
}
|
||
|
||
/* <20><><EFBFBD><EFBFBD> page count */
|
||
pages_per_block = NAND_GetPageCntPerBlk();
|
||
if(pages_per_block%64)
|
||
{
|
||
printf("get page cnt per block error %x!\n", pages_per_block);
|
||
goto error;
|
||
}
|
||
|
||
block_size = page_size*pages_per_block;
|
||
if(length%page_size)
|
||
{
|
||
printf(" uboot length check error!\n");
|
||
goto error;
|
||
}
|
||
|
||
if(length<=block_size)
|
||
{
|
||
ret = burn_uboot_in_one_blk((__u32)buffer, length);
|
||
}
|
||
else
|
||
{
|
||
ret = burn_uboot_in_many_blks((__u32)buffer, length);
|
||
}
|
||
|
||
return ret;
|
||
|
||
error:
|
||
return -1;
|
||
|
||
}
|
||
|
||
|
||
int NAND_GetParam_store(void *buffer, uint length)
|
||
{
|
||
memcpy(buffer, nand_para_store, length);
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
|