dm9000 mutex with nandc

This commit is contained in:
刘益星
2010-05-28 08:56:59 +00:00
committed by 黄涛
parent 970ad9daac
commit b6e7fd4dbb
2 changed files with 520 additions and 84 deletions

View File

@@ -26,10 +26,13 @@
#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
@@ -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<<chip; // select chip
}
pRK28NC ->FMCTL |= 0x1<<chip;
}
/*
@@ -156,8 +178,9 @@ static u_char rk2818_nand_read_byte(struct mtd_info *mtd)
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;
}
@@ -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;i<mtd->writesize/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; // ȫ<><C8AB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>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; //<2F><><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD>
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; //<2F><><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD>
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; //<2F><><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD>
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; //<2F><><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD>
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;i<mtd->writesize/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;i<mtd->writesize/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;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;
}
@@ -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;i<mtd->writesize/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<<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)
{
@@ -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<<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);
@@ -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);

View File

@@ -38,6 +38,7 @@
#include <asm/irq.h>
#include <asm/io.h>
#include <mach/gpio.h>
#include <mach/iomux.h>
#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,19 +1058,24 @@ dm9000_rx(struct net_device *dev)
} while (rxbyte & DM9000_PKT_RDY);
}
static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
#ifdef CONFIG_DM9000_USE_NAND_CONTROL
static void dm9000_interrupt_work(struct work_struct *work)
{
struct net_device *dev = dev_id;
board_info_t *db = netdev_priv(dev);
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;
dm9000_dbg(db, 3, "entering %s\n", __func__);
//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 */
@@ -1048,9 +1113,81 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
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;
board_info_t *db = netdev_priv(dev);
int int_status;
unsigned long flags;
u8 reg_save;
dm9000_dbg(db, 3, "entering %s\n", __func__);
/* A real interrupt coming */
/* holders of db->lock must always block IRQs */
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);
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