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);
|
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
|
/* dm9000_set_io
|
||||||
*
|
*
|
||||||
* select the specified set of io routines to use with the
|
* 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 */
|
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;
|
ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0;
|
||||||
|
|
||||||
/* if wol is needed, then always set NCR_WAKEEN otherwise we end
|
/* if wol is needed, then always set NCR_WAKEEN otherwise we end
|
||||||
@ -1201,109 +1305,6 @@ dm9000_open(struct net_device *dev)
|
|||||||
return 0;
|
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
|
static void
|
||||||
dm9000_shutdown(struct net_device *dev)
|
dm9000_shutdown(struct net_device *dev)
|
||||||
{
|
{
|
||||||
@ -1502,7 +1503,12 @@ dm9000_probe(struct platform_device *pdev)
|
|||||||
db->flags |= DM9000_PLATF_SIMPLE_PHY;
|
db->flags |= DM9000_PLATF_SIMPLE_PHY;
|
||||||
#endif
|
#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 */
|
/* try multiple times, DM9000 sometimes gets the read wrong */
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
|
@ -69,7 +69,9 @@
|
|||||||
#define NCR_WAKEEN (1<<6)
|
#define NCR_WAKEEN (1<<6)
|
||||||
#define NCR_FCOL (1<<4)
|
#define NCR_FCOL (1<<4)
|
||||||
#define NCR_FDX (1<<3)
|
#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 NCR_RST (1<<0)
|
||||||
|
|
||||||
#define NSR_SPEED (1<<7)
|
#define NSR_SPEED (1<<7)
|
||||||
@ -167,5 +169,12 @@
|
|||||||
#define ISR_LNKCHNG (1<<5)
|
#define ISR_LNKCHNG (1<<5)
|
||||||
#define ISR_UNDERRUN (1<<4)
|
#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_ */
|
#endif /* _DM9000X_H_ */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user