Skip to content

Commit

Permalink
DM9000B: driver initialization upgrade
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
josright123 authored and davem330 committed Mar 31, 2013
1 parent 3340d2a commit 6741f40
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 105 deletions.
214 changes: 110 additions & 104 deletions drivers/net/ethernet/davicom/dm9000.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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++) {
Expand Down
11 changes: 10 additions & 1 deletion drivers/net/ethernet/davicom/dm9000.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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_ */

0 comments on commit 6741f40

Please sign in to comment.