#include <asm/delay.h>
#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 dm9000_dbg(db, lev, msg...) do { \
if ((lev) < CONFIG_DM9000_DEBUGLEVEL && \
(lev) < db->debug_level) { \
} \
} while (0)
+#if defined(CONFIG_DM9000_USE_NAND_CONTROL) && defined(CONFIG_MTD_NAND_RK2818)
+extern void rk2818_nand_status_mutex_lock(void);
+extern int rk2818_nand_status_mutex_trylock(void);
+extern void rk2818_nand_status_mutex_unlock(void);
+#else
+static void rk2818_nand_status_mutex_lock(void){return;}
+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;
+
+ rk2818_nand_status_mutex_lock();
- 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);
+
+ rk2818_nand_status_mutex_lock();
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);
+
+ rk2818_nand_status_mutex_lock();
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);
+
+ rk2818_nand_status_mutex_lock();
- 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 */
+
+ rk2818_nand_status_mutex_lock();
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;
+ rk2818_nand_status_mutex_lock();
+
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__);
+
+ rk2818_nand_status_mutex_lock();
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);
+
+ rk2818_nand_status_mutex_lock();
+
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,
dm9000_dbg(db, 3, "%s:\n", __func__);
- if (db->tx_pkt_cnt > 1)
+ if (db->tx_pkt_cnt > 1) {
+ dev_dbg(db->dev, "netdev tx busy\n");
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);
do {
ior(db, DM9000_MRCMDX); /* Dummy read */
+ udelay(1);//add by lyx@20100713,or dm9000_rx will be error in high frequence
+
/* Get most updated data */
rxbyte = readb(db->io_data);
/* Status check: this byte must be 0 or 1 */
if (rxbyte & DM9000_PKT_ERR) {
dev_warn(db->dev, "status check fail: %d\n", rxbyte);
+ #if 0
iow(db, DM9000_RCR, 0x00); /* Stop Device */
- iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */
+ iow(db, DM9000_IMR, IMR_PAR); /* Stop INT request */
+ #else
+ dm9000_reset(db);
+ #endif
return;
}
} 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 */
+
+ rk2818_nand_status_mutex_lock();
+
+ 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);
+ rk2818_nand_status_mutex_lock();
+ 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 */
+ rk2818_nand_status_mutex_lock();
+
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);
+ rk2818_nand_status_mutex_lock();
+ 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 */
+ rk2818_nand_status_mutex_lock();
+
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;
}
/* fill in parameters for net-dev structure */
ndev->base_addr = (unsigned long)db->io_addr;
- ndev->irq = db->irq_res->start;
+ #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
+
/* ensure at least we have a default set of IO routines */
dm9000_set_io(db, iosize);
ndev->name, dm9000_type_to_char(db->type),
db->io_addr, db->io_data, ndev->irq,
ndev->dev_addr, mac_src);
+
+ dm9000_shutdown(ndev);//add by lyx@20100713, reduce power consume
+
return 0;
out: