From: 刘益星 Date: Fri, 28 May 2010 08:56:59 +0000 (+0000) Subject: dm9000 mutex with nandc X-Git-Tag: firefly_0821_release~11452 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=b6e7fd4dbb349633665cea55b9643811368dbb4f;p=firefly-linux-kernel-4.4.55.git dm9000 mutex with nandc --- diff --git a/drivers/mtd/nand/rk2818_nand.c b/drivers/mtd/nand/rk2818_nand.c index af3cefda8a96..19e65f0a77bd 100644 --- a/drivers/mtd/nand/rk2818_nand.c +++ b/drivers/mtd/nand/rk2818_nand.c @@ -26,10 +26,13 @@ #include #include #include +#include #include #include #include +#include +#include #define PROGRAM_BUSY_COUNT 10000 #define ERASE_BUSY_COUNT 20000 @@ -38,6 +41,10 @@ /* Define delays in microsec for NAND device operations */ #define TROP_US_DELAY 2000 +static struct mutex rknand_mutex; +//static spinlock_t rknand_lock; + + struct rk2818_nand_mtd { struct mtd_info mtd; struct nand_chip nand; @@ -45,9 +52,15 @@ struct rk2818_nand_mtd { struct device *dev; const struct rk2818_nand_flash *flash_info; - struct clk *clk; - void __iomem *regs; - uint16_t col_addr; + struct clk *clk; + unsigned long clk_rate; + void __iomem *regs; + int cs; // support muliple nand chip,record current chip select + u_char accesstime; +#ifdef CONFIG_CPU_FREQ + struct notifier_block freq_transition; +#endif + }; /* OOB placement block for use with software ecc generation */ @@ -142,8 +155,17 @@ static void rk2818_nand_select_chip(struct mtd_info *mtd, int chip) struct nand_chip *nand_chip = mtd->priv; struct rk2818_nand_mtd *master = nand_chip->priv; pNANDC pRK28NC= (pNANDC)(master->regs); + + + if( chip<0 ) + pRK28NC->FMCTL &=0xffffff00; // release chip select + else + { + master->cs = chip; + pRK28NC->FMCTL &=0xffffff00; + pRK28NC ->FMCTL |= 0x1<FMCTL |= 0x1<regs); u_char ret = 0; - pRK28NC->FLCTL &= ~FL_BYPASS; // bypass mode - ret = (u_char)(pRK28NC ->chip[0].data); + + ret = (u_char)(pRK28NC ->chip[master->cs].data); + return ret; } @@ -169,17 +192,16 @@ static u16 rk2818_nand_read_word(struct mtd_info *mtd) struct nand_chip *nand_chip = mtd->priv; struct rk2818_nand_mtd *master = nand_chip->priv; pNANDC pRK28NC= (pNANDC)(master->regs); + u_char tmp1 = 0,tmp2=0; u16 ret=0; - - pRK28NC->FLCTL &= ~FL_BYPASS; // bypass mode - - tmp1 = (u_char)(pRK28NC ->chip[0].data); - tmp2 = (u_char)(pRK28NC ->chip[0].data); + + tmp1 = (u_char)(pRK28NC ->chip[master->cs].data); + tmp2 = (u_char)(pRK28NC ->chip[master->cs].data); ret = (tmp2 <<8)|tmp1; - + return ret; } @@ -188,9 +210,16 @@ static void rk2818_nand_read_buf(struct mtd_info *mtd, u_char* const buf, int le struct nand_chip *nand_chip = mtd->priv; struct rk2818_nand_mtd *master = nand_chip->priv; pNANDC pRK28NC= (pNANDC)(master->regs); - uint32_t i; + uint32_t i, chipnr; + + mutex_lock(&rknand_mutex); + + chipnr = master->cs ; + + rk2818_nand_select_chip(mtd,chipnr); + + - if ( len < mtd->writesize ) // read oob { pRK28NC ->BCHCTL = BCH_RST; @@ -211,6 +240,13 @@ static void rk2818_nand_read_buf(struct mtd_info *mtd, u_char* const buf, int le memcpy(buf+i*0x400,(u_char *)(pRK28NC->buf),0x400); // only use nandc sram0 } } + + + + rk2818_nand_select_chip(mtd,-1); + + mutex_unlock(&rknand_mutex); + return; @@ -222,9 +258,18 @@ static void rk2818_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int l struct rk2818_nand_mtd *master = nand_chip->priv; pNANDC pRK28NC= (pNANDC)(master->regs); - uint32_t i = 0; + uint32_t i = 0, chipnr; + + + mutex_lock(&rknand_mutex); + + chipnr = master->cs ; + rk2818_nand_select_chip(mtd,chipnr); + pRK28NC->FLCTL |= FL_BYPASS; // dma mode + + for(i=0;iwritesize/0x400;i++) { memcpy((u_char *)(pRK28NC->buf),buf+i*0x400,0x400); // only use nandc sram0 @@ -232,6 +277,13 @@ static void rk2818_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int l pRK28NC ->FLCTL = (0<<4)|FL_COR_EN|0x1<<5|FL_RDN|FL_BYPASS|FL_START; wait_op_done(mtd,TROP_US_DELAY,0); } + + + + rk2818_nand_select_chip(mtd,-1); + + mutex_unlock(&rknand_mutex); + } @@ -244,12 +296,13 @@ static void rk2818_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int colum uint32_t timeout = 1000; char status,ret; + switch (command) { case NAND_CMD_READID: - pRK28NC ->chip[0].cmd = command; - pRK28NC ->chip[0].addr = 0x0; + pRK28NC ->chip[master->cs].cmd = command; + pRK28NC ->chip[master->cs].addr = 0x0; while (timeout>0) { timeout --; @@ -262,18 +315,18 @@ static void rk2818_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int colum break; case NAND_CMD_READ0: - pRK28NC ->chip[0].cmd = command; + pRK28NC ->chip[master->cs].cmd = command; if ( column>= 0 ) { - pRK28NC ->chip[0].addr = column & 0xff; + pRK28NC ->chip[master->cs].addr = column & 0xff; if( mtd->writesize > 512) - pRK28NC ->chip[0].addr = (column >> 8) & 0xff; + pRK28NC ->chip[master->cs].addr = (column >> 8) & 0xff; } if ( page_addr>=0 ) { - pRK28NC ->chip[0].addr = page_addr & 0xff; - pRK28NC ->chip[0].addr = (page_addr >> 8) & 0xFF; - pRK28NC ->chip[0].addr = (page_addr >> 16) & 0xff; + pRK28NC ->chip[master->cs].addr = page_addr & 0xff; + pRK28NC ->chip[master->cs].addr = (page_addr >> 8) & 0xFF; + pRK28NC ->chip[master->cs].addr = (page_addr >> 16) & 0xff; } if( mtd->writesize > 512) pRK28NC ->chip[0].cmd = NAND_CMD_READSTART; @@ -283,7 +336,7 @@ static void rk2818_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int colum break; case NAND_CMD_READ1: - pRK28NC ->chip[0].cmd = command; + pRK28NC ->chip[master->cs].cmd = command; break; case NAND_CMD_READOOB: @@ -291,26 +344,26 @@ static void rk2818_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int colum if( mtd->writesize > 512 ) command = NAND_CMD_READ0; // È«²¿¶Á£¬°üÀ¨¶Áoob - pRK28NC ->chip[0].cmd = command; + pRK28NC ->chip[master->cs].cmd = command; if ( mtd->writesize >512 ) { if ( column>= 0 ) { - pRK28NC ->chip[0].addr = (column + mtd->writesize) & 0xff; - pRK28NC ->chip[0].addr = ( (column + mtd->writesize) >> 8) & 0xff; + pRK28NC ->chip[master->cs].addr = (column + mtd->writesize) & 0xff; + pRK28NC ->chip[master->cs].addr = ( (column + mtd->writesize) >> 8) & 0xff; } if ( page_addr>=0 ) { - pRK28NC ->chip[0].addr = page_addr & 0xff; - pRK28NC ->chip[0].addr = (page_addr >> 8) & 0xFF; - pRK28NC ->chip[0].addr = (page_addr >> 16) & 0xff; + pRK28NC ->chip[master->cs].addr = page_addr & 0xff; + pRK28NC ->chip[master->cs].addr = (page_addr >> 8) & 0xFF; + pRK28NC ->chip[master->cs].addr = (page_addr >> 16) & 0xff; } - pRK28NC ->chip[0].cmd = NAND_CMD_READSTART; + pRK28NC ->chip[master->cs].cmd = NAND_CMD_READSTART; } else { - pRK28NC ->chip[0].addr = column; + pRK28NC ->chip[master->cs].addr = column; } rk2818_nand_wait_busy(mtd,READ_BUSY_COUNT); @@ -320,11 +373,11 @@ static void rk2818_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int colum case NAND_CMD_PAGEPROG: pRK28NC ->FMCTL |= FMC_WP; //½â³ýд±£»¤ - pRK28NC ->chip[0].cmd = command; + pRK28NC ->chip[master->cs].cmd = command; rk2818_nand_wait_busy(mtd,PROGRAM_BUSY_COUNT); - pRK28NC ->chip[0].cmd = NAND_CMD_STATUS; - status = pRK28NC ->chip[0].data; + pRK28NC ->chip[master->cs].cmd = NAND_CMD_STATUS; + status = pRK28NC ->chip[master->cs].data; if(status&0x1) ret = -1; @@ -336,21 +389,21 @@ static void rk2818_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int colum case NAND_CMD_ERASE1: pRK28NC ->FMCTL |= FMC_WP; //½â³ýд±£»¤ pRK28NC ->BCHCTL = 0x0; - pRK28NC ->chip[0].cmd = command; + pRK28NC ->chip[master->cs].cmd = command; if ( page_addr>=0 ) { - pRK28NC ->chip[0].addr = page_addr & 0xff; - pRK28NC ->chip[0].addr = (page_addr>>8)&0xff; - pRK28NC ->chip[0].addr = (page_addr>>16)&0xff; + pRK28NC ->chip[master->cs].addr = page_addr & 0xff; + pRK28NC ->chip[master->cs].addr = (page_addr>>8)&0xff; + pRK28NC ->chip[master->cs].addr = (page_addr>>16)&0xff; } break; case NAND_CMD_ERASE2: pRK28NC ->FMCTL |= FMC_WP; //½â³ýд±£»¤ - pRK28NC ->chip[0].cmd = command; + pRK28NC ->chip[master->cs].cmd = command; rk2818_nand_wait_busy(mtd,ERASE_BUSY_COUNT); - pRK28NC ->chip[0].cmd = NAND_CMD_STATUS; - status = pRK28NC ->chip[0].data; + pRK28NC ->chip[master->cs].cmd = NAND_CMD_STATUS; + status = pRK28NC ->chip[master->cs].data; if(status&0x1) ret = -1; @@ -361,35 +414,35 @@ static void rk2818_nand_cmdfunc(struct mtd_info *mtd, unsigned command,int colum case NAND_CMD_SEQIN: pRK28NC ->FMCTL |= FMC_WP; //½â³ýд±£»¤ - pRK28NC ->chip[0].cmd = command; + pRK28NC ->chip[master->cs].cmd = command; udelay(1); if ( column>= 0 ) { - pRK28NC ->chip[0].addr = column; + pRK28NC ->chip[master->cs].addr = column; if( mtd->writesize > 512) - pRK28NC ->chip[0].addr = (column >> 8) & 0xff; + pRK28NC ->chip[master->cs].addr = (column >> 8) & 0xff; } if( page_addr>=0 ) { - pRK28NC ->chip[0].addr = page_addr & 0xff; - pRK28NC ->chip[0].addr = (page_addr>>8)&0xff; - pRK28NC ->chip[0].addr = (page_addr>>16)&0xff; + pRK28NC ->chip[master->cs].addr = page_addr & 0xff; + pRK28NC ->chip[master->cs].addr = (page_addr>>8)&0xff; + pRK28NC ->chip[master->cs].addr = (page_addr>>16)&0xff; } break; case NAND_CMD_STATUS: pRK28NC ->BCHCTL = 0x0; - pRK28NC ->chip[0].cmd = command; + pRK28NC ->chip[master->cs].cmd = command; break; case NAND_CMD_RESET: - pRK28NC ->chip[0].cmd = command; + pRK28NC ->chip[master->cs].cmd = command; break; /* This applies to read commands */ default: - pRK28NC ->chip[0].cmd = command; + pRK28NC ->chip[master->cs].cmd = command; break; } @@ -453,15 +506,21 @@ int rk2818_nand_calculate_ecc(struct mtd_info *mtd,const uint8_t *dat,uint8_t *e struct nand_chip *nand_chip = mtd->priv; struct rk2818_nand_mtd *master = nand_chip->priv; pNANDC pRK28NC= (pNANDC)(master->regs); - - int i; - + int i,chipnr; + + + mutex_lock(&rknand_mutex); + chipnr = master->cs ; + + rk2818_nand_select_chip(mtd,chipnr); + + rk2818_nand_wait_busy(mtd,READ_BUSY_COUNT); pRK28NC->FLCTL |= FL_BYPASS; // dma mode - + for(i=0;iwritesize/0x400;i++) { pRK28NC ->BCHCTL = BCH_RST; @@ -471,7 +530,12 @@ int rk2818_nand_calculate_ecc(struct mtd_info *mtd,const uint8_t *dat,uint8_t *e memcpy(buf+i*0x400,(u_char *)(pRK28NC->buf),0x400); // only use nandc sram0 } + + rk2818_nand_select_chip(mtd,-1); + + mutex_unlock(&rknand_mutex); + return 0; } @@ -481,11 +545,17 @@ void rk2818_nand_write_page(struct mtd_info *mtd,struct nand_chip *chip,const u struct nand_chip *nand_chip = mtd->priv; struct rk2818_nand_mtd *master = nand_chip->priv; pNANDC pRK28NC= (pNANDC)(master->regs); - uint32_t i = 0; - + uint32_t i = 0, chipnr; + + mutex_lock(&rknand_mutex); + chipnr = master->cs ; + + rk2818_nand_select_chip(mtd,chipnr); pRK28NC->FLCTL |= FL_BYPASS; // dma mode + + for(i=0;iwritesize/0x400;i++) { memcpy((u_char *)(pRK28NC->buf),(buf+i*0x400),0x400); // only use nandc sram0 @@ -498,8 +568,14 @@ void rk2818_nand_write_page(struct mtd_info *mtd,struct nand_chip *chip,const u } pRK28NC ->chip[0].cmd = NAND_CMD_PAGEPROG; + + + rk2818_nand_wait_busy(mtd,PROGRAM_BUSY_COUNT); + rk2818_nand_select_chip(mtd,-1); + + mutex_unlock(&rknand_mutex); return; @@ -510,28 +586,43 @@ int rk2818_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page, struct nand_chip *nand_chip = mtd->priv; struct rk2818_nand_mtd *master = nand_chip->priv; pNANDC pRK28NC= (pNANDC)(master->regs); - int i; + int i,chipnr; + if (sndcmd) { chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); sndcmd = 0; } - + + mutex_lock(&rknand_mutex); + + chipnr = master->cs ; + + rk2818_nand_select_chip(mtd,chipnr); + rk2818_nand_wait_busy(mtd,READ_BUSY_COUNT); - + + pRK28NC->FLCTL |= FL_BYPASS; // dma mode + + + for(i=0;iwritesize/0x400;i++) { pRK28NC ->BCHCTL = BCH_RST; pRK28NC ->FLCTL = (0<<4)|FL_COR_EN|(0x1<<5)|FL_BYPASS|FL_START ; wait_op_done(mtd,TROP_US_DELAY,0); rk2818_nand_wait_bchdone(mtd,TROP_US_DELAY) ; - // memcpy(buf+i*0x400,(u_char *)(pRK28NC->buf),0x400); // only use nandc sram0 if(i==0) memcpy((u_char *)(chip->oob_poi+ chip->ops.ooboffs),(u_char *)(pRK28NC->spare),4); } + + rk2818_nand_select_chip(mtd,-1); + + mutex_unlock(&rknand_mutex); + return sndcmd; } @@ -542,14 +633,21 @@ int rk2818_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint struct rk2818_nand_mtd *master = nand_chip->priv; pNANDC pRK28NC= (pNANDC)(master->regs); - - int i; + int i,chipnr; + + + mutex_lock(&rknand_mutex); + + chipnr = master->cs ; + rk2818_nand_select_chip(mtd,chipnr); rk2818_nand_wait_busy(mtd,READ_BUSY_COUNT); pRK28NC->FLCTL |= FL_BYPASS; // dma mode + + for(i=0;iwritesize/0x400;i++) { pRK28NC ->BCHCTL = BCH_RST; @@ -560,10 +658,106 @@ int rk2818_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint if(i==0) memcpy((u_char *)(chip->oob_poi+ chip->ops.ooboffs),(u_char *)(pRK28NC->spare),4); } - + + + rk2818_nand_select_chip(mtd,-1); + mutex_unlock(&rknand_mutex); + + return 0; } +static int rk2818_nand_setrate(struct rk2818_nand_mtd *info) +{ + pNANDC pRK28NC= (pNANDC)(info->regs); + + unsigned long clkrate = clk_get_rate(info->clk); + + u_char accesstime,rwpw,csrw,rwcs; + + unsigned int ns=0,timingcfg; + + unsigned long flags; + + //scan nand flash access time + if ( info->accesstime ==0x00 ) + accesstime=50; + else if ( info->accesstime==0x80) + accesstime=25; + else if ( info->accesstime==0x08) + accesstime=20; + else + accesstime=60; //60ns + + info->clk_rate = clkrate; + clkrate /= 1000000; /* turn clock into MHz for ease of use */ + + if(clkrate>0 && clkrate<200) + ns= 1000/clkrate; // ns + else + return -1; + + timingcfg = (accesstime + ns -1)/ns; + + timingcfg = (timingcfg>=3) ? (timingcfg-2) : timingcfg; //csrw+1, rwcs+1 + + rwpw = timingcfg-timingcfg/4; + csrw = timingcfg/4; + rwcs = (timingcfg/4 >=1)?(timingcfg/4):1; + + mutex_lock(&rknand_mutex); + + pRK28NC ->FMWAIT |= (rwcs<clk); + + if (val == CPUFREQ_POSTCHANGE && newclk != info->clk_rate) + { + rk2818_nand_setrate(info); + } + + return 0; +} + +static inline int rk2818_nand_cpufreq_register(struct rk2818_nand_mtd *info) +{ + info->freq_transition.notifier_call = rk2818_nand_cpufreq_transition; + + return cpufreq_register_notifier(&info->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); +} + +static inline void rk2818_nand_cpufreq_deregister(struct rk2818_nand_mtd *info) +{ + cpufreq_unregister_notifier(&info->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); +} + +#else +static inline int rk2818_nand_cpufreq_register(struct rk2818_nand_mtd *info) +{ + return 0; +} + +static inline void rk2818_nand_cpufreq_deregister(struct rk2818_nand_mtd *info) +{ +} +#endif + static int rk2818_nand_probe(struct platform_device *pdev) { @@ -574,6 +768,7 @@ static int rk2818_nand_probe(struct platform_device *pdev) struct resource *res; int err = 0; pNANDC pRK28NC; + u_char maf_id,dev_id,ext_id3,ext_id4; #ifdef CONFIG_MTD_PARTITIONS struct mtd_partition *partitions = NULL; @@ -638,10 +833,28 @@ static int rk2818_nand_probe(struct platform_device *pdev) this->ecc.mode = NAND_ECC_SOFT; } + + mutex_init(&rknand_mutex); + + master->clk = clk_get(NULL, "nandc"); + + clk_enable(master->clk); + pRK28NC = (pNANDC)(master->regs); - pRK28NC ->FMCTL = FMC_WP|FMC_FRDY|(0x1<<0); + pRK28NC ->FMCTL = FMC_WP|FMC_FRDY; pRK28NC ->FMWAIT |= (1<BCHCTL = 0x1; + + this->select_chip(mtd, 0); + this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + maf_id = this->read_byte(mtd); + dev_id = this->read_byte(mtd); + ext_id3 = this->read_byte(mtd); + ext_id4 = this->read_byte(mtd); + + master->accesstime = ext_id4&0x88; + + rk2818_nand_setrate(master); /* Reset NAND */ this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); @@ -651,14 +864,28 @@ static int rk2818_nand_probe(struct platform_device *pdev) this->ecc.layout = &nand_hw_eccoob_16; } + // iomux flash cs1~cs7 + rk2818_mux_api_set(GPIOA5_FLASHCS1_SEL_NAME, IOMUXB_FLASH_CS1); + rk2818_mux_api_set(GPIOA6_FLASHCS2_SEL_NAME, IOMUXB_FLASH_CS2); + rk2818_mux_api_set(GPIOA7_FLASHCS3_SEL_NAME, IOMUXB_FLASH_CS3); + rk2818_mux_api_set(GPIOE_SPI1_FLASH_SEL1_NAME, IOMUXA_FLASH_CS45); + rk2818_mux_api_set(GPIOE_SPI1_FLASH_SEL_NAME, IOMUXA_FLASH_CS67); + /* Scan to find existence of the device */ - if (nand_scan(mtd, 1)) { + if (nand_scan(mtd, 8)) { // rk2818 nandc support max 8 cs + DEBUG(MTD_DEBUG_LEVEL0, "RK2818 NAND: Unable to find any NAND device.\n"); err = -ENXIO; goto outscan; } +#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); if (num_partitions > 0) { @@ -678,6 +905,12 @@ static int rk2818_nand_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); + err =rk2818_nand_cpufreq_register(master); + if (err < 0) { + printk(KERN_ERR"rk2818 nand failed to init cpufreq support\n"); + goto outscan; + } + return 0; outres: @@ -695,8 +928,24 @@ static int rk2818_nand_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); + if(master == NULL) + return 0; + + rk2818_nand_cpufreq_deregister(master); + + nand_release(&master->mtd); - iounmap(master->regs); + + if(master->regs!=NULL){ + iounmap(master->regs); + master->regs = NULL; + } + + if (master->clk != NULL && !IS_ERR(master->clk)) { + clk_disable(master->clk); + clk_put(master->clk); + } + kfree(master); return 0; @@ -756,6 +1005,26 @@ static void __exit rk2818_nand_exit(void) platform_driver_unregister(&rk2818_nand_driver); } + +// nandc dma cs mutex for dm9000 interface +int rk2818_nand_status_mutex_trylock(void) +{ + pNANDC pRK28NC= (pNANDC)RK2818_NANDC_BASE; + if( mutex_trylock(&rknand_mutex)) + { + pRK28NC->FMCTL &=0xffffff00; // release chip select + return 1; // ready + } + else + return 0; // busy +} + +void rk2818_nand_status_mutex_unlock(void) +{ + mutex_unlock(&rknand_mutex); + return; +} + module_init(rk2818_nand_init); module_exit(rk2818_nand_exit); diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 9a7d9e985797..1b0bb74a2e66 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "dm9000.h" @@ -104,6 +105,12 @@ typedef struct board_info { int debug_level; enum dm9000_type type; + +#ifdef CONFIG_DM9000_USE_NAND_CONTROL + void *dev_id; + struct work_struct dm9k_work; + struct workqueue_struct *dm9000_wq; +#endif void (*inblk)(void __iomem *port, void *data, int length); void (*outblk)(void __iomem *port, void *data, int length); @@ -133,7 +140,6 @@ typedef struct board_info { } board_info_t; /* debug code */ -#define DEBUG_LEVEL 4 #define dm9000_dbg(db, lev, msg...) do { \ if ((lev) < CONFIG_DM9000_DEBUGLEVEL && \ (lev) < db->debug_level) { \ @@ -141,6 +147,14 @@ typedef struct board_info { } \ } while (0) +#ifdef CONFIG_DM9000_USE_NAND_CONTROL +extern int rk2818_nand_status_mutex_trylock(void); +extern void rk2818_nand_status_mutex_unlock(void); +#else +static int rk2818_nand_status_mutex_trylock(void) {return 1;} +static void rk2818_nand_status_mutex_unlock(void) {return;} +#endif + static inline board_info_t *to_dm9000_board(struct net_device *dev) { return netdev_priv(dev); @@ -307,11 +321,16 @@ dm9000_read_locked(board_info_t *db, int reg) { unsigned long flags; unsigned int ret; + + while(!rk2818_nand_status_mutex_trylock()) + dev_dbg(db->dev, "fun:%s, nand busy\n", __func__); - spin_lock_irqsave(&db->lock, flags); + spin_lock_irqsave(&db->lock, flags); ret = ior(db, reg); spin_unlock_irqrestore(&db->lock, flags); + rk2818_nand_status_mutex_unlock(); + return ret; } @@ -363,21 +382,29 @@ dm9000_read_eeprom(board_info_t *db, int offset, u8 *to) } mutex_lock(&db->addr_lock); + + while(!rk2818_nand_status_mutex_trylock()) + dev_dbg(db->dev, "fun:%s, nand busy\n", __func__); spin_lock_irqsave(&db->lock, flags); - + iow(db, DM9000_EPAR, offset); iow(db, DM9000_EPCR, EPCR_ERPRR); spin_unlock_irqrestore(&db->lock, flags); + rk2818_nand_status_mutex_unlock(); + dm9000_wait_eeprom(db); /* delay for at-least 150uS */ msleep(1); + + while(!rk2818_nand_status_mutex_trylock()) + dev_dbg(db->dev, "fun:%s, nand busy\n", __func__); spin_lock_irqsave(&db->lock, flags); - + iow(db, DM9000_EPCR, 0x0); to[0] = ior(db, DM9000_EPDRL); @@ -385,6 +412,8 @@ dm9000_read_eeprom(board_info_t *db, int offset, u8 *to) spin_unlock_irqrestore(&db->lock, flags); + rk2818_nand_status_mutex_unlock(); + mutex_unlock(&db->addr_lock); } @@ -400,22 +429,32 @@ dm9000_write_eeprom(board_info_t *db, int offset, u8 *data) return; mutex_lock(&db->addr_lock); + + while(!rk2818_nand_status_mutex_trylock()) + dev_dbg(db->dev, "fun:%s, nand busy\n", __func__); - spin_lock_irqsave(&db->lock, flags); + spin_lock_irqsave(&db->lock, flags); iow(db, DM9000_EPAR, offset); iow(db, DM9000_EPDRH, data[1]); iow(db, DM9000_EPDRL, data[0]); iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW); spin_unlock_irqrestore(&db->lock, flags); + rk2818_nand_status_mutex_unlock(); + dm9000_wait_eeprom(db); mdelay(1); /* wait at least 150uS to clear */ + + while(!rk2818_nand_status_mutex_trylock()) + dev_dbg(db->dev, "fun:%s, nand busy\n", __func__); spin_lock_irqsave(&db->lock, flags); iow(db, DM9000_EPCR, 0); spin_unlock_irqrestore(&db->lock, flags); + rk2818_nand_status_mutex_unlock(); + mutex_unlock(&db->addr_lock); } @@ -480,9 +519,13 @@ static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data) if (dm->can_csum) { dm->rx_csum = data; + while(!rk2818_nand_status_mutex_trylock()) + dev_dbg(dm->dev, "fun:%s, nand busy\n", __func__); + spin_lock_irqsave(&dm->lock, flags); iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0); spin_unlock_irqrestore(&dm->lock, flags); + rk2818_nand_status_mutex_unlock(); return 0; } @@ -680,9 +723,12 @@ dm9000_hash_table(struct net_device *dev) unsigned long flags; dm9000_dbg(db, 1, "entering %s\n", __func__); + + while(!rk2818_nand_status_mutex_trylock()) + dev_dbg(db->dev, "fun:%s, nand busy\n", __func__); spin_lock_irqsave(&db->lock, flags); - + for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++) iow(db, oft, dev->dev_addr[i]); @@ -713,6 +759,8 @@ dm9000_hash_table(struct net_device *dev) iow(db, DM9000_RCR, rcr); spin_unlock_irqrestore(&db->lock, flags); + + rk2818_nand_status_mutex_unlock(); } /* @@ -776,6 +824,10 @@ static void dm9000_timeout(struct net_device *dev) /* Save previous register address */ reg_save = readb(db->io_addr); + + while(!rk2818_nand_status_mutex_trylock()) + dev_dbg(db->dev, "fun:%s, nand busy\n", __func__); + spin_lock_irqsave(&db->lock, flags); netif_stop_queue(dev); @@ -788,6 +840,8 @@ static void dm9000_timeout(struct net_device *dev) /* Restore previous register address */ writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock, flags); + + rk2818_nand_status_mutex_unlock(); } static void dm9000_send_packet(struct net_device *dev, @@ -830,8 +884,12 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } + if (!rk2818_nand_status_mutex_trylock()) { + dev_dbg(db->dev, "fun:%s, nand busy\n", __func__); + return NETDEV_TX_BUSY; + } spin_lock_irqsave(&db->lock, flags); - + /* Move data to DM9000 TX RAM */ writeb(DM9000_MWCMD, db->io_addr); @@ -850,6 +908,8 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) } spin_unlock_irqrestore(&db->lock, flags); + + rk2818_nand_status_mutex_unlock(); /* free this SKB */ dev_kfree_skb(skb); @@ -998,6 +1058,82 @@ dm9000_rx(struct net_device *dev) } while (rxbyte & DM9000_PKT_RDY); } +#ifdef CONFIG_DM9000_USE_NAND_CONTROL +static void dm9000_interrupt_work(struct work_struct *work) +{ + board_info_t *db = container_of(work, board_info_t, dm9k_work); + struct net_device *dev = db->dev_id; + int int_status; + unsigned long flags; + u8 reg_save; + + //printk("entering %s\n", __FUNCTION__); + + /* A real interrupt coming */ + + /* holders of db->lock must always block IRQs */ + + while(!rk2818_nand_status_mutex_trylock()) + dev_dbg(db->dev, "fun:%s, nand busy\n", __func__); + + spin_lock_irqsave(&db->lock, flags); + + /* Save previous register address */ + reg_save = readb(db->io_addr); + + /* Disable all interrupts */ + iow(db, DM9000_IMR, IMR_PAR); + + /* Got DM9000 interrupt status */ + int_status = ior(db, DM9000_ISR); /* Got ISR */ + iow(db, DM9000_ISR, int_status); /* Clear ISR status */ + + if (netif_msg_intr(db)) + dev_dbg(db->dev, "interrupt status %02x\n", int_status); + + /* Received the coming packet */ + if (int_status & ISR_PRS) + dm9000_rx(dev); + + /* Trnasmit Interrupt check */ + if (int_status & ISR_PTS) + dm9000_tx_done(dev, db); + + if (db->type != TYPE_DM9000E) { + if (int_status & ISR_LNKCHNG) { + /* fire a link-change request */ + schedule_delayed_work(&db->phy_poll, 1); + } + } + + /* Re-enable interrupt mask */ + iow(db, DM9000_IMR, db->imr_all); + + /* Restore previous register address */ + writeb(reg_save, db->io_addr); + + spin_unlock_irqrestore(&db->lock, flags); + + rk2818_nand_status_mutex_unlock(); + + enable_irq(dev->irq); + +} + +static irqreturn_t dm9000_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + board_info_t *db = netdev_priv(dev); + + //printk("enter : %s\n", __FUNCTION__); + + db->dev_id = dev_id; + disable_irq_nosync(irq); + queue_work(db->dm9000_wq, &(db->dm9k_work)); + + return IRQ_HANDLED; +} +#else static irqreturn_t dm9000_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; @@ -1010,7 +1146,7 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id) /* A real interrupt coming */ - /* holders of db->lock must always block IRQs */ + /* holders of db->lock must always block IRQs */ spin_lock_irqsave(&db->lock, flags); /* Save previous register address */ @@ -1048,9 +1184,10 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id) writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock, flags); - + return IRQ_HANDLED; } +#endif #ifdef CONFIG_NET_POLL_CONTROLLER /* @@ -1074,6 +1211,11 @@ dm9000_open(struct net_device *dev) board_info_t *db = netdev_priv(dev); unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK; + #ifdef CONFIG_DM9000_USE_NAND_CONTROL + db->dm9000_wq = create_workqueue("dm9000 wq"); + INIT_WORK(&(db->dm9k_work), dm9000_interrupt_work); + #endif + if (netif_msg_ifup(db)) dev_dbg(db->dev, "enabling %s\n", dev->name); @@ -1128,8 +1270,11 @@ dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) mutex_lock(&db->addr_lock); - spin_lock_irqsave(&db->lock,flags); + while(!rk2818_nand_status_mutex_trylock()) + dev_dbg(db->dev, "fun:%s, nand busy\n", __func__); + spin_lock_irqsave(&db->lock,flags); + /* Save previous register address */ reg_save = readb(db->io_addr); @@ -1140,10 +1285,16 @@ dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock,flags); + + rk2818_nand_status_mutex_unlock(); dm9000_msleep(db, 1); /* Wait read complete */ + while(!rk2818_nand_status_mutex_trylock()) + dev_dbg(db->dev, "fun:%s, nand busy\n", __func__); + spin_lock_irqsave(&db->lock,flags); + reg_save = readb(db->io_addr); iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer read command */ @@ -1154,6 +1305,8 @@ dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) /* restore the previous address */ writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock,flags); + + rk2818_nand_status_mutex_unlock(); mutex_unlock(&db->addr_lock); @@ -1175,8 +1328,11 @@ dm9000_phy_write(struct net_device *dev, dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); mutex_lock(&db->addr_lock); - spin_lock_irqsave(&db->lock,flags); + while(!rk2818_nand_status_mutex_trylock()) + dev_dbg(db->dev, "fun:%s, nand busy\n", __func__); + spin_lock_irqsave(&db->lock,flags); + /* Save previous register address */ reg_save = readb(db->io_addr); @@ -1191,10 +1347,16 @@ dm9000_phy_write(struct net_device *dev, writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock, flags); + + rk2818_nand_status_mutex_unlock(); dm9000_msleep(db, 1); /* Wait write complete */ + while(!rk2818_nand_status_mutex_trylock()) + dev_dbg(db->dev, "fun:%s, nand busy\n", __func__); + spin_lock_irqsave(&db->lock,flags); + reg_save = readb(db->io_addr); iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */ @@ -1203,6 +1365,8 @@ dm9000_phy_write(struct net_device *dev, writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock, flags); + + rk2818_nand_status_mutex_unlock(); mutex_unlock(&db->addr_lock); } @@ -1240,6 +1404,10 @@ dm9000_stop(struct net_device *ndev) dm9000_shutdown(ndev); + #ifdef CONFIG_DM9000_USE_NAND_CONTROL + destroy_workqueue(db->dm9000_wq); + #endif + return 0; } @@ -1290,8 +1458,6 @@ dm9000_probe(struct platform_device *pdev) db->dev = &pdev->dev; db->ndev = ndev; - //db->debug_level = 5;//add by liuyx@20100511 - spin_lock_init(&db->lock); mutex_init(&db->addr_lock); @@ -1350,6 +1516,7 @@ dm9000_probe(struct platform_device *pdev) #if 0 ndev->irq = db->irq_res->start; #else//modify by liuyx@20100510 + rk2818_mux_api_set(GPIOE_SPI1_FLASH_SEL1_NAME, IOMUXA_GPIO1_A12); ndev->irq = gpio_to_irq(db->irq_res->start); #endif