From 9f5150beff8e4f705e7a6ce3acd0a26b0abc2194 Mon Sep 17 00:00:00 2001 From: hxy Date: Fri, 26 Nov 2010 09:11:49 +0800 Subject: [PATCH] add 16-bit nand flash support and speed up flash read & write --- arch/arm/mach-rk29/include/mach/rk29_nand.h | 1 + drivers/mtd/nand/nand_base.c | 2 + drivers/mtd/nand/rk29_nand.c | 89 ++++++++++++--------- 3 files changed, 55 insertions(+), 37 deletions(-) diff --git a/arch/arm/mach-rk29/include/mach/rk29_nand.h b/arch/arm/mach-rk29/include/mach/rk29_nand.h index 0d1b116ec20b..57f7277a69f5 100644 --- a/arch/arm/mach-rk29/include/mach/rk29_nand.h +++ b/arch/arm/mach-rk29/include/mach/rk29_nand.h @@ -40,6 +40,7 @@ #define FMC_FRDY (0x1<<9) #define FMC_FRDY_INT_EN (0x1<<10) #define FMC_FRDY_INT_CLR (0x1<<11) +#define FMC_WIDTH_16 (0x1<<12) //FMWAIT¼Ä´æÆ÷ #define FMW_RWCS_OFFSET 0 #define FMW_RWPW_OFFSET 5 diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 65473c5c2f5b..b1221872dd3f 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2558,6 +2558,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, break; } + chip->options |= busw; + /* * Check, if buswidth is correct. Hardware drivers should set * chip correct ! diff --git a/drivers/mtd/nand/rk29_nand.c b/drivers/mtd/nand/rk29_nand.c index dc36e5fbd73f..d0ea1ed7f5d3 100644 --- a/drivers/mtd/nand/rk29_nand.c +++ b/drivers/mtd/nand/rk29_nand.c @@ -90,6 +90,22 @@ static struct nand_ecclayout nand_hw_eccoob_16 = { static const char *part_probes[] = { "cmdlinepart", NULL }; #endif +static void rk29_nand_wait_ready( struct mtd_info *mtd ) +{ + struct nand_chip *nand_chip = mtd->priv; + struct rk29_nand_mtd *master = nand_chip->priv; + pNANDC pRK29NC= (pNANDC)(master->regs); + uint32_t timeout = 1000; + + while (timeout>0) + { + timeout --; + if(pRK29NC->FMCTL&FMC_FRDY) + break; + udelay(1); + } + return; +} static void rk29_nand_wait_busy(struct mtd_info *mtd, uint32_t timeout) { @@ -301,7 +317,6 @@ static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column, struct rk29_nand_mtd *master = nand_chip->priv; pNANDC pRK29NC= (pNANDC)(master->regs); - uint32_t timeout = 1000; char status,ret; @@ -309,21 +324,15 @@ static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column, case NAND_CMD_READID: pRK29NC ->chip[master->cs].cmd = command; + rk29_nand_wait_ready(mtd); pRK29NC ->chip[master->cs].addr = 0x0; - while (timeout>0) - { - timeout --; - udelay(1); - if(pRK29NC->FLCTL&FL_INTCLR) - break; - - } - + rk29_nand_wait_ready(mtd); rk29_nand_wait_busy(mtd,READ_BUSY_COUNT); break; case NAND_CMD_READ0: pRK29NC ->chip[master->cs].cmd = command; + rk29_nand_wait_ready(mtd); if ( column>= 0 ) { pRK29NC ->chip[master->cs].addr = column & 0xff; @@ -336,15 +345,18 @@ static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column, pRK29NC ->chip[master->cs].addr = (page_addr >> 8) & 0xFF; pRK29NC ->chip[master->cs].addr = (page_addr >> 16) & 0xff; } + rk29_nand_wait_ready(mtd); if( mtd->writesize > 512) pRK29NC ->chip[0].cmd = NAND_CMD_READSTART; + rk29_nand_wait_ready(mtd); rk29_nand_wait_busy(mtd,READ_BUSY_COUNT); break; case NAND_CMD_READ1: pRK29NC ->chip[master->cs].cmd = command; + rk29_nand_wait_ready(mtd); break; case NAND_CMD_READOOB: @@ -354,6 +366,7 @@ static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column, pRK29NC ->chip[master->cs].cmd = command; + rk29_nand_wait_ready(mtd); if ( mtd->writesize >512 ) { if ( column>= 0 ) @@ -373,6 +386,7 @@ static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column, { pRK29NC ->chip[master->cs].addr = column; } + rk29_nand_wait_ready(mtd); rk29_nand_wait_busy(mtd,READ_BUSY_COUNT); @@ -382,9 +396,11 @@ static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column, case NAND_CMD_PAGEPROG: pRK29NC ->FMCTL |= FMC_WP; //½â³ýд±£»¤ pRK29NC ->chip[master->cs].cmd = command; + rk29_nand_wait_ready(mtd); rk29_nand_wait_busy(mtd,PROGRAM_BUSY_COUNT); pRK29NC ->chip[master->cs].cmd = NAND_CMD_STATUS; + rk29_nand_wait_ready(mtd); status = pRK29NC ->chip[master->cs].data; if(status&0x1) @@ -398,6 +414,7 @@ static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column, pRK29NC ->FMCTL |= FMC_WP; //½â³ýд±£»¤ pRK29NC ->BCHCTL = 0x0; pRK29NC ->chip[master->cs].cmd = command; + rk29_nand_wait_ready(mtd); if ( page_addr>=0 ) { pRK29NC ->chip[master->cs].addr = page_addr & 0xff; @@ -409,8 +426,10 @@ static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column, case NAND_CMD_ERASE2: pRK29NC ->FMCTL |= FMC_WP; //½â³ýд±£»¤ pRK29NC ->chip[master->cs].cmd = command; + rk29_nand_wait_ready(mtd); rk29_nand_wait_busy(mtd,ERASE_BUSY_COUNT); pRK29NC ->chip[master->cs].cmd = NAND_CMD_STATUS; + rk29_nand_wait_ready(mtd); status = pRK29NC ->chip[master->cs].data; if(status&0x1) @@ -423,7 +442,7 @@ static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column, case NAND_CMD_SEQIN: pRK29NC ->FMCTL |= FMC_WP; //½â³ýд±£»¤ pRK29NC ->chip[master->cs].cmd = command; - udelay(1); + rk29_nand_wait_ready(mtd); if ( column>= 0 ) { pRK29NC ->chip[master->cs].addr = column; @@ -442,36 +461,22 @@ static void rk29_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int column, case NAND_CMD_STATUS: pRK29NC ->BCHCTL = 0x0; pRK29NC ->chip[master->cs].cmd = command; - while (timeout>0) - { - timeout --; - udelay(1); - if(pRK29NC->FLCTL&FL_INTCLR) - break; - - } + rk29_nand_wait_ready(mtd); break; case NAND_CMD_RESET: pRK29NC ->chip[master->cs].cmd = command; - while (timeout>0) - { - timeout --; - udelay(1); - if(pRK29NC->FLCTL&FL_INTCLR) - break; - - } + rk29_nand_wait_ready(mtd); rk29_nand_wait_busy(mtd,RESET_BUSY_COUNT); break; /* This applies to read commands */ default: pRK29NC ->chip[master->cs].cmd = command; + rk29_nand_wait_ready(mtd); break; } - udelay (1); } @@ -545,6 +550,11 @@ int rk29_nand_calculate_ecc(struct mtd_info *mtd,const uint8_t *dat,uint8_t *ecc rk29_nand_wait_busy(mtd,READ_BUSY_COUNT); pRK29NC->FLCTL |= FL_BYPASS; // dma mode + + if(chip->options&NAND_BUSWIDTH_16) + { + pRK29NC ->FMCTL |= FMC_WIDTH_16; // ÉèÖÃΪ16λ + } for(i=0;iwritesize/0x400;i++) { @@ -580,7 +590,11 @@ void rk29_nand_write_page(struct mtd_info *mtd,struct nand_chip *chip,const uin pRK29NC->FLCTL |= FL_BYPASS; // dma mode - + if(chip->options&NAND_BUSWIDTH_16) + { + pRK29NC ->FMCTL |= FMC_WIDTH_16; // ÉèÖÃΪ16λ + } + for(i=0;iwritesize/0x400;i++) { memcpy((u_char *)(pRK29NC->buf),(buf+i*0x400),0x400); // only use nandc sram0 @@ -630,7 +644,10 @@ int rk29_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page, i pRK29NC->FLCTL |= FL_BYPASS; // dma mode - + if(chip->options&NAND_BUSWIDTH_16) + { + pRK29NC ->FMCTL |= FMC_WIDTH_16; // ÉèÖÃΪ16λ + } for(i=0;iwritesize/0x400;i++) @@ -671,7 +688,10 @@ int rk29_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_ pRK29NC->FLCTL |= FL_BYPASS; // dma mode - + if(chip->options&NAND_BUSWIDTH_16) + { + pRK29NC ->FMCTL |= FMC_WIDTH_16; // ÉèÖÃΪ16λ + } for(i=0;iwritesize/0x400;i++) { @@ -872,7 +892,7 @@ static int rk29_nand_probe(struct platform_device *pdev) pRK29NC = (pNANDC)(master->regs); pRK29NC ->FMCTL = FMC_WP|FMC_FRDY; - pRK29NC ->FMWAIT |= (1<FMWAIT |= (1<BCHCTL = 0x1; this->select_chip(mtd, 0); @@ -933,11 +953,6 @@ static int rk29_nand_probe(struct platform_device *pdev) DEBUG(MTD_DEBUG_LEVEL0, "RK2818 NAND: numchips error!!!\n"); } #endif -#if 0 - // rk281x dma mode bch must (1k data + 32 oob) bytes align , so cheat system writesize =1024,oobsize=32 - mtd->writesize = 1024; - mtd->oobsize = 32; -#endif #ifdef CONFIG_MTD_PARTITIONS num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0); -- 2.34.1