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

📄 nandflash_4730.c

📁 nand flash烧写源代码
💻 C
字号:
/* * 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.I/0读写操作接口(8位)  */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;}/*  * I/O read/write interface.I/0读写操作接口(16位)  */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.4730初始化  */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.关闭4730  */int nand_fini_4730(void){	nand_disable();	return 0;}/* * Read ID.读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.ECC校验  */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;}

⌨️ 快捷键说明

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