mirror of
git://projects.qi-hardware.com/xburst-tools.git
synced 2024-11-29 10:50:39 +02:00
add nand flash tools
This commit is contained in:
parent
e043feab69
commit
5c31ed05b7
37
nandprog/Makefile
Normal file
37
nandprog/Makefile
Normal 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
30
nandprog/README
Normal 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
605
nandprog/common/cmdline.c
Normal 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
214
nandprog/common/loadcfg.c
Normal 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
23
nandprog/common/main.c
Normal 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
406
nandprog/include/configs.h
Normal 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
140
nandprog/include/include.h
Normal 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
5113
nandprog/include/jz4730.h
Normal file
File diff suppressed because it is too large
Load Diff
4525
nandprog/include/jz4740.h
Normal file
4525
nandprog/include/jz4740.h
Normal file
File diff suppressed because it is too large
Load Diff
89
nandprog/include/nand_ecc.h
Normal file
89
nandprog/include/nand_ecc.h
Normal 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
606
nandprog/jz4730/nandflash_4730.c
Executable 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
734
nandprog/jz4740/nandflash_4740.c
Executable 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user