diff options
author | Juergen Beisert <jbe@pengutronix.de> | 2013-04-01 23:35:15 +0200 |
---|---|---|
committer | Juergen Beisert <jbe@pengutronix.de> | 2013-04-01 23:36:49 +0200 |
commit | 8cd132639fe9f4ad43e63618bd2df4723252eb99 (patch) | |
tree | 49be619dc94cd746e90dca3c93d8589220c04da6 | |
parent | 9f3936f5097ee645f68d2d58d0199bb22328a87b (diff) | |
download | OSELAS.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.patch | 297 | ||||
-rw-r--r-- | patches/linux-3.8/series | 1 |
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 |