summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuergen Beisert <jbe@pengutronix.de>2013-04-01 23:35:15 +0200
committerJuergen Beisert <jbe@pengutronix.de>2013-04-01 23:36:49 +0200
commit8cd132639fe9f4ad43e63618bd2df4723252eb99 (patch)
tree49be619dc94cd746e90dca3c93d8589220c04da6
parent9f3936f5097ee645f68d2d58d0199bb22328a87b (diff)
downloadOSELAS.BSP-Pengutronix-Mini2440-8cd132639fe9f4ad43e63618bd2df4723252eb99.tar.gz
OSELAS.BSP-Pengutronix-Mini2440-8cd132639fe9f4ad43e63618bd2df4723252eb99.tar.xz
Fix bug for DM9000 revision B which contain a DSP PHY
Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
-rw-r--r--patches/linux-3.8/dm9000B_driver_initialization_upgrade.patch297
-rw-r--r--patches/linux-3.8/series1
2 files changed, 298 insertions, 0 deletions
diff --git a/patches/linux-3.8/dm9000B_driver_initialization_upgrade.patch b/patches/linux-3.8/dm9000B_driver_initialization_upgrade.patch
new file mode 100644
index 0000000..abf4731
--- /dev/null
+++ b/patches/linux-3.8/dm9000B_driver_initialization_upgrade.patch
@@ -0,0 +1,297 @@
+From: Joseph CHANG <josright123@gmail.com>
+Subject: [PATCH 1/1] DM9000B: driver initialization upgrade
+
+Fix bug for DM9000 revision B which contain a DSP PHY
+
+DM9000B use DSP PHY instead previouse DM9000 revisions' analog PHY,
+So need extra change in initialization, For
+explicity PHY Reset and PHY init parameter, and
+first DM9000_NCR reset need NCR_MAC_LBK bit by dm9000_probe().
+
+Following DM9000_NCR reset cause by dm9000_open() clear the
+NCR_MAC_LBK bit.
+
+Without this fix, Power-up FIFO pointers error happen around 2%
+rate among Davicom's customers' boards. With this fix, All above
+cases can be solved.
+
+Signed-off-by: Joseph CHANG <josright123@gmail.com>
+---
+ drivers/net/ethernet/davicom/dm9000.c | 214 +++++++++++++++++-----------------
+ drivers/net/ethernet/davicom/dm9000.h | 11 +
+ 2 files changed, 120 insertions(+), 105 deletions(-)
+
+Index: linux-3.8/drivers/net/ethernet/davicom/dm9000.c
+===================================================================
+--- linux-3.8.orig/drivers/net/ethernet/davicom/dm9000.c
++++ linux-3.8/drivers/net/ethernet/davicom/dm9000.c
+@@ -265,6 +265,107 @@ static void dm9000_dumpblk_32bit(void __
+ tmp = readl(reg);
+ }
+
++/*
++ * Sleep, either by using msleep() or if we are suspending, then
++ * use mdelay() to sleep.
++ */
++static void dm9000_msleep(board_info_t *db, unsigned int ms)
++{
++ if (db->in_suspend)
++ mdelay(ms);
++ else
++ msleep(ms);
++}
++
++/* Read a word from phyxcer */
++static int
++dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg)
++{
++ board_info_t *db = netdev_priv(dev);
++ unsigned long flags;
++ unsigned int reg_save;
++ int ret;
++
++ mutex_lock(&db->addr_lock);
++
++ spin_lock_irqsave(&db->lock, flags);
++
++ /* Save previous register address */
++ reg_save = readb(db->io_addr);
++
++ /* Fill the phyxcer register into REG_0C */
++ iow(db, DM9000_EPAR, DM9000_PHY | reg);
++
++ /* Issue phyxcer read command */
++ iow(db, DM9000_EPCR, EPCR_ERPRR | EPCR_EPOS);
++
++ writeb(reg_save, db->io_addr);
++ spin_unlock_irqrestore(&db->lock, flags);
++
++ dm9000_msleep(db, 1); /* Wait read complete */
++
++ spin_lock_irqsave(&db->lock, flags);
++ reg_save = readb(db->io_addr);
++
++ iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer read command */
++
++ /* The read data keeps on REG_0D & REG_0E */
++ ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL);
++
++ /* restore the previous address */
++ writeb(reg_save, db->io_addr);
++ spin_unlock_irqrestore(&db->lock, flags);
++
++ mutex_unlock(&db->addr_lock);
++
++ dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret);
++ return ret;
++}
++
++/* Write a word to phyxcer */
++static void
++dm9000_phy_write(struct net_device *dev,
++ int phyaddr_unused, int reg, int value)
++{
++ board_info_t *db = netdev_priv(dev);
++ unsigned long flags;
++ unsigned long reg_save;
++
++ dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value);
++ mutex_lock(&db->addr_lock);
++
++ spin_lock_irqsave(&db->lock, flags);
++
++ /* Save previous register address */
++ reg_save = readb(db->io_addr);
++
++ /* Fill the phyxcer register into REG_0C */
++ iow(db, DM9000_EPAR, DM9000_PHY | reg);
++
++ /* Fill the written data into REG_0D & REG_0E */
++ iow(db, DM9000_EPDRL, value);
++ iow(db, DM9000_EPDRH, value >> 8);
++
++ /* Issue phyxcer write command */
++ iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW);
++
++ writeb(reg_save, db->io_addr);
++ spin_unlock_irqrestore(&db->lock, flags);
++
++ dm9000_msleep(db, 1); /* Wait write complete */
++
++ spin_lock_irqsave(&db->lock, flags);
++ reg_save = readb(db->io_addr);
++
++ iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */
++
++ /* restore the previous address */
++ writeb(reg_save, db->io_addr);
++
++ spin_unlock_irqrestore(&db->lock, flags);
++ mutex_unlock(&db->addr_lock);
++}
++
+ /* dm9000_set_io
+ *
+ * select the specified set of io routines to use with the
+@@ -802,6 +903,9 @@ dm9000_init_dm9000(struct net_device *de
+
+ iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */
+
++ dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET */
++ dm9000_phy_write(dev, 0, MII_DM_DSPCR, DSPCR_INIT_PARAM); /* Init */
++
+ ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0;
+
+ /* if wol is needed, then always set NCR_WAKEEN otherwise we end
+@@ -1214,109 +1318,6 @@ dm9000_open(struct net_device *dev)
+ return 0;
+ }
+
+-/*
+- * Sleep, either by using msleep() or if we are suspending, then
+- * use mdelay() to sleep.
+- */
+-static void dm9000_msleep(board_info_t *db, unsigned int ms)
+-{
+- if (db->in_suspend)
+- mdelay(ms);
+- else
+- msleep(ms);
+-}
+-
+-/*
+- * Read a word from phyxcer
+- */
+-static int
+-dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg)
+-{
+- board_info_t *db = netdev_priv(dev);
+- unsigned long flags;
+- unsigned int reg_save;
+- int ret;
+-
+- mutex_lock(&db->addr_lock);
+-
+- spin_lock_irqsave(&db->lock,flags);
+-
+- /* Save previous register address */
+- reg_save = readb(db->io_addr);
+-
+- /* Fill the phyxcer register into REG_0C */
+- iow(db, DM9000_EPAR, DM9000_PHY | reg);
+-
+- iow(db, DM9000_EPCR, EPCR_ERPRR | EPCR_EPOS); /* Issue phyxcer read command */
+-
+- writeb(reg_save, db->io_addr);
+- spin_unlock_irqrestore(&db->lock,flags);
+-
+- dm9000_msleep(db, 1); /* Wait read complete */
+-
+- spin_lock_irqsave(&db->lock,flags);
+- reg_save = readb(db->io_addr);
+-
+- iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer read command */
+-
+- /* The read data keeps on REG_0D & REG_0E */
+- ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL);
+-
+- /* restore the previous address */
+- writeb(reg_save, db->io_addr);
+- spin_unlock_irqrestore(&db->lock,flags);
+-
+- mutex_unlock(&db->addr_lock);
+-
+- dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret);
+- return ret;
+-}
+-
+-/*
+- * Write a word to phyxcer
+- */
+-static void
+-dm9000_phy_write(struct net_device *dev,
+- int phyaddr_unused, int reg, int value)
+-{
+- board_info_t *db = netdev_priv(dev);
+- unsigned long flags;
+- unsigned long reg_save;
+-
+- dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value);
+- mutex_lock(&db->addr_lock);
+-
+- spin_lock_irqsave(&db->lock,flags);
+-
+- /* Save previous register address */
+- reg_save = readb(db->io_addr);
+-
+- /* Fill the phyxcer register into REG_0C */
+- iow(db, DM9000_EPAR, DM9000_PHY | reg);
+-
+- /* Fill the written data into REG_0D & REG_0E */
+- iow(db, DM9000_EPDRL, value);
+- iow(db, DM9000_EPDRH, value >> 8);
+-
+- iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW); /* Issue phyxcer write command */
+-
+- writeb(reg_save, db->io_addr);
+- spin_unlock_irqrestore(&db->lock, flags);
+-
+- dm9000_msleep(db, 1); /* Wait write complete */
+-
+- spin_lock_irqsave(&db->lock,flags);
+- reg_save = readb(db->io_addr);
+-
+- iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */
+-
+- /* restore the previous address */
+- writeb(reg_save, db->io_addr);
+-
+- spin_unlock_irqrestore(&db->lock, flags);
+- mutex_unlock(&db->addr_lock);
+-}
+-
+ static void
+ dm9000_shutdown(struct net_device *dev)
+ {
+@@ -1515,7 +1516,12 @@ dm9000_probe(struct platform_device *pde
+ db->flags |= DM9000_PLATF_SIMPLE_PHY;
+ #endif
+
+- dm9000_reset(db);
++ /* Fixing bug on dm9000_probe, takeover dm9000_reset(db),
++ * Need 'NCR_MAC_LBK' bit to indeed stable our DM9000 fifo
++ * while probe stage.
++ */
++
++ iow(db, DM9000_NCR, NCR_MAC_LBK | NCR_RST);
+
+ /* try multiple times, DM9000 sometimes gets the read wrong */
+ for (i = 0; i < 8; i++) {
+Index: linux-3.8/drivers/net/ethernet/davicom/dm9000.h
+===================================================================
+--- linux-3.8.orig/drivers/net/ethernet/davicom/dm9000.h
++++ linux-3.8/drivers/net/ethernet/davicom/dm9000.h
+@@ -69,7 +69,9 @@
+ #define NCR_WAKEEN (1<<6)
+ #define NCR_FCOL (1<<4)
+ #define NCR_FDX (1<<3)
+-#define NCR_LBK (3<<1)
++
++#define NCR_RESERVED (3<<1)
++#define NCR_MAC_LBK (1<<1)
+ #define NCR_RST (1<<0)
+
+ #define NSR_SPEED (1<<7)
+@@ -167,5 +169,12 @@
+ #define ISR_LNKCHNG (1<<5)
+ #define ISR_UNDERRUN (1<<4)
+
++/* Davicom MII registers.
++ */
++
++#define MII_DM_DSPCR 0x1b /* DSP Control Register */
++
++#define DSPCR_INIT_PARAM 0xE100 /* DSP init parameter */
++
+ #endif /* _DM9000X_H_ */
+
diff --git a/patches/linux-3.8/series b/patches/linux-3.8/series
index 7c6e2cf..e8609ac 100644
--- a/patches/linux-3.8/series
+++ b/patches/linux-3.8/series
@@ -22,6 +22,7 @@ PATCH_2_3_rtc-s3c_Disable_alarm_entries_that_are_not_chosen.diff
# will be part of mainline some time
dm9000_Make_the_driver_follow_the_IRQF_SHARED_contract.patch
dm9000_Implement_full_reset_of_network_device.patch
+dm9000B_driver_initialization_upgrade.patch
# due to wrong option, mounting NAND is slow
speed_up_NAND_mounting.diff