1
0
mirror of git://projects.qi-hardware.com/xburst-tools.git synced 2024-11-25 20:04:03 +02:00

add nand flash tools

This commit is contained in:
xiangfu 2009-04-05 16:26:33 +00:00
parent e043feab69
commit 5c31ed05b7
12 changed files with 12522 additions and 0 deletions

37
nandprog/Makefile Normal file
View File

@ -0,0 +1,37 @@
#
# Makefile
#
CROSS = mipsel-linux-
CC = $(CROSS)gcc
LD = $(CROSS)ld
ROOTFIR = .
JZ4730DIR = $(ROOTFIR)/jz4730
JZ4740DIR = $(ROOTFIR)/jz4740
INCDIR = $(ROOTFIR)/include
COMDIR = $(ROOTFIR)/common
SOURCES += $(wildcard $(JZ4730DIR)/*.c)
SOURCES += $(wildcard $(JZ4740DIR)/*.c)
SOURCES += $(wildcard $(COMDIR)/*.c)
HEADS :=$(wildcard $(INCDIR)/*.h)
OBJS := $(addsuffix .o , $(basename $(notdir $(SOURCES))))
CFLAGS := -I$(INCDIR) -O2 -Wall
VPATH := $(JZ4730DIR) $(COMDIR) $(JZ4740DIR)
TARGETS = nandprog
all: $(TARGETS)
$(TARGETS) : $(OBJS) $(HEADS)
$(CC) $(CFLAGS) -o $(TARGETS) $(OBJS)
.c.o:
$(CC) $(CFLAGS) -o $@ -c $<
install:
clean:
rm -f *.o $(TARGETS)

30
nandprog/README Normal file
View File

@ -0,0 +1,30 @@
This package contains source of the NAND flash programmer. It is an user
application program running on the Linux kernel.
To build the software, you need to have a Linux PC and install the
mipsel-linux-gcc compiler first, and then type 'make' under the
Linux command shell:
$ make
The dir tree as following:
|-- Makefile
|-- common
| |-- cmdline.c
| |-- loadcfg.c
| `-- main.c
|-- include
| |-- configs.h
| |-- include.h
| |-- jz4730.h
| |-- jz4740.h
| `-- nand_ecc.h
|-- jz4730
| `-- nandflash_4730.c
`-- jz4740
`-- nandflash_4740.c
To get more information, please read <NandProgrammer_Manual.pdf>.
Any questions, contact with me <yliu@ingenic.cn>.

605
nandprog/common/cmdline.c Normal file
View File

@ -0,0 +1,605 @@
/*
* 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;
}

214
nandprog/common/loadcfg.c Normal file
View File

@ -0,0 +1,214 @@
/*
* Configfile parsing.
*/
#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"
#define CFG_FIELD_NUM 10
static np_data np;
extern struct nand_oobinfo oob_64[];
const char CFG_FIELD[][30]=
{
"CPUTYPE",
"BUSWIDTH",
"ROWCYCLES",
"PAGESIZE",
"PAGEPERBLOCK",
"OOBSIZE",
"BADBLOCKPOS",
"BADBLOCKPAGE",
"ECCTYPE",
"[END]",
};
np_data * load_cfg(void)
{
FILE *fp;
char line[100];
unsigned short i,j;
unsigned int d;
if ((fp = fopen("nandprog.cfg", "r"))==NULL)
{
printf("Can not open configration file!\n");
return 0;
}
while(!strstr(line, "[NANDPROG]")) //find the nandprog section!
{
if (feof(fp))
{
printf("nand programmer configration file illege!\n");
return 0;
}
fscanf(fp,"%s",line);
}
while(1)
{
if (feof(fp))
{
printf("nand programmer configration file illege!\n");
return 0;
}
fscanf(fp,"%s",line);
if (line[0]==';')
{
line[0]='\0';
continue;
}
for (i=0;i<CFG_FIELD_NUM;i++)
if (strstr(line,CFG_FIELD[i])) break;
switch (i)
{
case 0: //CPUTYPE
while (!feof(fp))
{
fscanf(fp,"%s",line);
if (strstr(line,"JZ4730"))
{
np.pt = JZ4730;
break;
}
else if (strstr(line,"JZ4740"))
{
np.pt = JZ4740;
break;
}
else continue;
}
break;
case 1: //BUSWIDTH
while (!feof(fp))
{
fscanf(fp,"%d",&d);
if (d!=8 && d!=16) continue;
np.bw = d;
break;
}
break;
case 2: //ROWCYCLES
while (!feof(fp))
{
fscanf(fp,"%d",&d);
if (d!=3 && d!=2) continue;
np.rc = d;
break;
}
break;
case 3: //PAGESIZE
while (!feof(fp))
{
fscanf(fp,"%d",&d);
if (d!=2048 && d!=512) continue;
np.ps = d;
break;
}
break;
case 4: //PAGEPERBLOCK
while (!feof(fp))
{
fscanf(fp,"%d",&d);
if (d!=128 && d!=64) continue;
np.ppb = d;
break;
}
break;
case 5: //OOBSIZE
while (!feof(fp))
{
fscanf(fp,"%d",&d);
if (d!=16 && d!=64) continue;
np.os = d;
break;
}
break;
case 6: //BADBLOCKPOS
while (!feof(fp))
{
fscanf(fp,"%d",&d);
if (d>2048) continue;
np.bbp = d;
break;
}
break;
case 7: //BADBLOCKPAGE
while (!feof(fp))
{
fscanf(fp,"%d",&d);
if (d>np.ppb) continue;
np.bba = d;
break;
}
break;
case 8: //ECCTYPE
while (!feof(fp))
{
fscanf(fp,"%s",line);
if (strstr(line,"RS"))
{
np.et = HARDRS;
d = 36; //36 bytes ecc
oob_64[4].eccbytes = 36;
np.ep = 4;
break;
}
else if (strstr(line,"HM"))
{
np.et = HARDHM;
d = 24; //24 bytes ecc
oob_64[4].eccbytes = 24;
np.ep = 4;
break;
}
else continue;
}
while (!feof(fp))
{
fscanf(fp,"%s",line);
if (strstr(line,"{")) break;
}
for (j = 0;j < d;j++)
{
if (feof(fp))
{
printf("nand programmer configration file illege!\n");
return 0;
}
fscanf(fp,"%d",&d);
if (d > np.os)
{
printf("nand programmer configration file illege!\n");
return 0;
}
oob_64[4].eccpos[j] = d;
}
while (!feof(fp))
{
fscanf(fp,"%s",line);
if (strstr(line,"}")) break;
}
break;
case 9:
return &np;
default:
;
}
}
}

23
nandprog/common/main.c Normal file
View File

@ -0,0 +1,23 @@
/*
* Main entry of the program.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include "include.h"
static np_data *npdata;
int main(int argc, char *argv[])
{
if (cmdline(argc, argv, npdata)) return 0;
npdata=cmdinit();
if (!npdata) return 0;
if (cmdexcute(npdata)) return 0;
if (cmdexit(npdata)) return 0;
return 0;
}

406
nandprog/include/configs.h Normal file
View File

@ -0,0 +1,406 @@
#ifndef __CONFIGS_H__
#define __CONFIGS_H__
#include "include.h"
np_data config_list[]=
{
{
//No 0
//The config for jz4730 uboot
.pt = JZ4730,
.et = HARDHM, //HW HM ECC
.ep = 0, //ecc position index 0
.bw = 8,
.ps = 2048,
.os = 64,
.ppb = 64,
.rc = 3,
.bbp = 0,
.bba = 0,
.ebase = 0x13010000,
.dport = 0x14000000,
.gport = 0,
.bm_ms = 0x100,
.pm_ms = 0xb0000,
.gm_ms = 0,
.ap_offset = 0x80000,
.cp_offset = 0x40000,
.nand_init = nand_init_4730,
.nand_erase = nand_erase_4730,
.nand_program = nand_program_4730,
.nand_read = nand_read_4730,
.nand_read_oob = nand_read_oob_4730,
.nand_block_markbad = nand_block_markbad,
.nand_check = nand_check_cmp,
.nand_check_block = nand_check_block,
.nand_select = chip_select_4730,
},
{
//No 1
//The config for jz4730 linux fs
.pt = JZ4730,
.et = HARDHM, //HW HM ECC
.ep = 1, //ecc position index 1
.bw = 8,
.ps = 2048,
.os = 64,
.ppb = 64,
.rc = 3,
.bbp = 0,
.bba = 0,
.ebase = 0x13010000,
.dport = 0x14000000,
.gport = 0,
.bm_ms = 0x100,
.pm_ms = 0xb0000,
.gm_ms = 0,
.ap_offset = 0x80000,
.cp_offset = 0x40000,
.nand_init = nand_init_4730,
.nand_erase = nand_erase_4730,
.nand_program = nand_program_4730,
.nand_read = nand_read_4730,
.nand_read_oob = nand_read_oob_4730,
.nand_block_markbad = nand_block_markbad,
.nand_check = nand_check_cmp,
.nand_check_block = nand_check_block,
.nand_select = chip_select_4730,
},
{
//No 2
//The config for jz4730 ucos
.pt = JZ4730,
.et = HARDHM, //HW HM ECC
.ep = 1, //need modify
.bw = 8,
.ps = 2048,
.os = 64,
.ppb = 64,
.rc = 3,
.bbp = 0, //need modify
.bba = 0, //need modify
//do not need modify
.ebase = 0x13010000,
.dport = 0x14000000,
.gport = 0,
.bm_ms = 0x100,
.pm_ms = 0xb0000,
.gm_ms = 0,
.ap_offset = 0x80000,
.cp_offset = 0x40000,
.nand_init = nand_init_4730,
.nand_erase = nand_erase_4730,
.nand_program = nand_program_4730,
.nand_read = nand_read_4730,
.nand_read_oob = nand_read_oob_4730,
.nand_block_markbad = nand_block_markbad,
.nand_check = nand_check_cmp,
.nand_check_block = nand_check_block,
.nand_select = chip_select_4730,
},
{
//No 3
//The config for jz4730 wince
.pt = JZ4730,
.et = HARDHM, //HW HM ECC
.ep = 1, //need modify
.bw = 8,
.ps = 2048,
.os = 64,
.ppb = 64,
.rc = 3,
.bbp = 0, //need modify
.bba = 0, //need modify
//do not need modify
.ebase = 0x13010000,
.dport = 0x14000000,
.gport = 0,
.bm_ms = 0x100,
.pm_ms = 0xb0000,
.gm_ms = 0,
.ap_offset = 0x80000,
.cp_offset = 0x40000,
.nand_init = nand_init_4730,
.nand_erase = nand_erase_4730,
.nand_program = nand_program_4730,
.nand_read = nand_read_4730,
.nand_read_oob = nand_read_oob_4730,
.nand_block_markbad = nand_block_markbad,
.nand_check = nand_check_cmp,
.nand_check_block = nand_check_block,
.nand_select = chip_select_4730,
},
{
//No 4
//The config for jz4740 uboot use HW RS
.pt = JZ4740,
.et = HARDRS, //HW HM ECC
.ep = 2, //need modify
.bw = 8,
.ps = 2048,
.os = 64,
.ppb = 128,
.rc = 3,
.bbp = 0, //need modify
.bba = 0, //need modify
//do not need modify
.ebase = 0x13010000,
.dport = 0x18000000,
.gport = 0x10010000,
.bm_ms = 0x100,
.pm_ms = 0x20000,
.gm_ms = 0x500,
.ap_offset = 0x10000,
.cp_offset = 0x8000,
.nand_init = nand_init_4740,
.nand_erase = nand_erase_4740,
.nand_program = nand_program_4740,
.nand_read = nand_read_4740_rs,
.nand_read_oob = nand_read_oob_4740,
.nand_block_markbad = nand_block_markbad_4740,
.nand_check = nand_check_cmp,
.nand_check_block = nand_check_block_4740,
.nand_select = chip_select_4740,
},
{
//No 5
//The config for jz4740 linux use HW RS
.pt = JZ4740,
.et = HARDRS, //HW HM ECC
.ep = 3, //need modify
.bw = 8,
.ps = 2048,
.os = 64,
.ppb = 128,
.rc = 3,
.bbp = 1, //need modify
.bba = 0, //need modify
//do not need modify
.ebase = 0x13010000,
.dport = 0x18000000,
.gport = 0x10010000,
.bm_ms = 0x100,
.pm_ms = 0x20000,
.gm_ms = 0x500,
.ap_offset = 0x10000,
.cp_offset = 0x8000,
.nand_init = nand_init_4740,
.nand_fini = nand_fini_4740,
.nand_erase = nand_erase_4740,
.nand_program = nand_program_4740,
.nand_read = nand_read_4740_rs,
.nand_read_oob = nand_read_oob_4740,
.nand_block_markbad = nand_block_markbad_4740,
.nand_check = nand_check_cmp,
.nand_check_block = nand_check_block_4740,
.nand_select = chip_select_4740,
},
{
//No 6
//The config for jz4740 linux use HW HM
.pt = JZ4740,
.et = HARDHM, //HW HM ECC
.ep = 1, //need modify
.bw = 8,
.ps = 2048,
.os = 64,
.ppb = 128,
.rc = 3,
.bbp = 0, //need modify
.bba = 0, //need modify
//do not need modify
.ebase = 0x13010000,
.dport = 0x18000000,
.gport = 0x10010000,
.bm_ms = 0x100,
.pm_ms = 0x20000,
.gm_ms = 0x500,
.ap_offset = 0x10000,
.cp_offset = 0x8000,
.nand_init = nand_init_4740,
.nand_erase = nand_erase_4740,
.nand_program = nand_program_4740,
.nand_read = nand_read_4740_hm,
.nand_read_oob = nand_read_oob_4740,
.nand_block_markbad = nand_block_markbad_4740,
.nand_check = nand_check_cmp,
.nand_check_block = nand_check_block_4740,
.nand_select = chip_select_4740,
},
{
//No 7
//The config for jz4740 ucos use HW RS
.pt = JZ4740,
.et = HARDRS, //HW HM ECC
// .ep = 3, //need modify
.bw = 8,
.ps = 2048,
.os = 64,
.ppb = 128,
.rc = 3,
// .bbp = 0, //need modify
// .bba = 0, //need modify
//do not need modify
.ebase = 0x13010000,
.dport = 0x18000000,
.gport = 0x10010000,
.bm_ms = 0x100,
.pm_ms = 0x20000,
.gm_ms = 0x500,
.ap_offset = 0x10000,
.cp_offset = 0x8000,
.nand_init = nand_init_4740,
.nand_erase = nand_erase_4740,
.nand_program = nand_program_4740,
.nand_read = nand_read_4740_rs,
.nand_read_oob = nand_read_oob_4740,
.nand_block_markbad = nand_block_markbad_4740,
.nand_check = nand_check_cmp,
.nand_check_block = nand_check_block_4740,
.nand_select = chip_select_4740,
},
{
//No 8
//The config for jz4740 ucos use HW HM
.pt = JZ4740,
.et = HARDHM, //HW HM ECC
// .ep = 3, //need modify
.bw = 8,
.ps = 2048,
.os = 64,
.ppb = 128,
.rc = 3,
// .bbp = 0, //need modify
// .bba = 0, //need modify
//do not need modify
.ebase = 0x13010000,
.dport = 0x18000000,
.gport = 0x10010000,
.bm_ms = 0x100,
.pm_ms = 0x20000,
.gm_ms = 0x500,
.ap_offset = 0x10000,
.cp_offset = 0x8000,
.nand_init = nand_init_4740,
.nand_erase = nand_erase_4740,
.nand_program = nand_program_4740,
.nand_read = nand_read_4740_hm,
.nand_read_oob = nand_read_oob_4740,
.nand_block_markbad = nand_block_markbad_4740,
.nand_check = nand_check_cmp,
.nand_check_block = nand_check_block_4740,
.nand_select = chip_select_4740,
},
{
//No 9
//The config for jz4740 wince use HW RS
.pt = JZ4740,
.et = HARDRS, //HW HM ECC
// .ep = 3, //need modify
.bw = 8,
.ps = 2048,
.os = 64,
.ppb = 128,
.rc = 3,
// .bbp = 0, //need modify
// .bba = 0, //need modify
//do not need modify
.ebase = 0x13010000,
.dport = 0x18000000,
.gport = 0x10010000,
.bm_ms = 0x100,
.pm_ms = 0x20000,
.gm_ms = 0x500,
.ap_offset = 0x10000,
.cp_offset = 0x8000,
.nand_init = nand_init_4740,
.nand_erase = nand_erase_4740,
.nand_program = nand_program_4740,
.nand_read = nand_read_4740_rs,
.nand_read_oob = nand_read_oob_4740,
.nand_block_markbad = nand_block_markbad_4740,
.nand_check = nand_check_cmp,
.nand_check_block = nand_check_block_4740,
.nand_select = chip_select_4740,
},
{
//No 10
//The config for jz4740 wince use HW RS
.pt = JZ4740,
.et = HARDHM, //HW HM ECC
// .ep = 3, //need modify
.bw = 8,
.ps = 2048,
.os = 64,
.ppb = 128,
.rc = 3,
// .bbp = 0, //need modify
// .bba = 0, //need modify
//do not need modify
.ebase = 0x13010000,
.dport = 0x18000000,
.gport = 0x10010000,
.bm_ms = 0x100,
.pm_ms = 0x20000,
.gm_ms = 0x500,
.ap_offset = 0x10000,
.cp_offset = 0x8000,
.nand_init = nand_init_4740,
.nand_erase = nand_erase_4740,
.nand_program = nand_program_4740,
.nand_read = nand_read_4740_hm,
.nand_read_oob = nand_read_oob_4740,
.nand_block_markbad = nand_block_markbad_4740,
.nand_check = nand_check_cmp,
.nand_check_block = nand_check_block_4740,
.nand_select = chip_select_4740,
},
};
#endif

140
nandprog/include/include.h Normal file
View File

@ -0,0 +1,140 @@
#ifndef __INCLUDE_H__
#define __INCLUDE_H__
//#include "nand_ecc.h"
#define u32 unsigned int
#define u16 unsigned short
#define u8 unsigned char
#define MAX_PAGE 0xffffffff
#define PAGE_SIZE np->ps
#define OOB_SIZE np->os
#define OOBPAGE_SIZE (PAGE_SIZE + OOB_SIZE)
#define MAX_BUF_PAGE np->ppb
#define MAX_BUF_SIZE OOBPAGE_SIZE*MAX_BUF_PAGE
#define MAX_RETRY 3
#define LAST_PAGE 65536
#define LOG_FILENAME "nprog.log"
#define NUM_FILENAME "number.log"
enum
{
JZ4730CPU,
LINUXHM,
JZ4740CPU,
LINUXRS,
USERSPEC,
};
struct nand_oobinfo
{
int eccname;
unsigned int eccbytes;
unsigned int eccpos[64];
};
enum
{
SOFTHM,
SOFTRS,
HARDHM,
HARDRS
};
enum
{
JZ4730,
JZ4740,
JZ4760
};
enum
{
READ_FLASH,
WRITE_FLASH
};
typedef struct _NP_DATA
{
u8 pt; //processor type jz4730/jz4740/jz4760....
u8 et; //ECC type software HM/RS or hardware HM/RS
u8 ep; //ECC position index
u8 ops; //opration type read/write
u8 cs; //chip select index number
u8 *fname; //Source or object file name
u32 spage; //opration start page number of nand flash
u32 epage; //opration end page number of nand flash
u32 bw; //nand flash bus width
u32 ps; //nand flash page size
u32 os; //nand flash oob size
u32 ppb; //nand flash page per block
u32 rc; //nand flash row syscle
u32 bbp; //nand flash bad block ID position
u32 bba; //nand flash bad block ID page position
u32 ebase; //EMC base PHY address
void *base_map; //EMC base mapped address
u32 bm_ms; // EMC base mapped size
u32 dport; //Nand flash port base PHY address
void *port_map; //nand port mapped address
u32 pm_ms; // EMC base mapped size
u32 gport; //GPIO base PHY address
void *gpio_map; //GPIO mapped address
u32 gm_ms; // EMC base mapped size
u32 ap_offset; //addrport offset
u32 cp_offset; //cmdportoffset
int (*nand_init)(struct _NP_DATA *);
int (*nand_fini)(void);
u32 (*nand_query)(void);
int (*nand_erase)(int, int, int);
int (*nand_program)(u8 *, int, int );
int (*nand_read)(u8 *, u32, u32);
int (*nand_read_raw)(u8 *, u32, u32);
int (*nand_read_oob)(u8 *, u32, u32);
int (*nand_check_block) (u32);
int (*nand_check) (u8 *,u8 *,u32 );
void (*nand_block_markbad) (u32);
int (*nand_select) (u8);
}np_data;
//jz4730 functions
extern int nand_init_4730(np_data *);
extern int nand_fini_4730(void);
extern unsigned int nand_query_4730(void);
extern int nand_erase_4730(int blk_num, int sblk, int force);
extern int nand_program_4730(u8 *buf, int startpage, int pagenum);
extern int nand_read_4730(u8 *buf, u32 startpage, u32 pagenum);
extern int nand_read_raw_4730(u8 *buf, u32 startpage, u32 pagenum);
extern int nand_read_oob_4730(u8 *buf, u32 startpage, u32 pagenum);
extern int nand_check_block(u32);
extern void nand_block_markbad(u32);
extern int chip_select_4730(u8 cs);
//jz4740 functions
extern int nand_init_4740(np_data *);
extern int nand_fini_4740(void);
extern unsigned int nand_query_4740(void);
extern int nand_erase_4740(int blk_num, int sblk, int force);
extern int nand_program_4740(u8 *buf, int startpage, int pagenum);
extern int nand_read_4740_hm(u8 *buf, u32 startpage, u32 pagenum);
extern int nand_read_4740_rs(u8 *buf, u32 startpage, u32 pagenum);
extern int nand_read_raw_4740(u8 *buf, u32 startpage, u32 pagenum);
extern int nand_read_oob_4740(u8 *buf, u32 startpage, u32 pagenum);
extern int nand_check_block_4740(u32);
extern void nand_block_markbad_4740(u32);
extern int chip_select_4740(u8 cs);
//common functions
extern int cmdline(int,char **,np_data *);
extern np_data * cmdinit();
extern int cmdexcute(np_data *);
extern int cmdexit(np_data *);
extern int nand_check_cmp(u8 *buf1,u8 *buf2,u32 len);
extern np_data * load_cfg();
#endif

5113
nandprog/include/jz4730.h Normal file

File diff suppressed because it is too large Load Diff

4525
nandprog/include/jz4740.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,89 @@
#ifndef __NAND_ECC_H__
#define __NAND_ECC_H__
#include "include.h"
// This head file define these ecc position and ecc types
struct nand_oobinfo oob_64[] =
{
{
.eccname = JZ4730CPU,
.eccbytes = 24,
.eccpos =
{
4, 5, 6,
8, 9, 10,
12,13,14,
16,17,18,
20,21,22,
24,25,26,
28,29,30,
32,33,34,
},
},
{
.eccname = LINUXHM,
.eccbytes = 24,
.eccpos =
{
41, 40, 42,
44, 43, 45,
47, 46, 48,
50, 49, 51,
53, 52, 54,
56, 55, 57,
59, 58, 60,
62, 61, 63
/* old need change position
40, 41, 42,
43, 44, 45,
46, 47, 48,
49, 50, 51,
52, 53, 54,
55, 56, 57,
58, 59, 60,
61, 62, 63
*/
},
},
{
.eccname = JZ4740CPU,
.eccbytes = 36,
.eccpos =
{
6, 7, 8, 9, 10,11,12,13,14,
15,16,17,18,19,20,21,22,23,
24,25,26,27,28,29,30,31,32,
33,34,35,36,37,38,39,40,41
},
},
{
.eccname = LINUXRS,
.eccbytes = 36,
.eccpos =
{
28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63
},
},
{ //this one must update by config file
.eccname = USERSPEC,
.eccbytes = 64,
.eccpos =
{
0, 0, 0, 0,
},
},
};
#endif

