mirror of
git://projects.qi-hardware.com/xburst-tools.git
synced 2024-11-01 20:21:54 +02:00
606 lines
13 KiB
C
606 lines
13 KiB
C
|
/*
|
||
|
* Command line handling.
|
||
|
*
|
||
|
* This software is free.
|
||
|
*/
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <unistd.h>
|
||
|
#include <sys/mman.h>
|
||
|
#include <string.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#include "include.h"
|
||
|
#include "configs.h"
|
||
|
#include "nand_ecc.h"
|
||
|
|
||
|
#define printf_log(fp,fmt,args...) fprintf(fp,fmt,## args)
|
||
|
|
||
|
static u8 nand_buf[(2048+64)*128]; //Max 128 pages!
|
||
|
static u8 check_buf[(2048+64)*128];
|
||
|
static u32 spage, epage, chip_num;
|
||
|
static u8 *filename,ops_t,idx,cs_index,args_num;
|
||
|
static np_data *npdata;
|
||
|
static FILE *log_fp;
|
||
|
|
||
|
#define USE_VALID_CHECK
|
||
|
|
||
|
int nand_check_cmp(u8 *buf1,u8 *buf2,u32 len)
|
||
|
{
|
||
|
u32 i;
|
||
|
|
||
|
for (i = 0; i < len; i++)
|
||
|
{
|
||
|
if (buf1[i] != buf2[i])
|
||
|
{
|
||
|
printf("Check error! %x\n",i);
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void dump_npdata(np_data *np)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
printf("Process type:%d \n",np->pt);
|
||
|
|
||
|
printf("NAND interface ps:%d bw:%d rc:%d ppb:%d os:%d bbp:%d bba:%d\n",
|
||
|
np->ps,np->bw,np->rc,np->ppb,np->os,np->bbp,np->bba);
|
||
|
|
||
|
printf("ECC configration type:%d index:%d\n",np->et,np->ep);
|
||
|
printf("ECC position:");
|
||
|
for (i = 0;i < oob_64[np->ep].eccbytes;i++)
|
||
|
{
|
||
|
if (i % 9 == 0) printf("\n");
|
||
|
printf("%d ",oob_64[np->ep].eccpos[i]);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//a check sample for WINCE
|
||
|
//Modify this function according to your system
|
||
|
int check_invalid_block(u8 *buf,np_data *np)
|
||
|
{
|
||
|
int i,j;
|
||
|
u8 *p = buf + np->ps ,* q ;
|
||
|
|
||
|
q = buf + (( np->ps + np->os ) * np->ppb - 1) - 10;
|
||
|
|
||
|
if ( (*q) != 0xff )
|
||
|
{
|
||
|
// printf("A mark erase block! \n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
for ( i = 0; i < np->ppb; i ++ )
|
||
|
{
|
||
|
for (j = 0; j < np->os; j ++ )
|
||
|
{
|
||
|
if ( p[j] != 0xff )
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
p += np->ps;
|
||
|
}
|
||
|
// printf("A never use block! \n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int do_read_flash(np_data *np)
|
||
|
{
|
||
|
FILE *fp;
|
||
|
u32 sp;
|
||
|
int i,j,k;
|
||
|
|
||
|
if ((fp = fopen((const char *)np->fname, "w+")) == NULL )
|
||
|
{
|
||
|
printf("Can not open source or object file!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
i = np->epage - np->spage;
|
||
|
j = i / MAX_BUF_PAGE;
|
||
|
k = i % MAX_BUF_PAGE;
|
||
|
sp = np->spage;
|
||
|
|
||
|
for (i=0;i<j;i++)
|
||
|
{
|
||
|
if (np->nand_check_block(sp/np->ppb))
|
||
|
{
|
||
|
printf_log(log_fp,"Skip a old block at %x!\n",sp/np->ppb);
|
||
|
sp += MAX_BUF_PAGE;
|
||
|
printf("Skip a old block!\n");
|
||
|
continue;
|
||
|
}
|
||
|
np->nand_read(nand_buf, sp, MAX_BUF_PAGE);
|
||
|
#ifdef USE_VALID_CHECK
|
||
|
if ( check_invalid_block(nand_buf,np) )
|
||
|
{
|
||
|
#endif
|
||
|
fwrite(nand_buf,1,MAX_BUF_SIZE,fp);
|
||
|
printf("Read block %d finish\n",sp/np->ppb);
|
||
|
#ifdef USE_VALID_CHECK
|
||
|
}
|
||
|
else printf("Skip a invalid block! %d \n",sp/np->ppb);
|
||
|
#endif
|
||
|
sp += MAX_BUF_PAGE;
|
||
|
}
|
||
|
if (k)
|
||
|
{
|
||
|
if (np->nand_check_block(sp/np->ppb))
|
||
|
{
|
||
|
printf_log(log_fp,"Skip a old block at %x!\n",sp/np->ppb);
|
||
|
printf("Skip a old block!\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
np->nand_read(nand_buf, sp, k);
|
||
|
#ifdef USE_VALID_CHECK
|
||
|
if ( check_invalid_block(nand_buf,np) )
|
||
|
{
|
||
|
#endif
|
||
|
fwrite(nand_buf, 1, k*OOBPAGE_SIZE, fp);
|
||
|
#ifdef USE_VALID_CHECK
|
||
|
}
|
||
|
else printf("Skip a invalid block! %d \n",sp/np->ppb);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
printf("Read nand flash finish!\n");
|
||
|
fclose(fp);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int do_write_flash(np_data *np)
|
||
|
{
|
||
|
FILE *fp;
|
||
|
u32 sp,flen,offset;
|
||
|
int i,j,k,r,error_flag=0;
|
||
|
if ((fp = fopen((const char *)np->fname,"r")) == NULL )
|
||
|
{
|
||
|
printf("Can not open source or object file!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
fseek(fp,0,SEEK_END);
|
||
|
flen = ftell(fp);
|
||
|
i = flen / OOBPAGE_SIZE;
|
||
|
if (flen % OOBPAGE_SIZE !=0)
|
||
|
{
|
||
|
printf("Source file length is not fit!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
sp = np->spage;
|
||
|
if (sp % np->ppb !=0)
|
||
|
{
|
||
|
printf("Start page number not blockaligned!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
//Erase object block first
|
||
|
j = sp / np->ppb;
|
||
|
k = flen/OOBPAGE_SIZE;
|
||
|
if (k % np->ppb == 0) k = k / np->ppb;
|
||
|
else k = k / np->ppb +1;
|
||
|
np->nand_erase(k,j,0);
|
||
|
j = i / MAX_BUF_PAGE;
|
||
|
k = i % MAX_BUF_PAGE;
|
||
|
offset = 0;
|
||
|
// printf("j k %d %d %d %d\n",j,k,i,flen);
|
||
|
|
||
|
for (i=0;i<j;i++)
|
||
|
{
|
||
|
fseek(fp,offset,SEEK_SET);
|
||
|
fread(nand_buf,1,MAX_BUF_SIZE,fp);
|
||
|
BLOCK_BROKEN:
|
||
|
for (r=0;r<MAX_RETRY;r++)
|
||
|
{
|
||
|
for (;sp <=np->epage - np->ppb;sp += np->ppb)
|
||
|
{ //old bad block
|
||
|
if (!np->nand_check_block(sp/np->ppb))
|
||
|
break;
|
||
|
printf("Skip a old bad blocks!\n");
|
||
|
printf_log(log_fp,"Skip a old block at %x!\n",sp/np->ppb);
|
||
|
}
|
||
|
if (sp/np->ppb > np->epage /np->ppb)
|
||
|
{
|
||
|
printf("Program end but not finish,due to bad block!\n");
|
||
|
printf_log(log_fp,"Program end but not finish,due to bad block!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
if (np->nand_program(nand_buf,sp,np->ppb))
|
||
|
{
|
||
|
error_flag = 1;
|
||
|
printf("Program error!\n");
|
||
|
printf_log(log_fp,"Program error! %x\n",sp/np->ppb);
|
||
|
break;
|
||
|
}
|
||
|
memset(check_buf,0,MAX_BUF_SIZE);
|
||
|
np->nand_read(check_buf,sp,np->ppb);
|
||
|
if (np->nand_check(nand_buf,check_buf,
|
||
|
MAX_BUF_SIZE) )
|
||
|
{ //check error!
|
||
|
error_flag = 1;
|
||
|
printf("Error retry!\n");
|
||
|
printf_log(log_fp,"Error retry!\n");
|
||
|
continue;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
error_flag = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (error_flag)
|
||
|
{ //block has broken!
|
||
|
printf("Found a new bad block: %x!\n",sp/np->ppb);
|
||
|
printf_log(log_fp,"Found a new bad block at %x!\n",sp/np->ppb);
|
||
|
np->nand_erase(1,sp/np->ppb,0); //erase before mark bad block!
|
||
|
np->nand_block_markbad(sp /np->ppb);
|
||
|
sp += np->ppb;
|
||
|
goto BLOCK_BROKEN;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("Write block %d finish\n",sp/np->ppb);
|
||
|
sp += np->ppb;
|
||
|
offset += MAX_BUF_SIZE;
|
||
|
}
|
||
|
}
|
||
|
if (k)
|
||
|
{
|
||
|
fseek(fp,offset,SEEK_SET);
|
||
|
fread(nand_buf,1,k * OOBPAGE_SIZE ,fp);
|
||
|
BLOCK_BROKEN1:
|
||
|
for (r=0;r<MAX_RETRY;r++)
|
||
|
{
|
||
|
for (;sp <=np->epage - np->ppb;sp += np->ppb)
|
||
|
{ //old bad block
|
||
|
if (!np->nand_check_block(sp/np->ppb))
|
||
|
break;
|
||
|
printf("Skip a old bad blocks!\n");
|
||
|
printf_log(log_fp,"Skip a old block at %x!\n",sp/np->ppb);
|
||
|
}
|
||
|
if (sp/np->ppb > np->epage/np->ppb)
|
||
|
{
|
||
|
printf("Program end but not finish,due to bad block!\n");
|
||
|
printf_log(log_fp,"Program end but not finish,due to bad block!\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (np->nand_program(nand_buf,sp,k))
|
||
|
{
|
||
|
error_flag = 1;
|
||
|
printf("Program error!\n");
|
||
|
printf_log(log_fp,"Program error! %x\n",sp/np->ppb);
|
||
|
break;
|
||
|
}
|
||
|
memset(check_buf,0,MAX_BUF_SIZE);
|
||
|
np->nand_read(check_buf,sp,k);
|
||
|
if (np->nand_check(nand_buf,check_buf,
|
||
|
k * OOBPAGE_SIZE) )
|
||
|
{ //check error!
|
||
|
error_flag = 1;
|
||
|
printf("Error retry!\n");
|
||
|
printf_log(log_fp,"Error retry!\n");
|
||
|
continue;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
error_flag = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (error_flag)
|
||
|
{ //block has broken!
|
||
|
printf("Found a new bad block : %x!\n",sp/np->ppb);
|
||
|
printf_log(log_fp,"Found a new bad block at %x!\n",sp/np->ppb);
|
||
|
np->nand_erase(1,sp/np->ppb,0); //erase before mark bad block!
|
||
|
np->nand_block_markbad(sp /np->ppb);
|
||
|
sp += np->ppb;
|
||
|
goto BLOCK_BROKEN1;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
printf("Nand flash write finish!\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void show_usage()
|
||
|
{
|
||
|
printf("Nand flash programmer.Version v1.0\n");
|
||
|
printf("Usage: nandprog spage epage opration_type obj_file chip_index [config_index]\n\n");
|
||
|
printf(" spage operation start page number\n");
|
||
|
printf(" epage operation end page number\n");
|
||
|
printf(" opration_type operation type read or write\n");
|
||
|
printf(" obj_file source or object filename\n");
|
||
|
printf(" chip_index chip select index\n");
|
||
|
printf(" config_index optional,when chosen,\n");
|
||
|
printf(" will use one of these default configrations instead of load from CFG\n");
|
||
|
|
||
|
}
|
||
|
|
||
|
int cmdline(int argc, char *argv[], np_data *np)
|
||
|
{
|
||
|
|
||
|
if (argc<6 || argc>7)
|
||
|
{
|
||
|
show_usage();
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (strlen(argv[1])>8)
|
||
|
{
|
||
|
printf("Start address page error!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
spage = atoi(argv[1]);
|
||
|
if (spage > MAX_PAGE)
|
||
|
{
|
||
|
printf("Start address page error!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (strlen(argv[2])>8)
|
||
|
{
|
||
|
printf("End address page error!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
epage = atoi(argv[2]);
|
||
|
if (epage > MAX_PAGE)
|
||
|
{
|
||
|
printf("End address page error!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (strlen(argv[3])>1)
|
||
|
{
|
||
|
printf("Operation type error!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
if (argv[3][0] == 'r')
|
||
|
ops_t = READ_FLASH;
|
||
|
else if (argv[3][0] == 'w')
|
||
|
ops_t = WRITE_FLASH;
|
||
|
else
|
||
|
{
|
||
|
printf("Operation type error!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (strlen(argv[4])>20)
|
||
|
{
|
||
|
printf("Source or object file name error!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
filename = (unsigned char *)argv[4];
|
||
|
|
||
|
if (strlen(argv[5])>2)
|
||
|
{
|
||
|
printf("Chip select number error!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
cs_index = atoi(argv[5]);
|
||
|
|
||
|
if (epage <= spage)
|
||
|
{
|
||
|
printf("End page number must larger than start page number!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (argc == 7)
|
||
|
{
|
||
|
args_num = 7;
|
||
|
if (strlen(argv[6])>3)
|
||
|
{
|
||
|
printf("Processor type error!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
idx = atoi(argv[6]);
|
||
|
if (idx > 20)
|
||
|
{
|
||
|
printf("Processor type error!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
else args_num = 6;
|
||
|
|
||
|
printf("Deal command line: spage%d epage%d ops%d file:%s cs%d\n",
|
||
|
spage,epage,ops_t,filename,cs_index);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void init_funs(np_data *np)
|
||
|
{
|
||
|
switch (np->pt)
|
||
|
{
|
||
|
case JZ4740:
|
||
|
np->ebase = 0x13010000;
|
||
|
np->dport = 0x18000000;
|
||
|
np->gport = 0x10010000;
|
||
|
np->bm_ms = 0x100;
|
||
|
np->pm_ms = 0x20000;
|
||
|
np->gm_ms = 0x500;
|
||
|
np->ap_offset = 0x10000;
|
||
|
np->cp_offset = 0x8000;
|
||
|
|
||
|
np->nand_init = nand_init_4740;
|
||
|
np->nand_erase = nand_erase_4740;
|
||
|
np->nand_program = nand_program_4740;
|
||
|
np->nand_read = nand_read_4740_rs;
|
||
|
np->nand_read_raw = nand_read_raw_4740;
|
||
|
np->nand_read_oob = nand_read_oob_4740;
|
||
|
np->nand_block_markbad = nand_block_markbad_4740;
|
||
|
np->nand_check = nand_check_cmp;
|
||
|
np->nand_check_block = nand_check_block_4740;
|
||
|
if (np->et == HARDRS)
|
||
|
np->nand_read = nand_read_4740_rs;
|
||
|
else
|
||
|
np->nand_read = nand_read_4740_hm;
|
||
|
|
||
|
break;
|
||
|
case JZ4730:
|
||
|
np->ebase = 0x13010000;
|
||
|
np->dport = 0x14000000;
|
||
|
np->gport = 0x0;
|
||
|
np->bm_ms = 0x100;
|
||
|
np->pm_ms = 0xb0000;
|
||
|
np->gm_ms = 0x0;
|
||
|
np->ap_offset = 0x80000;
|
||
|
np->cp_offset = 0x40000;
|
||
|
|
||
|
np->nand_init = nand_init_4730;
|
||
|
np->nand_erase = nand_erase_4730;
|
||
|
np->nand_program = nand_program_4730;
|
||
|
np->nand_read = nand_read_4730;
|
||
|
np->nand_read_oob = nand_read_oob_4730;
|
||
|
np->nand_block_markbad = nand_block_markbad;
|
||
|
np->nand_check = nand_check_cmp;
|
||
|
np->nand_check_block = nand_check_block;
|
||
|
np->nand_select = chip_select_4730;
|
||
|
break;
|
||
|
case JZ4760:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// dump_npdata(np);
|
||
|
}
|
||
|
|
||
|
np_data * cmdinit()
|
||
|
{
|
||
|
int fd;
|
||
|
if (args_num>6)
|
||
|
{
|
||
|
npdata = &config_list[idx];
|
||
|
if (npdata)
|
||
|
printf("Load configration index success!\n");
|
||
|
else
|
||
|
{
|
||
|
printf("Load configration index fail!\n");
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
npdata = load_cfg();
|
||
|
if (npdata)
|
||
|
printf("Load configration file success!\n");
|
||
|
else
|
||
|
{
|
||
|
printf("Load configration file fail!\n");
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
if (!npdata) return 0;
|
||
|
|
||
|
init_funs(npdata);
|
||
|
npdata->spage = spage;
|
||
|
npdata->epage = epage;
|
||
|
npdata->fname = filename;
|
||
|
npdata->ops = ops_t;
|
||
|
npdata->cs = cs_index;
|
||
|
|
||
|
if((fd=open("/dev/mem",O_RDWR|O_SYNC))==-1)
|
||
|
{
|
||
|
printf("Can not open memory file!\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
npdata->base_map = mmap(NULL,npdata->bm_ms,PROT_READ | PROT_WRITE,MAP_SHARED,fd,npdata->ebase);
|
||
|
if(npdata->base_map == MAP_FAILED)
|
||
|
{
|
||
|
printf("Can not map EMC_BASE ioport!\n");
|
||
|
return 0;
|
||
|
}
|
||
|
else printf("Map EMC_BASE success :%x\n",(u32)npdata->base_map);
|
||
|
|
||
|
npdata->port_map=mmap(NULL,npdata->pm_ms ,PROT_READ | PROT_WRITE,MAP_SHARED,fd,npdata->dport);
|
||
|
if(npdata->port_map== MAP_FAILED)
|
||
|
{
|
||
|
printf("Can not map NAND_PORT ioport!\n");
|
||
|
return 0;
|
||
|
}
|
||
|
else printf("Map NAND_PORT success :%x\n",(u32)npdata->port_map);
|
||
|
|
||
|
if (npdata->pt == JZ4740)
|
||
|
{
|
||
|
npdata->gpio_map=mmap(NULL,npdata->gm_ms ,PROT_READ | PROT_WRITE,MAP_SHARED,fd,npdata->gport);
|
||
|
if(npdata->gpio_map== MAP_FAILED)
|
||
|
{
|
||
|
printf("Can not map GPIO ioport!\n");
|
||
|
return 0;
|
||
|
}
|
||
|
else printf("Map GPIO_PORT success :%x\n",(u32)npdata->gpio_map);
|
||
|
}
|
||
|
|
||
|
close(fd);
|
||
|
|
||
|
printf("Memory map all success!\n");
|
||
|
npdata->nand_init(npdata);
|
||
|
|
||
|
return npdata;
|
||
|
}
|
||
|
|
||
|
int cmdexcute(np_data *np)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
if ((log_fp=fopen(NUM_FILENAME,"a+"))==NULL )
|
||
|
{
|
||
|
printf("Can not open number file!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
fscanf(log_fp,"%d",&chip_num);
|
||
|
fclose(log_fp);
|
||
|
chip_num++;
|
||
|
if ((log_fp=fopen(NUM_FILENAME,"w"))==NULL )
|
||
|
{
|
||
|
printf("Can not open number file!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
printf_log(log_fp,"%d",chip_num);
|
||
|
fclose(log_fp);
|
||
|
|
||
|
if ((log_fp=fopen(LOG_FILENAME,"a+"))==NULL )
|
||
|
{
|
||
|
printf("Can not open log file!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
printf_log(log_fp,"\nNo.%d :\n",chip_num);
|
||
|
|
||
|
if (np->ops == READ_FLASH)
|
||
|
{
|
||
|
printf_log(log_fp,"Read nand flash!\n");
|
||
|
printf_log(log_fp,"Args:index=%d spage=%d epage=%d file=%s cs=%d\n",
|
||
|
idx,spage,epage,filename,cs_index);
|
||
|
ret= do_read_flash(np);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf_log(log_fp,"Write nand flash!\n");
|
||
|
printf_log(log_fp,"Args:index=%d spage=%d epage=%d file=%s cs=%d\n",
|
||
|
idx,spage,epage,filename,cs_index);
|
||
|
ret= do_write_flash(np);
|
||
|
}
|
||
|
|
||
|
if (!ret)
|
||
|
printf_log(log_fp,"Operation success!\n");
|
||
|
else
|
||
|
printf_log(log_fp,"Operation fail!\n");
|
||
|
|
||
|
fclose(log_fp);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int cmdexit(np_data *np)
|
||
|
{
|
||
|
munmap(np->base_map,np->bm_ms);
|
||
|
munmap(np->port_map,np->pm_ms);
|
||
|
if (np->pt == JZ4740)
|
||
|
munmap(np->gpio_map,np->gm_ms);
|
||
|
return 0;
|
||
|
}
|