mirror of
https://github.com/torvalds/linux.git
synced 2026-06-08 14:42:37 +02:00
update yaffs2 nand according to raho project
This commit is contained in:
parent
43e3beb4e9
commit
33c55e5813
|
|
@ -1191,8 +1191,15 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
|||
else
|
||||
ret = chip->ecc.read_page(mtd, chip, bufpoi,
|
||||
page);
|
||||
#ifdef CONFIG_MTD_NAND_RK29
|
||||
extern int rk29_nand_refresh(struct mtd_info *mtd, int srcAddr);
|
||||
if(ret == -1)
|
||||
ret=rk29_nand_refresh(mtd, page<<chip->page_shift);
|
||||
#endif
|
||||
if (ret < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Transfer not aligned data */
|
||||
if (!aligned) {
|
||||
|
|
|
|||
|
|
@ -1004,6 +1004,10 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
|||
if (md)
|
||||
mark_bbt_region(mtd, md);
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_RK29
|
||||
extern void mark_reserve_region(struct mtd_info *mtd,struct nand_bbt_descr *td,struct nand_bbt_descr *md);
|
||||
mark_reserve_region(mtd, td, md);
|
||||
#endif
|
||||
vfree(buf);
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,13 @@
|
|||
|
||||
/* Define delays in microsec for NAND device operations */
|
||||
#define TROP_US_DELAY 2000
|
||||
#define NAND_FLAG_WRITE 1
|
||||
|
||||
#if 1
|
||||
#define FLASH_DEBUG(x...) do{printk(x);}while(0)
|
||||
#else
|
||||
#define FLASH_DEBUG(s,x...)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DM9000_USE_NAND_CONTROL
|
||||
static DEFINE_MUTEX(rknand_mutex);
|
||||
|
|
@ -69,6 +75,8 @@ struct rk29_nand_mtd {
|
|||
#endif
|
||||
|
||||
};
|
||||
static int read_in_refresh = 0;
|
||||
static int gbRefresh = 0;
|
||||
|
||||
/* OOB placement block for use with software ecc generation */
|
||||
static struct nand_ecclayout nand_sw_eccoob_8 = {
|
||||
|
|
@ -169,7 +177,397 @@ static int rk29_nand_dev_ready(struct mtd_info *mtd)
|
|||
else
|
||||
return 0;
|
||||
}
|
||||
void mark_reserve_region(struct mtd_info *mtd,struct nand_bbt_descr *td,struct nand_bbt_descr *md)
|
||||
{
|
||||
int i, block, nrblocks, tdblock, update = 0;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
uint8_t oldval, newval;
|
||||
|
||||
tdblock = (td->maxblocks >= md->maxblocks)?td->maxblocks:md->maxblocks;
|
||||
nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
|
||||
block = nrblocks - tdblock - RK29_RESERVE_BLOCK_NUM;
|
||||
block <<= 1;
|
||||
|
||||
for(i=0; i<RK29_RESERVE_BLOCK_NUM; i++) {
|
||||
oldval = this->bbt[(block>>3)];
|
||||
newval = oldval|(0x2 << (block & 0x06));
|
||||
this->bbt[(block>>3)] = newval;
|
||||
if (oldval != newval)
|
||||
update = 1;
|
||||
block += 2;
|
||||
}
|
||||
|
||||
if(update&&td->reserved_block_code)
|
||||
{
|
||||
printk("mark_reserve_region need update!\n");
|
||||
nand_update_bbt(mtd, (loff_t)(block - 2) <<
|
||||
(this->bbt_erase_shift - 1));
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(mark_reserve_region);
|
||||
|
||||
static int rk29_nand_erase(struct mtd_info *mtd, int srcAddr)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
int status;
|
||||
|
||||
//printk(">>>>>>> erase page [%d]\n", srcAddr>>this->page_shift);
|
||||
this->select_chip(mtd, 0);
|
||||
this->cmdfunc(mtd, NAND_CMD_ERASE1, -1, srcAddr>>this->page_shift);
|
||||
this->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
|
||||
status = this->waitfunc(mtd, this);
|
||||
if(status&NAND_STATUS_FAIL){
|
||||
FLASH_DEBUG("%s: %s erase failed!\n", __FILE__,__FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk29_get_swap_block_erased(struct mtd_info *mtd, int bdown)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_bbt_descr *td = this->bbt_td;
|
||||
struct nand_bbt_descr *md = this->bbt_md;
|
||||
int nrblocks, block, tdblock, startblock, i, fward;
|
||||
|
||||
tdblock = (td->maxblocks > md->maxblocks)?td->maxblocks:md->maxblocks;
|
||||
nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
|
||||
if(bdown){
|
||||
startblock = nrblocks-tdblock-1;
|
||||
fward = -1;
|
||||
}
|
||||
else{
|
||||
startblock = nrblocks-tdblock-RK29_RESERVE_BLOCK_NUM;
|
||||
fward = 1;
|
||||
}
|
||||
|
||||
for(i=0; i<RK29_RESERVE_BLOCK_NUM; i++){
|
||||
block = startblock + fward*i;
|
||||
if(((this->bbt[block>>2]>>(2*(block & 0x03)))&0x03)==0x02){
|
||||
if(rk29_nand_erase(mtd, block<<this->phys_erase_shift)){
|
||||
mtd->block_markbad(mtd, block<<this->phys_erase_shift);
|
||||
FLASH_DEBUG("%s: %s erase failed!\n", __FILE__,__FUNCTION__);
|
||||
}
|
||||
else{
|
||||
return block<<this->phys_erase_shift;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk29_block_copy(struct mtd_info *mtd, int srcAddr, int dstAddr, int bSetFlag)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
uint8_t *buf=(uint8_t*)kmalloc(mtd->writesize+32, GFP_KERNEL);
|
||||
int i,status,pagePblock,src_page,dst_page,src_block;
|
||||
u_char oob[4], oob_bak[4];
|
||||
|
||||
if(!buf){
|
||||
printk("%s:kmalloc failed!\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pagePblock = mtd->erasesize/mtd->writesize;
|
||||
src_page = srcAddr>>this->page_shift;
|
||||
src_block = srcAddr>>this->phys_erase_shift;
|
||||
dst_page = dstAddr>>this->page_shift;
|
||||
|
||||
memcpy(oob_bak, (u_char *)(this->oob_poi + this->ops.ooboffs),4);
|
||||
if(bSetFlag){
|
||||
uint8_t block_1_8, block_2_8;
|
||||
|
||||
if(src_block >= 65535){
|
||||
printk("block num err\n");
|
||||
kfree(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
block_1_8 = src_block&0xFF;
|
||||
block_2_8 = (src_block>>8)&0xFF;
|
||||
|
||||
oob[0]='S';
|
||||
oob[1]='W';
|
||||
oob[2]=block_1_8;
|
||||
oob[3]=block_2_8;
|
||||
}
|
||||
else{
|
||||
oob[0]=0xFF;
|
||||
oob[1]=0xFF;
|
||||
oob[2]=0xFF;
|
||||
oob[3]=0xFF;
|
||||
}
|
||||
memcpy((u_char *)(this->oob_poi + this->ops.ooboffs),(u_char *)oob,4);
|
||||
|
||||
this->select_chip(mtd, 0);
|
||||
for(i=0;i<pagePblock;i++){
|
||||
this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, src_page);
|
||||
status = this->ecc.read_page(mtd, this, buf, src_page);
|
||||
if(status==-2){
|
||||
FLASH_DEBUG("%s: %s read_page failed status=[%d]!\n", __FILE__,__FUNCTION__, status);
|
||||
kfree(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
this->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, dst_page);
|
||||
this->ecc.write_page_raw(mtd, this, buf);
|
||||
this->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
|
||||
status = this->waitfunc(mtd, this);
|
||||
if(status&NAND_STATUS_FAIL){
|
||||
FLASH_DEBUG("%s: %s write_page failed status=[%d]!\n", __FILE__,__FUNCTION__, status);
|
||||
kfree(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
src_page++;
|
||||
dst_page++;
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
memcpy((u_char *)(this->oob_poi + this->ops.ooboffs), oob_bak, 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if NAND_FLAG_WRITE
|
||||
static int rk29_flag_check(struct mtd_info *mtd, uint8_t *buf)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(buf[0] == 'R' && buf[1] == 'K'
|
||||
&& buf[2] == '2' && buf[3] == '9'
|
||||
&& buf[4] == '1' && buf[5] == '8')
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else{
|
||||
for(i=0;i<mtd->writesize;i++){
|
||||
if(buf[i]!=0xFF)
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int rk29_get_flag_page(struct mtd_info *mtd, int bdown)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
struct nand_bbt_descr *td = this->bbt_td;
|
||||
struct nand_bbt_descr *md = this->bbt_md;
|
||||
int nrblocks, block, tdblock, startblock, i, status, fward, j, src_page, pageState;
|
||||
uint8_t *buf=(uint8_t*)kmalloc(mtd->writesize+32, GFP_KERNEL);
|
||||
|
||||
if(!buf){
|
||||
printk("%s:kmalloc failed!\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tdblock = (td->maxblocks > md->maxblocks)?td->maxblocks:md->maxblocks;
|
||||
nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
|
||||
if(bdown){
|
||||
startblock = nrblocks-tdblock-1;
|
||||
fward = -1;
|
||||
}
|
||||
else{
|
||||
startblock = nrblocks-tdblock-RK29_RESERVE_BLOCK_NUM;
|
||||
fward = 1;
|
||||
}
|
||||
this->select_chip(mtd, 0);
|
||||
for(i=0; i<RK29_RESERVE_BLOCK_NUM - 3; i++){
|
||||
block = startblock + fward*i;
|
||||
if(((this->bbt[block>>2]>>(2*(block & 0x03)))&0x03)==0x02){
|
||||
for(j=0; j<(1<<(this->phys_erase_shift-this->page_shift)); j++){
|
||||
src_page = (block<<(this->phys_erase_shift-this->page_shift))+j;
|
||||
this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, src_page);
|
||||
status = this->ecc.read_page_raw(mtd, this, buf, src_page);
|
||||
if(status==-2){
|
||||
FLASH_DEBUG("%s: %s read_page failed status=[%d]!\n", __FILE__,__FUNCTION__, status);
|
||||
kfree(buf);
|
||||
return 0;
|
||||
}
|
||||
if(j==0){
|
||||
u_char oob[4];
|
||||
memcpy(oob, (u_char *)(this->oob_poi + this->ops.ooboffs),4);
|
||||
if((oob[0]!='R')||(oob[1]!='K')||(oob[2]!='F')||(oob[3]!='G')){
|
||||
if(rk29_nand_erase(mtd, block<<this->phys_erase_shift)){
|
||||
mtd->block_markbad(mtd, block<<this->phys_erase_shift);
|
||||
break;
|
||||
}
|
||||
//printk("get a free block [%d]!\n", block);
|
||||
}
|
||||
this->cmdfunc(mtd, NAND_CMD_READ0, 0x00, src_page);
|
||||
status = this->ecc.read_page_raw(mtd, this, buf, src_page);
|
||||
if(status==-2){
|
||||
FLASH_DEBUG("%s: %s read_page failed status=[%d]!\n", __FILE__,__FUNCTION__, status);
|
||||
kfree(buf);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
pageState = rk29_flag_check(mtd, buf);
|
||||
//printk("src_page = [%d] pageState = [%d]\n", src_page, pageState);
|
||||
if(pageState == 0){
|
||||
continue;
|
||||
}
|
||||
else if(pageState == 1){
|
||||
if(rk29_nand_erase(mtd, block<<this->phys_erase_shift)){
|
||||
mtd->block_markbad(mtd, block<<this->phys_erase_shift);
|
||||
break;
|
||||
}
|
||||
kfree(buf);
|
||||
//printk("rk29_get_flag_page: block<<(this->phys_erase_shift-this->page_shift = [%d]\n", block<<(this->phys_erase_shift-this->page_shift));
|
||||
return block<<(this->phys_erase_shift-this->page_shift);
|
||||
}
|
||||
else{
|
||||
kfree(buf);
|
||||
//printk("rk29_get_flag_page: src_page = [%d]\n", src_page);
|
||||
return src_page;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
kfree(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk29_nand_refresh_flag(struct mtd_info *mtd, int srcAddr, int swapAddr)
|
||||
{
|
||||
int flagAddr, status;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
uint8_t *buf=(uint8_t*)kmalloc(mtd->writesize+32, GFP_KERNEL);
|
||||
u_char oob[4];
|
||||
|
||||
if(!buf){
|
||||
printk("%s:kmalloc failed!\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
flagAddr = rk29_get_flag_page(mtd, 1);
|
||||
if(flagAddr){
|
||||
buf[0] = 'R';
|
||||
buf[1] = 'K';
|
||||
buf[2] = '2';
|
||||
buf[3] = '9';
|
||||
buf[4] = '1';
|
||||
buf[5] = '8';
|
||||
buf[6] = (uint8_t)(srcAddr&0xFF);
|
||||
buf[7] = (uint8_t)((srcAddr>>8)&0xFF);
|
||||
buf[8] = (uint8_t)((srcAddr>>16)&0xFF);
|
||||
buf[9] = (uint8_t)((srcAddr>>24)&0xFF);
|
||||
memset(&buf[10], 0x88, mtd->writesize-10);
|
||||
|
||||
oob[0]='R';
|
||||
oob[1]='K';
|
||||
oob[2]='F';
|
||||
oob[3]='G';
|
||||
memcpy((u_char *)(this->oob_poi + this->ops.ooboffs),oob,4);
|
||||
|
||||
this->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, flagAddr);
|
||||
this->ecc.write_page_raw(mtd, this, buf);
|
||||
this->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
|
||||
status = this->waitfunc(mtd, this);
|
||||
if(status&NAND_STATUS_FAIL){
|
||||
FLASH_DEBUG("%s: %s write_page failed status=[%d]!\n", __FILE__,__FUNCTION__, status);
|
||||
kfree(buf);
|
||||
return -1;
|
||||
}
|
||||
//printk("rk29_nand_refresh_flag: page = [%d]\n", flagAddr);
|
||||
}
|
||||
kfree(buf);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int rk29_nand_refresh(struct mtd_info *mtd, int srcAddr)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
int swapAddr;
|
||||
int ret = 0;
|
||||
|
||||
if(!gbRefresh){
|
||||
printk("bbt is not ready!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
srcAddr = (srcAddr>>this->phys_erase_shift)<<this->phys_erase_shift;
|
||||
|
||||
swapAddr = rk29_get_swap_block_erased(mtd, 0);
|
||||
printk("%s swapAddr[%d] srcAddr[%d]\n", __FUNCTION__, swapAddr, srcAddr);
|
||||
|
||||
#if NAND_FLAG_WRITE
|
||||
rk29_nand_refresh_flag(mtd, srcAddr, swapAddr);
|
||||
#endif
|
||||
|
||||
read_in_refresh = 1;
|
||||
if(!swapAddr){
|
||||
printk("no swap block fined!!!\n");
|
||||
ret = -1;
|
||||
goto nand_refresh_error;
|
||||
}
|
||||
|
||||
if(rk29_nand_erase(mtd, swapAddr)){
|
||||
printk("rk29_nand_erase[0x%x] failed!\n", srcAddr);
|
||||
ret = -1;
|
||||
goto nand_refresh_error;
|
||||
}
|
||||
|
||||
if(rk29_block_copy(mtd, srcAddr, swapAddr, 1)){
|
||||
printk("rk29_block_copy[0x%x ---> 0x%x] failed!\n", srcAddr, swapAddr);
|
||||
ret = -1;
|
||||
goto nand_refresh_error;
|
||||
}
|
||||
|
||||
if(rk29_nand_erase(mtd, srcAddr)){
|
||||
printk("rk29_nand_erase[0x%x] failed!\n", srcAddr);
|
||||
ret = -1;
|
||||
goto nand_refresh_error;
|
||||
}
|
||||
|
||||
if(rk29_block_copy(mtd, swapAddr, srcAddr, 0)){
|
||||
printk("rk29_block_copy[0x%x ---> 0x%x] failed!\n", swapAddr, srcAddr);
|
||||
ret = -1;
|
||||
goto nand_refresh_error;
|
||||
}
|
||||
if(rk29_nand_erase(mtd, swapAddr)){
|
||||
printk("rk29_nand_erase[0x%x] failed!\n", srcAddr);
|
||||
ret = -1;
|
||||
goto nand_refresh_error;
|
||||
}
|
||||
nand_refresh_error:
|
||||
read_in_refresh = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(rk29_nand_refresh);
|
||||
|
||||
|
||||
static int rk29_nand_check_hwecc(struct mtd_info *mtd, int page)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct rk29_nand_mtd *master = nand_chip->priv;
|
||||
pNANDC pRK29NC= (pNANDC)(master->regs);
|
||||
|
||||
if((pRK29NC->BCHST[0]&0x1) && (pRK29NC->BCHST[0]&0x4))
|
||||
{
|
||||
FLASH_DEBUG("%s: %s BCH FAIL!!!page=[%d]\n", __FILE__,__FUNCTION__, page);
|
||||
dump_stack();
|
||||
return 2;
|
||||
}
|
||||
|
||||
if((((pRK29NC->BCHST[0])>>3)&0x1F) >= 12 /*|| refreshTestCnt++%10000 == 0*/)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(pRK29NC->BCHST[0]&0x2){
|
||||
return 0;
|
||||
}
|
||||
else{
|
||||
FLASH_DEBUG("%s: %s Flash BCH no done!!!\n", __FILE__,__FUNCTION__);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* ÉèÖÃÆ¬Ñ¡
|
||||
*/
|
||||
|
|
@ -316,9 +714,6 @@ static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column,
|
|||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct rk29_nand_mtd *master = nand_chip->priv;
|
||||
pNANDC pRK29NC= (pNANDC)(master->regs);
|
||||
|
||||
char status,ret;
|
||||
|
||||
|
||||
switch (command) {
|
||||
|
||||
|
|
@ -393,15 +788,6 @@ static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column,
|
|||
pRK29NC ->chip[master->cs].cmd = command;
|
||||
udelay(1);
|
||||
rk29_nand_wait_busy(mtd,PROGRAM_BUSY_COUNT);
|
||||
|
||||
pRK29NC ->chip[master->cs].cmd = NAND_CMD_STATUS;
|
||||
status = pRK29NC ->chip[master->cs].data;
|
||||
|
||||
if(status&0x1)
|
||||
ret = -1;
|
||||
else
|
||||
ret =0;
|
||||
|
||||
break;
|
||||
|
||||
case NAND_CMD_ERASE1:
|
||||
|
|
@ -420,14 +806,6 @@ static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column,
|
|||
pRK29NC ->FMCTL |= FMC_WP; //½â³ýд±£»¤
|
||||
pRK29NC ->chip[master->cs].cmd = command;
|
||||
rk29_nand_wait_busy(mtd,ERASE_BUSY_COUNT);
|
||||
pRK29NC ->chip[master->cs].cmd = NAND_CMD_STATUS;
|
||||
status = pRK29NC ->chip[master->cs].data;
|
||||
|
||||
if(status&0x1)
|
||||
ret = -1;
|
||||
else
|
||||
ret =0;
|
||||
|
||||
break;
|
||||
|
||||
case NAND_CMD_SEQIN:
|
||||
|
|
@ -476,6 +854,7 @@ int rk29_nand_calculate_ecc(struct mtd_info *mtd,const uint8_t *dat,uint8_t *ecc
|
|||
|
||||
int eccdata[7],i;
|
||||
|
||||
FLASH_DEBUG("%s:%s, %d\n", __FILE__,__FUNCTION__, __LINE__);
|
||||
for(i=0;i<7;i++)
|
||||
{
|
||||
eccdata[i] = pRK29NC->spare[i+1];
|
||||
|
|
@ -497,6 +876,7 @@ int rk29_nand_calculate_ecc(struct mtd_info *mtd,const uint8_t *dat,uint8_t *ecc
|
|||
struct rk29_nand_mtd *master = nand_chip->priv;
|
||||
pNANDC pRK29NC= (pNANDC)(master->regs);
|
||||
|
||||
FLASH_DEBUG("%s:%s, %d\n", __FILE__,__FUNCTION__, __LINE__);
|
||||
pRK29NC->BCHCTL = 1; // reset bch and enable hw ecc
|
||||
|
||||
return;
|
||||
|
|
@ -511,8 +891,7 @@ int rk29_nand_calculate_ecc(struct mtd_info *mtd,const uint8_t *dat,uint8_t *ecc
|
|||
// hw correct data
|
||||
if( pRK29NC->BCHST[0] & (1<<2) )
|
||||
{
|
||||
DEBUG(MTD_DEBUG_LEVEL0,
|
||||
"rk2818 nand :hw ecc uncorrectable error\n");
|
||||
FLASH_DEBUG("%s: %s BCH FAILED!!!\n", __FILE__,__FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -525,7 +904,7 @@ int rk29_nand_calculate_ecc(struct mtd_info *mtd,const uint8_t *dat,uint8_t *ecc
|
|||
struct rk29_nand_mtd *master = nand_chip->priv;
|
||||
pNANDC pRK29NC= (pNANDC)(master->regs);
|
||||
|
||||
int i,chipnr;
|
||||
int i,chipnr, ecc = 0;
|
||||
|
||||
|
||||
RKNAND_LOCK();
|
||||
|
|
@ -533,9 +912,7 @@ int rk29_nand_calculate_ecc(struct mtd_info *mtd,const uint8_t *dat,uint8_t *ecc
|
|||
chipnr = master->cs ;
|
||||
|
||||
rk29_nand_select_chip(mtd,chipnr);
|
||||
|
||||
|
||||
rk29_nand_wait_busy(mtd,READ_BUSY_COUNT);
|
||||
|
||||
|
||||
pRK29NC->FLCTL |= FL_BYPASS; // dma mode
|
||||
|
||||
|
|
@ -550,15 +927,27 @@ int rk29_nand_calculate_ecc(struct mtd_info *mtd,const uint8_t *dat,uint8_t *ecc
|
|||
pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_BYPASS|FL_START ;
|
||||
wait_op_done(mtd,TROP_US_DELAY,0);
|
||||
rk29_nand_wait_bchdone(mtd,TROP_US_DELAY) ;
|
||||
|
||||
ecc |= rk29_nand_check_hwecc(mtd, page);
|
||||
memcpy(buf+i*0x400,(u_char *)(pRK29NC->buf),0x400); // only use nandc sram0
|
||||
}
|
||||
|
||||
if(ecc & 0x2){
|
||||
mtd->ecc_stats.failed++;
|
||||
return -EBADMSG;
|
||||
}
|
||||
else if(ecc & 0x1){
|
||||
if(!read_in_refresh){
|
||||
//FLASH_DEBUG("Flash need fresh srcAddr = [%d]\n", ((page*mtd->writesize)/mtd->erasesize)*mtd->erasesize);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
rk29_nand_select_chip(mtd,-1);
|
||||
|
||||
RKNAND_UNLOCK();
|
||||
|
||||
//t2 = ktime_get();
|
||||
//delta = ktime_sub(t2, t1);
|
||||
//FLASH_DEBUG("%s:%s [%lli nsec]\r\n",__FILE__,__FUNCTION__, (long long)ktime_to_ns(delta));
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
|
@ -613,7 +1002,11 @@ int rk29_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page, i
|
|||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct rk29_nand_mtd *master = nand_chip->priv;
|
||||
pNANDC pRK29NC= (pNANDC)(master->regs);
|
||||
int i,chipnr;
|
||||
int i,chipnr,ecc=0;
|
||||
RKNAND_LOCK();
|
||||
chipnr = master->cs ;
|
||||
|
||||
rk29_nand_select_chip(mtd,chipnr);
|
||||
|
||||
|
||||
if (sndcmd) {
|
||||
|
|
@ -621,12 +1014,6 @@ int rk29_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page, i
|
|||
sndcmd = 0;
|
||||
}
|
||||
|
||||
RKNAND_LOCK();
|
||||
|
||||
chipnr = master->cs ;
|
||||
|
||||
rk29_nand_select_chip(mtd,chipnr);
|
||||
|
||||
rk29_nand_wait_busy(mtd,READ_BUSY_COUNT);
|
||||
|
||||
|
||||
|
|
@ -644,10 +1031,21 @@ int rk29_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page, i
|
|||
pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_BYPASS|FL_START ;
|
||||
wait_op_done(mtd,TROP_US_DELAY,0);
|
||||
rk29_nand_wait_bchdone(mtd,TROP_US_DELAY) ;
|
||||
ecc |= rk29_nand_check_hwecc(mtd, page);
|
||||
if(i==0)
|
||||
memcpy((u_char *)(chip->oob_poi+ chip->ops.ooboffs),(u_char *)(pRK29NC->spare),4);
|
||||
}
|
||||
|
||||
if(ecc & 0x2){
|
||||
mtd->ecc_stats.failed++;
|
||||
return -EBADMSG;
|
||||
}
|
||||
else if(ecc & 0x1){
|
||||
if(!read_in_refresh){
|
||||
//FLASH_DEBUG("Flash need fresh srcAddr = [%d]\n", ((page*mtd->writesize)/mtd->erasesize)*mtd->erasesize);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
rk29_nand_select_chip(mtd,-1);
|
||||
|
||||
|
|
@ -663,7 +1061,7 @@ int rk29_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_
|
|||
struct rk29_nand_mtd *master = nand_chip->priv;
|
||||
pNANDC pRK29NC= (pNANDC)(master->regs);
|
||||
|
||||
int i,chipnr;
|
||||
int i,chipnr,ecc=0;
|
||||
|
||||
|
||||
RKNAND_LOCK();
|
||||
|
|
@ -687,11 +1085,22 @@ int rk29_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_
|
|||
pRK29NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_BYPASS|FL_START ;
|
||||
wait_op_done(mtd,TROP_US_DELAY,0);
|
||||
rk29_nand_wait_bchdone(mtd,TROP_US_DELAY) ;
|
||||
ecc |= rk29_nand_check_hwecc(mtd, page);
|
||||
memcpy(buf+i*0x400,(u_char *)(pRK29NC->buf),0x400); // only use nandc sram0
|
||||
if(i==0)
|
||||
memcpy((u_char *)(chip->oob_poi+ chip->ops.ooboffs),(u_char *)(pRK29NC->spare),4);
|
||||
}
|
||||
|
||||
if(ecc & 0x2){
|
||||
mtd->ecc_stats.failed++;
|
||||
return -EBADMSG;
|
||||
}
|
||||
else if(ecc & 0x1){
|
||||
if(!read_in_refresh){
|
||||
//FLASH_DEBUG("Flash need fresh srcAddr = [%d]\n", ((page*mtd->writesize)/mtd->erasesize)*mtd->erasesize);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
rk29_nand_select_chip(mtd,-1);
|
||||
RKNAND_UNLOCK();
|
||||
|
|
@ -699,6 +1108,45 @@ int rk29_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_
|
|||
|
||||
return 0;
|
||||
}
|
||||
int rk29_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,const uint8_t *buf)
|
||||
{
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct rk29_nand_mtd *master = nand_chip->priv;
|
||||
pNANDC pRK29NC= (pNANDC)(master->regs);
|
||||
int i,chipnr;
|
||||
|
||||
//FLASH_DEBUG("%s: %s, %d\n", __FILE__ ,__FUNCTION__, __LINE__);
|
||||
|
||||
RKNAND_LOCK();
|
||||
|
||||
chipnr = master->cs ;
|
||||
|
||||
rk29_nand_select_chip(mtd,chipnr);
|
||||
|
||||
rk29_nand_wait_busy(mtd, PROGRAM_BUSY_COUNT);
|
||||
|
||||
pRK29NC->FLCTL |= FL_BYPASS; // dma mode
|
||||
|
||||
if(chip->options&NAND_BUSWIDTH_16)
|
||||
{
|
||||
pRK29NC ->FMCTL |= FMC_WIDTH_16; // ÉèÖÃΪ16λ
|
||||
}
|
||||
|
||||
for(i=0;i<mtd->writesize/0x400;i++)
|
||||
{
|
||||
pRK29NC->BCHCTL = BCH_WR|BCH_RST;
|
||||
memcpy((u_char *)(pRK29NC->buf),(buf+i*0x400),0x400);
|
||||
if(i==0)
|
||||
memcpy((u_char *)(pRK29NC->spare),(u_char *)(chip->oob_poi + chip->ops.ooboffs),4);
|
||||
pRK29NC->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_RDN|FL_BYPASS|FL_START;
|
||||
wait_op_done(mtd,TROP_US_DELAY,0);
|
||||
}
|
||||
rk29_nand_select_chip(mtd,-1);
|
||||
|
||||
RKNAND_UNLOCK();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int rk29_nand_setrate(struct rk29_nand_mtd *info)
|
||||
{
|
||||
|
|
@ -795,7 +1243,6 @@ static int rk29_nand_probe(struct platform_device *pdev)
|
|||
int err = 0;
|
||||
pNANDC pRK29NC;
|
||||
u_char maf_id,dev_id,ext_id3,ext_id4;
|
||||
struct nand_chip *chip;
|
||||
|
||||
#ifdef CONFIG_MTD_PARTITIONS
|
||||
struct mtd_partition *partitions = NULL;
|
||||
|
|
@ -896,39 +1343,16 @@ static int rk29_nand_probe(struct platform_device *pdev)
|
|||
|
||||
/* Scan to find existence of the device */
|
||||
#if 0
|
||||
if (nand_scan(mtd, 8)) { // rk2818 nandc support max 8 cs
|
||||
if (nand_scan(mtd, 8)) { // rk29 nandc support max 8 cs
|
||||
#else
|
||||
if (nand_scan(mtd, 1)) { // test for fpga board nand
|
||||
#endif
|
||||
DEBUG(MTD_DEBUG_LEVEL0,
|
||||
"RK2818 NAND: Unable to find any NAND device.\n");
|
||||
"RK29 NAND: Unable to find any NAND device.\n");
|
||||
err = -ENXIO;
|
||||
goto outscan;
|
||||
}
|
||||
|
||||
//根据片选情况恢复IO MUX原始值
|
||||
#if 0
|
||||
chip = mtd->priv;
|
||||
switch(chip->numchips)
|
||||
{
|
||||
case 1:
|
||||
rk2818_mux_api_mode_resume(GPIOA5_FLASHCS1_SEL_NAME);
|
||||
case 2:
|
||||
rk2818_mux_api_mode_resume(GPIOA6_FLASHCS2_SEL_NAME);
|
||||
case 3:
|
||||
rk2818_mux_api_mode_resume(GPIOA7_FLASHCS3_SEL_NAME);
|
||||
case 4:
|
||||
rk2818_mux_api_mode_resume(GPIOE_SPI1_FLASH_SEL1_NAME);
|
||||
case 5:
|
||||
case 6:
|
||||
rk2818_mux_api_mode_resume(GPIOE_SPI1_FLASH_SEL_NAME);
|
||||
case 7:
|
||||
case 8:
|
||||
break;
|
||||
default:
|
||||
DEBUG(MTD_DEBUG_LEVEL0, "RK2818 NAND: numchips error!!!\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_PARTITIONS
|
||||
num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0);
|
||||
|
|
@ -959,6 +1383,7 @@ static int rk29_nand_probe(struct platform_device *pdev)
|
|||
|
||||
outres:
|
||||
outscan:
|
||||
printk("rk29_nand_probe error!!!\n");
|
||||
iounmap(master->regs);
|
||||
kfree(master);
|
||||
|
||||
|
|
@ -998,6 +1423,7 @@ static int rk29_nand_remove(struct platform_device *pdev)
|
|||
#ifdef CONFIG_PM
|
||||
static int rk29_nand_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
#if 0
|
||||
struct mtd_info *info = platform_get_drvdata(pdev);
|
||||
int ret = 0;
|
||||
|
||||
|
|
@ -1005,10 +1431,14 @@ static int rk29_nand_suspend(struct platform_device *pdev, pm_message_t state)
|
|||
if (info)
|
||||
ret = info->suspend(info);
|
||||
return ret;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int rk29_nand_resume(struct platform_device *pdev)
|
||||
{
|
||||
#if 0
|
||||
struct mtd_info *info = platform_get_drvdata(pdev);
|
||||
int ret = 0;
|
||||
|
||||
|
|
@ -1019,6 +1449,9 @@ static int rk29_nand_resume(struct platform_device *pdev)
|
|||
info->resume(info);
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
#define rk29_nand_suspend NULL
|
||||
|
|
|
|||
|
|
@ -173,7 +173,12 @@ int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
|
|||
if (localData)
|
||||
yaffs_ReleaseTempBuffer(dev, data, __LINE__);
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_RK29
|
||||
//dxj 20101221@ if return -EBADMSG then i think the page is badchunk so just set the eccResult=YAFFS_ECC_RESULT_NO_ERROR
|
||||
if (tags && retval == -EBADMSG /*&& tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR*/) {
|
||||
#else
|
||||
if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) {
|
||||
#endif
|
||||
tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
||||
dev->eccUnfixed++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ extern void nand_release (struct mtd_info *mtd);
|
|||
/* Internal helper for board drivers which need to override command function */
|
||||
extern void nand_wait_ready(struct mtd_info *mtd);
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_RK29
|
||||
#define RK29_RESERVE_BLOCK_NUM 5
|
||||
#endif
|
||||
/* The maximum number of NAND chips in an array */
|
||||
#define NAND_MAX_CHIPS 8
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user