606
nandprog/jz4730/nandflash_4730.c Executable file
View File

@ -0,0 +1,606 @@
/*
* Common NAND Flash operations for JZ4730.
*
* This software is free.
*/
#include "jz4730.h"
#include "include.h"
unsigned int EMC_BASE;
extern struct nand_oobinfo oob_64[];
/*
* Standard NAND commands.
*/
#define CMD_READA 0x00
#define CMD_READB 0x01
#define CMD_READC 0x50
#define CMD_ERASE_SETUP 0x60
#define CMD_ERASE 0xD0
#define CMD_READ_STATUS 0x70
#define CMD_CONFIRM 0x30
#define CMD_SEQIN 0x80
#define CMD_PGPROG 0x10
#define CMD_READID 0x90
#define CMD_RESET 0xff
#define ECC_BLOCK 256 /* 3-bytes HW ECC per 256-bytes data */
#define ECC_OFFSET 4 /* ECC store location offset to the spare area */
/*
* NAND routines.
*/
#define nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE | EMC_NFCSR_FCE)
#define nand_disable() (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFE | EMC_NFCSR_FCE))
#define nand_ecc_enable() (REG_EMC_NFCSR |= EMC_NFCSR_ECCE | EMC_NFCSR_ERST)
#define nand_ecc_disable() (REG_EMC_NFCSR &= ~EMC_NFCSR_ECCE)
#define nand_ready() (REG_EMC_NFCSR & EMC_NFCSR_RB)
#define nand_ecc() (REG_EMC_NFECC & 0x00ffffff)
#define nand_cmd(n) (REG8(cmdport+csn) = (n))
#define nand_addr(n) (REG8(addrport+csn) = (n))
#define nand_data8() REG8(dataport+csn)
#define nand_data16() REG16(dataport+csn)
static inline void nand_wait_ready(void)
{
u32 to = 1000;
while (nand_ready() && to--);
while (!nand_ready());
}
static volatile unsigned char *emcbase = 0;
static volatile unsigned char *addrport = 0;
static volatile unsigned char *dataport = 0;
static volatile unsigned char *cmdport = 0;
static u32 bus = 8, row = 2, pagesize = 512, oobsize = 16, ppb = 32;
static u32 bad_block_pos = 0 , bad_block_page =0, csn =0;
static struct nand_oobinfo *oob_pos;
static np_data *np;
/*
* notify(int param)
*
* param value:
* 0 : Ok
* -1: page op fail
* -2: hit bad block, skip it.
*/
static int (*write_proc)(unsigned char *, int) = 0;
static int (*read_proc)(unsigned char *, int) = 0;
static u8 badbuf[2048 + 64] = {0};
static u8 oobbuf[64] = {0};
/*
* I/O read/write interface.
*/
static inline int nand_data_write8(unsigned char *buf, int count)
{
int i;
u8 *p = (u8 *)buf;
for (i = 0; i < count; i++)
nand_data8() = *p++;
return 0;
}
static inline int nand_data_write16(unsigned char *buf, int count)
{
int i;
u16 *p = (u16 *)buf;
for (i = 0; i < count/2; i++)
nand_data16() = *p++;
return 0;
}
static inline int nand_data_read8(unsigned char *buf, int count)
{
int i;
u8 *p = (u8 *)buf;
for (i = 0; i < count; i++)
*p++ = nand_data8();
return 0;
}
static inline int nand_data_read16(unsigned char *buf, int count)
{
int i;
u16 *p = (u16 *)buf;
for (i = 0; i < count/2; i++)
*p++ = nand_data16();
return 0;
}
int chip_select_4730(u8 cs)
{
csn = (u32)cs << 15; //modify this number for your board
return 0;
}
/*
* Init nand parameters and enable nand controller.
*/
int nand_init_4730(np_data *npp)
{
bus = npp->bw;
row = npp->rc;
pagesize = npp->ps;
oobsize = npp->os;
ppb = npp->ppb;
bad_block_pos = npp->bbp;
bad_block_page = npp->bba;
if (bus == 8) {
write_proc = nand_data_write8;
read_proc = nand_data_read8;
} else {
write_proc = nand_data_write16;
read_proc = nand_data_read16;
}
emcbase = (u8 *)npp->base_map;
dataport = (u8 *)npp->port_map;
addrport = (u8 *)((u32)dataport + npp->ap_offset);
cmdport = (u8 *)((u32)dataport + npp->cp_offset);
EMC_BASE = (u32)emcbase;
oob_pos = &oob_64[npp->ep];
np = npp;
nand_enable();
chip_select_4730(npp->cs);
return 0;
}
/*
* Disable nand operation.
*/
int nand_fini_4730(void)
{
nand_disable();
return 0;
}
/*
* Read ID.
*/
unsigned int nand_query_4730(void)
{
u16 vid, did;
nand_cmd(CMD_READID);
nand_addr(0);
vid = nand_data8();
did = nand_data8();
return (vid << 16) | did;
}
/*
* Read oob data for 512B pagesize.
*/
static void read_oob_512(void *buf, u32 oobsize, u32 pg)
{
int i;
u32 rowaddr;
rowaddr = pg;
nand_cmd(0x50);
nand_addr(0);
for (i = 0; i < row; i++) {
nand_addr(rowaddr & 0xff);
rowaddr >>= 8;
}
nand_wait_ready();
read_proc(buf, oobsize);
}
/*
* Read oob data for 2KB pagesize.
*/
static void read_oob_2048(u8 *buf, u32 oobsize, u32 pg)
{
u32 i, coladdr, rowaddr;
coladdr = 2048;
rowaddr = pg;
nand_cmd(CMD_READA);
nand_addr(coladdr & 0xff);
nand_addr(coladdr >> 8);
for (i = 0; i < row; i++) {
nand_addr(rowaddr & 0xff);
rowaddr >>= 8;
}
nand_cmd(CMD_CONFIRM);
nand_wait_ready();
read_proc(buf, oobsize);
}
/*
* Read oob data.
*/
static void read_oob(u8 *buf, int oobsize, int pg)
{
if (pagesize == 2048)
read_oob_2048(buf, oobsize, pg);
else
read_oob_512(buf, oobsize, pg);
}
/*
* Return 1 if the block is bad block, else return 0.
*/
int nand_check_block(u32 block)
{
u32 pg;
// pg = block * ppb;
pg = block * ppb + bad_block_page;
//bad block ID locate No.bad_block_page
read_oob(oobbuf, oobsize, pg);
if (oobbuf[bad_block_pos] != 0xff)
return -1;
read_oob(oobbuf, oobsize, pg + 1);
if (oobbuf[bad_block_pos] != 0xff)
return -1;
return 0;
}
/*
* Mark a block bad.
*/
void nand_block_markbad(u32 block)
{
u32 i, rowaddr;
for (i = 0; i < pagesize + oobsize; i++)
badbuf[i] = 0xff;
badbuf[pagesize + bad_block_pos] = 0; /* bad block flag */
rowaddr = block * ppb + bad_block_page;
//bad block ID locate No.bad_block_page
nand_cmd(CMD_READA);
nand_cmd(CMD_SEQIN);
nand_addr(0);
if (pagesize == 2048)
nand_addr(0);
for (i = 0; i < row; i++) {
nand_addr(rowaddr & 0xff);
rowaddr >>= 8;
}
write_proc((unsigned char *)badbuf, pagesize + oobsize);
nand_cmd(CMD_PGPROG);
nand_wait_ready();
}
/*
* Erase <blk_num> blocks from block <sblk>.
*/
int nand_erase_4730(int blk_num, int sblk, int force)
{
int i, cnt;
u32 cur_blk, rowaddr;
force = 0;
/* Send reset command to nand */
nand_cmd(CMD_RESET);
nand_wait_ready();
cur_blk = sblk;
cnt = 0;
while (cnt < blk_num) {
/*
* if force flag was not set, check for bad block.
* if force flag was set, erase anything.
*/
#if 1
//we do force erase for ever??
if (!force) {
if (nand_check_block(cur_blk)) {
cur_blk ++; /* Bad block, set to next block */
continue;
}
}
#endif
nand_cmd(CMD_ERASE_SETUP);
rowaddr = cur_blk * ppb;
for (i = 0; i < row; i++) {
nand_addr(rowaddr & 0xff);
rowaddr >>= 8;
}
nand_cmd(CMD_ERASE);
nand_wait_ready();
nand_cmd(CMD_READ_STATUS);
nand_wait_ready();
if (nand_data8() & 0x01) {
/* Erase Error, mark it as bad block */
nand_block_markbad(cur_blk);
} else {
/* Erase OK */
cnt++;
}
cur_blk++;
}
return 0;
}
/*
* Do nand hw ecc correction.
*/
int nand_hw_ecc_correct(u8 *buf, u8 *stored_ecc, u8 *calc_ecc, int eccblock)
{
u32 i, j, ecc_bit,a,b,c,tmp;
int res = 0;
for (i = 0; i < eccblock; i++) {
a=stored_ecc[oob_pos->eccpos[i*3+0]] ^ calc_ecc[i*4+0];
b=stored_ecc[oob_pos->eccpos[i*3+1]] ^ calc_ecc[i*4+1];
c=stored_ecc[oob_pos->eccpos[i*3+2]] ^ calc_ecc[i*4+2];
tmp = (c<<16) + (b<<8) +a;
#if 0
printf("AAAAAAAA %x %x %x : %x %x %x %x\n",
stored_ecc[oob_pos->eccpos[i*3+0]],
stored_ecc[oob_pos->eccpos[i*3+1]],
stored_ecc[oob_pos->eccpos[i*3+2]],
calc_ecc[i*4+0],
calc_ecc[i*4+1],
calc_ecc[i*4+2],
tmp);
#endif
if (tmp) { /* ECC error */
ecc_bit = 0;
for (j = 0; j < 24; j++)
if ((tmp >> j) & 0x01)
ecc_bit ++;
if (ecc_bit == 11) { /* Correctable error */
u8 idx;
ecc_bit = 0;
for (j = 12; j >= 1; j--) {
ecc_bit <<= 1;
ecc_bit |= ((tmp >> (j*2-1)) & 0x01);
}
idx = ecc_bit & 0x07;
buf[i * ECC_BLOCK + (ecc_bit >> 3)] ^= (1 << idx);
}
else { /* Fatal error */
//if ecc all ff means this page no data!
if (stored_ecc[oob_pos->eccpos[i*3+0]]==0xff
&&stored_ecc[oob_pos->eccpos[i*3+1]]==0xff
&&stored_ecc[oob_pos->eccpos[i*3+2]]==0xff )
return res;
// printf("Uncorrectable ecc error!\n");
res = -1;
}
}
}
return res;
}
/*
* Read data <pagenum> pages from <startpage> page.
* Skip bad block if detected.
* HW ECC is used.
*/
int nand_read_4730(u8 *buf, u32 startpage, u32 pagenum)
{
u32 cnt, i;
u32 cur_page, rowaddr, eccblock;
u32 calc_ecc[8];
u8 *tmpbuf,*stored_ecc;
eccblock = pagesize / ECC_BLOCK;
cur_page = startpage;
cnt = 0;
while (cnt < pagenum) {
//we do not check bad block here!
#if 0
if ((cur_page % ppb) == 0) {
cur_blk = cur_page / ppb;
if (nand_check_block(cur_blk)) {
cur_page += ppb; /* Bad block, set to next block */
continue;
}
}
#endif
nand_cmd(CMD_READA);
nand_addr(0);
if (pagesize == 2048)
nand_addr(0);
rowaddr = cur_page;
for (i = 0; i < row; i++) {
nand_addr(rowaddr & 0xff);
rowaddr >>= 8;
}
if (pagesize == 2048)
nand_cmd(CMD_CONFIRM);
nand_wait_ready();
tmpbuf = (u8 *)((u32)buf + cnt * (pagesize + oobsize));
for (i = 0; i < eccblock; i++) {
nand_ecc_enable();
read_proc(tmpbuf, ECC_BLOCK);
nand_ecc_disable();
calc_ecc[i] = nand_ecc();
if (oob_pos->eccname == LINUXHM)
calc_ecc[i] = ~(calc_ecc[i]) | 0x00030000;
tmpbuf += ECC_BLOCK;
}
read_proc((u8 *)tmpbuf, oobsize);
tmpbuf = (u8 *)((u32)buf + cnt * (pagesize + oobsize));
//read ecc from oob
stored_ecc = (u8 *)(((u32)tmpbuf) + pagesize );
/* Check ECC */
nand_hw_ecc_correct(tmpbuf, stored_ecc, (u8 *)calc_ecc, eccblock);
cur_page++;
cnt++;
}
return 0;
}
/*
* Read data <pagenum> pages from <startpage> page.
* Don't skip bad block.
* Don't use HW ECC.
*/
int nand_read_raw_4730(u8 *buf, u32 startpage, u32 pagenum)
{
u32 cnt, i;
u32 cur_page, rowaddr;
u8 *tmpbuf;
tmpbuf = (u8 *)buf;
cur_page = startpage;
cnt = 0;
while (cnt < pagenum) {
nand_cmd(CMD_READA);
nand_addr(0);
if (pagesize == 2048)
nand_addr(0);
rowaddr = cur_page;
for (i = 0; i < row; i++) {
nand_addr(rowaddr & 0xff);
rowaddr >>= 8;
}
if (pagesize == 2048)
nand_cmd(CMD_CONFIRM);
nand_wait_ready();
read_proc(tmpbuf, pagesize);
tmpbuf += pagesize;
cur_page++;
cnt++;
}
return 0;
}
/*
* Read oob <pagenum> pages from <startpage> page.
* Don't skip bad block.
* Don't use HW ECC.
*/
int nand_read_oob_4730(u8 *buf, u32 startpage, u32 pagenum)
{
u32 cnt, cur_page;
u8 *tmpbuf;
tmpbuf = (u8 *)buf;
cur_page = startpage;
cnt = 0;
while (cnt < pagenum) {
read_oob((void *)tmpbuf, oobsize, cur_page);
tmpbuf += oobsize;
cur_page++;
cnt++;
}
return 0;
}
/*
* Write <pagenum> pages from <startpage> page.
* Skip bad block if detected.
*/
int nand_program_4730(u8 *buf, int startpage, int pagenum)
{
u32 cnt, i,j;
u32 cur_page, rowaddr, eccblock;
u8 *tmpbuf;
tmpbuf = (u8 *)buf;
eccblock = pagesize / ECC_BLOCK;
cur_page = startpage;
cnt = 0;
while (cnt < pagenum) {
//do not check bad block here! check uplayer!
for (j=0;j<np->os;j++)
{
if (tmpbuf[j+np->ps]!=0xff)
break;
}
if (j==np->os)
{
tmpbuf += np->ps+np->os;
cur_page ++;
cnt ++;
continue;
}
// nand_wait_ready();
nand_cmd(CMD_READA);
nand_cmd(CMD_SEQIN);
nand_addr(0);
if (pagesize == 2048)
nand_addr(0);
rowaddr = cur_page;
for (i = 0; i < row; i++) {
nand_addr(rowaddr & 0xff);
rowaddr >>= 8;
}
/* Write out data and oob*/
// we don't need work out ecc
//because it already exist in image file
write_proc(tmpbuf, np->ps+np->os);
tmpbuf += np->ps+np->os;
nand_cmd(CMD_PGPROG);
nand_wait_ready();
nand_cmd(CMD_READ_STATUS);
// nand_wait_ready();
if (nand_data8() & 0x01) {
/* Page program error.
* Note: we should mark this block bad, and copy data of this
* block to a new block.
*/
;
} else {
;
}
cur_page ++;
cnt ++;
}
return cnt;
}

734
nandprog/jz4740/nandflash_4740.c Executable file
View File

@ -0,0 +1,734 @@
/*
* Common NAND Flash operations for JZ4740.
*
* This software is free.
*/
#include "jz4740.h"
#include "include.h"
extern struct nand_oobinfo oob_64[];
#define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1)
#define __nand_disable() (REG_EMC_NFCSR &= ~(EMC_NFCSR_NFCE1|EMC_NFCSR_NFE1 ))
#define __nand_ecc_rs_encoding() (REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST | EMC_NFECR_RS | EMC_NFECR_RS_ENCODING)
#define __nand_ecc_rs_decoding() (REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST | EMC_NFECR_RS | EMC_NFECR_RS_DECODING)
#define __nand_ecc_disable() (REG_EMC_NFECR &= ~EMC_NFECR_ECCE)
#define __nand_ecc_encode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_ENCF))
#define __nand_ecc_decode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_DECF))
#define __nand_ecc_enable() (REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST )
#define __nand_ecc_disable() (REG_EMC_NFECR &= ~EMC_NFECR_ECCE)
#define __nand_select_hm_ecc() (REG_EMC_NFECR &= ~EMC_NFECR_RS )
#define __nand_select_rs_ecc() (REG_EMC_NFECR |= EMC_NFECR_RS)
#define __nand_read_hm_ecc() (REG_EMC_NFECC & 0x00ffffff)
#define __nand_ecc() (REG_EMC_NFECC & 0x00ffffff)
#define __nand_cmd(n) (REG8(cmdport+csn) = (n))
#define __nand_addr(n) (REG8(addrport+csn) = (n))
#define __nand_data8() REG8(dataport+csn)
#define __nand_data16() REG16(dataport+csn)
#define CMD_READA 0x00
#define CMD_READB 0x01
#define CMD_READC 0x50
#define CMD_ERASE_SETUP 0x60
#define CMD_ERASE 0xD0
#define CMD_READ_STATUS 0x70
#define CMD_CONFIRM 0x30
#define CMD_SEQIN 0x80
#define CMD_PGPROG 0x10
#define CMD_READID 0x90
#define OOB_BAD_OFF 0x00
#define OOB_ECC_OFF 0x04
#define OP_ERASE 0
#define OP_WRITE 1
#define OP_READ 2
#define ECC_BLOCK 512
#define ECC_POS 6
#define PAR_SIZE 9
static volatile unsigned char *gpio_base;
static volatile unsigned char *emc_base;
static volatile unsigned char *addrport;
static volatile unsigned char *dataport;
static volatile unsigned char *cmdport;
unsigned int EMC_BASE;
unsigned int GPIO_BASE;
static int bus = 8, row = 2, pagesize = 512, oobsize = 16, ppb = 32;
static u32 bad_block_pos = 0,bad_block_page=0, csn = 0;
static u8 badbuf[2048 + 64] = {0};
static u8 data_buf[2048] = {0};
static u8 oob_buf[128] = {0};
static struct nand_oobinfo *oob_pos;
static np_data *np;
static inline void __nand_sync(void)
{
unsigned int timeout = 1000;
while ((REG_GPIO_PXPIN(2) & 0x40000000) && timeout--);
while (!(REG_GPIO_PXPIN(2) & 0x40000000));
}
static int read_oob(u8 *buf, u32 size, u32 pg);
static int nand_data_write8(unsigned char *buf, int count);
static int nand_data_write16(unsigned char *buf, int count);
static int nand_data_read8(unsigned char *buf, int count);
static int nand_data_read16(unsigned char *buf, int count);
static int (*write_proc)(unsigned char *, int) = 0;
static int (*read_proc)(unsigned char *, int) = 0;
extern void dumpbuf(u8 *p, int count);
unsigned int nand_query_4740(void)
{
u16 vid, did;
__nand_sync();
__nand_cmd(CMD_READID);
__nand_addr(0);
vid = __nand_data8();
did = __nand_data8();
return (vid << 16) | did;
}
int chip_select_4740(u8 cs)
{
csn = (u32)cs << 15; // modify this number for your board
return 0;
}
int nand_init_4740(np_data *npp)
{
bus = npp->bw;
row = npp->rc;
pagesize = npp->ps;
oobsize = npp->os;
ppb = npp->ppb;
bad_block_pos = npp->bbp;
bad_block_page = npp->bba;
gpio_base = (u8 *)npp->gpio_map;
emc_base = (u8 *)npp->base_map;
dataport = (u8 *)npp->port_map;
addrport = (u8 *)((u32)dataport + npp->ap_offset);
cmdport = (u8 *)((u32)dataport + npp->cp_offset);
EMC_BASE = (u32)emc_base;
GPIO_BASE = (u32)gpio_base;
/* Initialize NAND Flash Pins */
// __gpio_as_nand();
// __nand_enable();
chip_select_4740(npp->cs);
if (bus == 8) {
write_proc = nand_data_write8;
read_proc = nand_data_read8;
} else {
write_proc = nand_data_write16;
read_proc = nand_data_read16;
}
oob_pos = &oob_64[npp->ep];
// REG_EMC_SMCR1 = 0x0fff7700;
np = npp;
return 0;
}
int nand_fini_4740(void)
{
__nand_disable();
return 0;
}
/*
* Read oob <pagenum> pages from <startpage> page.
* Don't skip bad block.
* Don't use HW ECC.
*/
int nand_read_oob_4740(u8 *buf, u32 startpage, u32 pagenum)
{
u32 cnt, cur_page;
u8 *tmpbuf;
tmpbuf = (u8 *)buf;
cur_page = startpage;
cnt = 0;
while (cnt < pagenum) {
read_oob((void *)tmpbuf, oobsize, cur_page);
tmpbuf += oobsize;
cur_page++;
cnt++;
}
return 0;
}
int nand_check_block_4740(u32 block)
{
u32 pg;
pg = block * ppb + bad_block_page;
read_oob(oob_buf, oobsize, pg);
if (oob_buf[bad_block_pos] != 0xff)
return -1;
read_oob(oob_buf, oobsize, pg + 1);
if (oob_buf[bad_block_pos] != 0xff)
return -1;
return 0;
}
/*
* Mark a block bad.
*/
void nand_block_markbad_4740(u32 block)
{
u32 i, rowaddr;
for (i = 0; i < pagesize + oobsize; i++)
badbuf[i] = 0x00;
badbuf[pagesize + bad_block_pos] = 0; /* bad block flag */
rowaddr = block * ppb + bad_block_page;
//bad block ID locate No.bad_block_page page
__nand_cmd(CMD_READA);
__nand_cmd(CMD_SEQIN);
__nand_addr(0);
if (pagesize == 2048)
__nand_addr(0);
for (i = 0; i < row; i++) {
__nand_addr(rowaddr & 0xff);
rowaddr >>= 8;
}
write_proc((unsigned char *)badbuf, pagesize + oobsize);
__nand_cmd(CMD_PGPROG);
__nand_sync();
}
/*
* Read data <pagenum> pages from <startpage> page.
* Don't skip bad block.
* Don't use HW ECC.
*/
int nand_read_raw_4740(u8 *buf, u32 startpage, u32 pagenum)
{
u32 cnt, j;
u32 cur_page, rowaddr;
u8 *tmpbuf;
tmpbuf = (u8 *)buf;
cur_page = startpage;
cnt = 0;
while (cnt < pagenum) {
__nand_sync();
__nand_cmd(CMD_READA);
__nand_addr(0);
if (pagesize == 2048)
__nand_addr(0);
rowaddr = cur_page;
for (j = 0; j < row; j++) {
__nand_addr(rowaddr & 0xff);
rowaddr >>= 8;
}
if (pagesize == 2048)
__nand_cmd(CMD_CONFIRM);
__nand_sync();
read_proc(tmpbuf, pagesize);
tmpbuf += pagesize;
cur_page++;
cnt++;
}
return 0;
}
int nand_erase_4740(int blk_num, int sblk, int force)
{
int i, j;
u32 cur, rowaddr;
cur = sblk * ppb;
for (i = 0; i < blk_num; i++) {
rowaddr = cur;
if (!force) { /* if set, erase anything */
/* test Badflag. */
__nand_sync();
__nand_cmd(CMD_READA);
__nand_addr(0);
if (pagesize == 2048)
__nand_addr(0);
for (j=0;j<row;j++) {
__nand_addr(rowaddr & 0xff);
rowaddr >>= 8;
}
if (pagesize == 2048)
__nand_cmd(CMD_CONFIRM);
__nand_sync();
read_proc((u8 *)data_buf, pagesize);
read_proc((u8 *)oob_buf, oobsize);
if (oob_buf[0] != 0xff) { /* Bad block, skip */
cur += ppb;
continue;
}
rowaddr = cur;
}
__nand_cmd(CMD_ERASE_SETUP);
for (j = 0; j < row; j++) {
__nand_addr(rowaddr & 0xff);
rowaddr >>= 8;
}
__nand_cmd(CMD_ERASE);
__nand_sync();
__nand_cmd(CMD_READ_STATUS);
if (__nand_data8() & 0x01)
{
/* Erase Error, mark it as bad block */
nand_block_markbad(cur);
} else ;
cur += ppb;
}
return 0;
}
static int read_oob(u8 *buf, u32 size, u32 pg)
{
u32 i, coladdr, rowaddr;
if (pagesize == 512)
coladdr = 0;
else
coladdr = pagesize;
if (pagesize == 512)
/* Send READOOB command */
__nand_cmd(CMD_READC);
else
/* Send READ0 command */
__nand_cmd(CMD_READA);
/* Send column address */
__nand_addr(coladdr & 0xff);
if (pagesize != 512)
__nand_addr(coladdr >> 8);
/* Send page address */
rowaddr = pg;
for (i = 0; i < row; i++) {
__nand_addr(rowaddr & 0xff);
rowaddr >>= 8;
}
/* Send READSTART command for 2048 ps NAND */
if (pagesize != 512)
__nand_cmd(CMD_CONFIRM);
/* Wait for device ready */
__nand_sync();
/* Read oob data */
read_proc(buf, size);
return 0;
}
/* Correct 1~9-bit errors in 512-bytes data */
static void rs_correct(unsigned char *dat, int idx, int mask)
{
int i;
idx--;
i = idx + (idx >> 3);
if (i >= 512)
return;
mask <<= (idx & 0x7);
dat[i] ^= mask & 0xff;
if (i < 511)
dat[i+1] ^= (mask >> 8) & 0xff;
}
static int nand_hm_correct_data(u8 *dat, u8 *oob_s, u8 *calc_ecc,u8 p)
{
u8 a, b, c, d1, d2, d3, add, bit, i;
u8 *e1,*e2,*e3;
e1 = &oob_s[oob_pos->eccpos[p+0]];
e2 = &oob_s[oob_pos->eccpos[p+1]];
e3 = &oob_s[oob_pos->eccpos[p+2]];
// printf("read ecc :%x %x %x %d %d\n",*e1,*e2,*e3,
// oob_pos->eccpos[p+0],oob_pos->eccpos[p+1]);
d1 = calc_ecc[0] ^ *e1;
d2 = calc_ecc[1] ^ *e2;
d3 = calc_ecc[2] ^ *e3;
if ((d1 | d2 | d3) == 0) {
/* No errors */
return 0;
}
else {
a = (d1 ^ (d1 >> 1)) & 0x55;
b = (d2 ^ (d2 >> 1)) & 0x55;
c = (d3 ^ (d3 >> 1)) & 0x54;
/* Found and will correct single bit error in the data */
if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
c = 0x80;
add = 0;
a = 0x80;
for (i=0; i<4; i++) {
if (d1 & c)
add |= a;
c >>= 2;
a >>= 1;
}
c = 0x80;
for (i=0; i<4; i++) {
if (d2 & c)
add |= a;
c >>= 2;
a >>= 1;
}
bit = 0;
b = 0x04;
c = 0x80;
for (i=0; i<3; i++) {
if (d3 & c)
bit |= b;
c >>= 2;
b >>= 1;
}
b = 0x01;
a = dat[add];
a ^= (b << bit);
dat[add] = a;
return 0;
}
else {
i = 0;
while (d1) {
if (d1 & 0x01)
++i;
d1 >>= 1;
}
while (d2) {
if (d2 & 0x01)
++i;
d2 >>= 1;
}
while (d3) {
if (d3 & 0x01)
++i;
d3 >>= 1;
}
if (i == 1) {
/* ECC Code Error Correction */
*e1 = calc_ecc[0];
*e2 = calc_ecc[1];
*e3 = calc_ecc[2];
return 0;
}
else {
/* Uncorrectable Error */
// printf("uncorrectable ECC error\n");
return -1;
}
}
}
/* Should never happen */
return -1;
}
/*
* Read data <pagenum> pages from <startpage> page.
* HW ECC is used.
*/
int nand_read_4740_hm(u8 *buf, u32 startpage, u32 pagenum)
{
u32 j, calc_ecc;
u32 cur_page, cnt, rowaddr, ecccnt;
u8 *tmpbuf;
ecccnt = pagesize / 256;
cur_page = startpage;
cnt = 0;
while (cnt < pagenum) {
/* read oob first */
read_oob(oob_buf, oobsize, cur_page);
__nand_sync();
__nand_cmd(CMD_READA);
__nand_addr(0);
if (pagesize == 2048)
__nand_addr(0);
rowaddr = cur_page;
for (j = 0; j < row; j++) {
__nand_addr(rowaddr & 0xff);
rowaddr >>= 8;
}
if (pagesize == 2048)
__nand_cmd(CMD_CONFIRM);
__nand_sync();
tmpbuf = (u8 *)((u32)buf + cnt * ( pagesize+oobsize));
for (j = 0; j < ecccnt ; j++)
{
__nand_ecc_enable();
__nand_select_hm_ecc();
read_proc(tmpbuf, 256);
__nand_ecc_disable();
calc_ecc = __nand_read_hm_ecc();
if (oob_pos->eccname == LINUXHM)
calc_ecc = ~calc_ecc | 0x00030000;
nand_hm_correct_data(tmpbuf,oob_buf,(u8*)&calc_ecc,j*3);
tmpbuf += 256;
}
for (j = 0; j < oobsize; j++)
tmpbuf[j] = oob_buf[j];
cur_page++;
cnt++;
}
return 0;
}
/*
* Read data <pagenum> pages from <startpage> page.
* HW ECC is used.
*/
int nand_read_4740_rs(u8 *buf, u32 startpage, u32 pagenum)
{
u32 j, k;
u32 cur_page, cnt, rowaddr, ecccnt;
u8 *tmpbuf;
ecccnt = pagesize / ECC_BLOCK;
cur_page = startpage;
cnt = 0;
while (cnt < pagenum) {
/* read oob first */
read_oob(oob_buf, oobsize, cur_page);
__nand_sync();
__nand_cmd(CMD_READA);
__nand_addr(0);
if (pagesize == 2048)
__nand_addr(0);
rowaddr = cur_page;
for (j = 0; j < row; j++) {
__nand_addr(rowaddr & 0xff);
rowaddr >>= 8;
}
if (pagesize == 2048)
__nand_cmd(CMD_CONFIRM);
__nand_sync();
tmpbuf = (u8 *)((u32)buf + cnt * ( pagesize+oobsize));
for (j = 0; j < ecccnt ; j++) {
volatile u8 *paraddr = (volatile u8 *)EMC_NFPAR0;
u32 stat;
/* Read data */
REG_EMC_NFINTS = 0x0;
__nand_ecc_rs_decoding();
read_proc(tmpbuf, ECC_BLOCK);
/* Set PAR values */
for (k = 0; k < PAR_SIZE; k++) {
*paraddr++ = oob_buf[oob_pos->eccpos[j*PAR_SIZE + k]];
}
/* Set PRDY */
REG_EMC_NFECR |= EMC_NFECR_PRDY;
/* Wait for completion */
__nand_ecc_decode_sync();
__nand_ecc_disable();
/* Check decoding */
stat = REG_EMC_NFINTS;
if (stat & EMC_NFINTS_ERR) {
// printf("Error occured!\n");
if (stat & EMC_NFINTS_UNCOR) {
int t;
for (t = 0; t < oob_pos->eccbytes; t++)
if (oob_buf[oob_pos->eccpos[t]] != 0xff) break;
if (t < oob_pos->eccbytes-1) {
// printf("Uncorrectable error occurred\n");
}
}
else {
u32 errcnt = (stat & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT;
switch (errcnt) {
case 4:
rs_correct(tmpbuf, (REG_EMC_NFERR3 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR3 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT);
case 3:
rs_correct(tmpbuf, (REG_EMC_NFERR2 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR2 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT);
case 2:
rs_correct(tmpbuf, (REG_EMC_NFERR1 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR1 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT);
case 1:
rs_correct(tmpbuf, (REG_EMC_NFERR0 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR0 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT);
break;
default:
break;
}
}
}
/* increment pointer */
tmpbuf += ECC_BLOCK ;
}
for (j = 0; j < oobsize; j++)
tmpbuf[j] = oob_buf[j];
cur_page++;
cnt++;
}
return 0;
}
int nand_program_4740(u8 *context, int spage, int pages)
{
u32 i, j, cur, rowaddr;
u8 *tmpbuf;
tmpbuf = (u8 *)context;
i = 0;
cur = spage;
while (i < pages) {
for (j=0;j<np->os;j++)
{
if (tmpbuf[j+np->ps]!=0xff)
break;
}
if (j==np->os)
{
tmpbuf += np->ps+np->os;
i ++;
cur ++;
continue;
}
if (pagesize != 2048)
__nand_cmd(CMD_READA);
__nand_cmd(CMD_SEQIN);
__nand_addr(0);
if (pagesize == 2048)
__nand_addr(0);
rowaddr = cur;
for (j = 0; j < row; j++) {
__nand_addr(rowaddr & 0xff);
rowaddr >>= 8;
}
write_proc(tmpbuf, np->ps+np->os);
tmpbuf += np->ps+np->os;
/* send program confirm command */
__nand_cmd(CMD_PGPROG);
__nand_sync();
__nand_cmd(CMD_READ_STATUS);
// __nand_sync();
if (__nand_data8() & 0x01) { /* page program error */
return -1;
} else ;
i ++;
cur ++;
}
return 0;
}
static int nand_data_write8(unsigned char *buf, int count)
{
int i;
u8 *p = (u8 *)buf;
for (i=0;i<count;i++)
__nand_data8() = *p++;
return 0;
}
static int nand_data_write16(unsigned char *buf, int count)
{
int i;
u16 *p = (u16 *)buf;
for (i=0;i<count/2;i++)
__nand_data16() = *p++;
return 0;
}
static int nand_data_read8(unsigned char *buf, int count)
{
int i;
u8 *p = (u8 *)buf;
for (i=0;i<count;i++)
*p++ = __nand_data8();
return 0;
}
static int nand_data_read16(unsigned char *buf, int count)
{
int i;
u16 *p = (u16 *)buf;
for (i=0;i<count/2;i++)
*p++ = __nand_data16();
return 0;
}