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> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
3340d2aae3
commit
6741f40d19
@ -257,6 +257,107 @@ static void dm9000_dumpblk_32bit(void __iomem *reg, int count)
|
||||
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
|
||||
@ -795,6 +896,9 @@ dm9000_init_dm9000(struct net_device *dev)
|
||||
|
||||
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
|
||||
@ -1201,109 +1305,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)
|
||||
{
|
||||
@ -1502,7 +1503,12 @@ dm9000_probe(struct platform_device *pdev)
|
||||
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++) {
|
||||
|
@ -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_ */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user