#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/cpufreq.h>
#include <linux/err.h>
#include <linux/io.h>
#include <mach/rk2818_nand.h>
+#include <mach/rk2818_iomap.h>
+#include <mach/iomux.h>
#define PROGRAM_BUSY_COUNT 10000
#define ERASE_BUSY_COUNT 20000
/* 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;
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 */
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<<chip; // select chip
+ }
- pRK28NC ->FMCTL |= 0x1<<chip;
}
/*
pNANDC pRK28NC= (pNANDC)(master->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;
}
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;
}
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;
memcpy(buf+i*0x400,(u_char *)(pRK28NC->buf),0x400); // only use nandc sram0
}
}
+
+
+
+ rk2818_nand_select_chip(mtd,-1);
+
+ mutex_unlock(&rknand_mutex);
+
return;
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;i<mtd->writesize/0x400;i++)
{
memcpy((u_char *)(pRK28NC->buf),buf+i*0x400,0x400); // only use nandc sram0
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);
+
}
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 --;
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;
break;
case NAND_CMD_READ1:
- pRK28NC ->chip[0].cmd = command;
+ pRK28NC ->chip[master->cs].cmd = command;
break;
case NAND_CMD_READOOB:
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);
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;
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;
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;
}
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;i<mtd->writesize/0x400;i++)
{
pRK28NC ->BCHCTL = BCH_RST;
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;
}
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;i<mtd->writesize/0x400;i++)
{
memcpy((u_char *)(pRK28NC->buf),(buf+i*0x400),0x400); // only use nandc sram0
}
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;
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;i<mtd->writesize/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;
}
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;i<mtd->writesize/0x400;i++)
{
pRK28NC ->BCHCTL = BCH_RST;
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<<FMW_RWCS_OFFSET)|(rwpw<<FMW_RWPW_OFFSET)|(csrw<<FMW_CSRW_OFFSET);
+
+ mutex_unlock(&rknand_mutex);
+
+
+ return 0;
+}
+
+/* cpufreq driver support */
+
+#ifdef CONFIG_CPU_FREQ
+
+static int rk2818_nand_cpufreq_transition(struct notifier_block *nb, unsigned long val, void *data)
+{
+ struct rk2818_nand_mtd *info;
+ unsigned long newclk;
+
+ info = container_of(nb, struct rk2818_nand_mtd, freq_transition);
+ newclk = clk_get_rate(info->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)
{
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;
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<<FMW_RWCS_OFFSET)|(4<<FMW_RWPW_OFFSET)|(1<<FMW_CSRW_OFFSET);
pRK28NC ->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);
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) {
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:
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;
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);
#include <asm/irq.h>
#include <asm/io.h>
#include <mach/gpio.h>
+#include <mach/iomux.h>
#include "dm9000.h"
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);
} 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) { \
} \
} 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);
{
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;
}
}
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);
spin_unlock_irqrestore(&db->lock, flags);
+ rk2818_nand_status_mutex_unlock();
+
mutex_unlock(&db->addr_lock);
}
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);
}
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;
}
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]);
iow(db, DM9000_RCR, rcr);
spin_unlock_irqrestore(&db->lock, flags);
+
+ rk2818_nand_status_mutex_unlock();
}
/*
/* 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);
/* 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,
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);
}
spin_unlock_irqrestore(&db->lock, flags);
+
+ rk2818_nand_status_mutex_unlock();
/* free this SKB */
dev_kfree_skb(skb);
} 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;
/* 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 */
writeb(reg_save, db->io_addr);
spin_unlock_irqrestore(&db->lock, flags);
-
+
return IRQ_HANDLED;
}
+#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
/*
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);
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);
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 */
/* 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);
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);
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 */
writeb(reg_save, db->io_addr);
spin_unlock_irqrestore(&db->lock, flags);
+
+ rk2818_nand_status_mutex_unlock();
mutex_unlock(&db->addr_lock);
}
dm9000_shutdown(ndev);
+ #ifdef CONFIG_DM9000_USE_NAND_CONTROL
+ destroy_workqueue(db->dm9000_wq);
+ #endif
+
return 0;
}
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);
#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