From ee62ed3286f83b98b7785e0318dc6379e78f7ff6 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Tue, 15 Jan 2008 14:11:00 -0600 Subject: net: reduce boot latency on QE UEC based boards actually polling for PHY autonegotiation to finish enables us to remove the 5 second boot prompt latency present on QE based boards. call to qe_set_mii_clk_src in init_phy, and mv call to init_phy from uec_initialize to uec_init by Joakim Tjernlund; autonegotiation wait code shamelessly stolen from tsec driver. also rm unused CONFIG_RMII_MODE code. Signed-off-by: Kim Phillips Signed-off-by: Joakim Tjernlund Signed-off-by: Ben Warren --- drivers/qe/uec.c | 69 ++++++++++++++++++++++++++++++++-------------------- drivers/qe/uec_phy.c | 58 ++++++++++++++++++++++++++----------------- 2 files changed, 79 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c index 9094643912a..55f37cb55c3 100644 --- a/drivers/qe/uec.c +++ b/drivers/qe/uec.c @@ -512,6 +512,8 @@ static int init_phy(struct eth_device *dev) uec->mii_info = mii_info; + qe_set_mii_clk_src(uec->uec_info->uf_info.ucc_num); + if (init_mii_management_configuration(umii_regs)) { printf("%s: The MII Bus is stuck!", dev->name); err = -1; @@ -618,21 +620,12 @@ static void adjust_link(struct eth_device *dev) static void phy_change(struct eth_device *dev) { uec_private_t *uec = (uec_private_t *)dev->priv; - uec_t *uec_regs; - int result = 0; - - uec_regs = uec->uec_regs; - - /* Delay 5s to give the PHY a chance to change the register state */ - udelay(5000000); /* Update the link, speed, duplex */ - result = uec->mii_info->phyinfo->read_status(uec->mii_info); + uec->mii_info->phyinfo->read_status(uec->mii_info); /* Adjust the interface according to speed */ - if ((0 == result) || (uec->mii_info->link == 0)) { - adjust_link(dev); - } + adjust_link(dev); } static int uec_set_mac_address(uec_private_t *uec, u8 *mac_addr) @@ -1157,27 +1150,59 @@ static int uec_startup(uec_private_t *uec) static int uec_init(struct eth_device* dev, bd_t *bd) { uec_private_t *uec; - int err; + int err, i; + struct phy_info *curphy; uec = (uec_private_t *)dev->priv; if (uec->the_first_run == 0) { - /* Set up the MAC address */ - if (dev->enetaddr[0] & 0x01) { - printf("%s: MacAddress is multcast address\n", - __FUNCTION__); - return -1; + err = init_phy(dev); + if (err) { + printf("%s: Cannot initialize PHY, aborting.\n", + dev->name); + return err; } - uec_set_mac_address(uec, dev->enetaddr); + + curphy = uec->mii_info->phyinfo; + + if (curphy->config_aneg) { + err = curphy->config_aneg(uec->mii_info); + if (err) { + printf("%s: Can't negotiate PHY\n", dev->name); + return err; + } + } + + /* Give PHYs up to 5 sec to report a link */ + i = 50; + do { + err = curphy->read_status(uec->mii_info); + udelay(100000); + } while (((i-- > 0) && !uec->mii_info->link) || err); + + if (err || i <= 0) + printf("warning: %s: timeout on PHY link\n", dev->name); + uec->the_first_run = 1; } + /* Set up the MAC address */ + if (dev->enetaddr[0] & 0x01) { + printf("%s: MacAddress is multcast address\n", + __FUNCTION__); + return -1; + } + uec_set_mac_address(uec, dev->enetaddr); + + err = uec_open(uec, COMM_DIR_RX_AND_TX); if (err) { printf("%s: cannot enable UEC device\n", dev->name); return -1; } + phy_change(dev); + return (uec->mii_info->link ? 0 : -1); } @@ -1330,14 +1355,6 @@ int uec_initialize(int index) return err; } - err = init_phy(dev); - if (err) { - printf("%s: Cannot initialize PHY, aborting.\n", dev->name); - return err; - } - - phy_change(dev); - return 1; } #endif /* CONFIG_QE */ diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c index ca6faa6ef4e..f890d4fbfb2 100644 --- a/drivers/qe/uec_phy.c +++ b/drivers/qe/uec_phy.c @@ -77,11 +77,10 @@ void uec_write_phy_reg (struct eth_device *dev, int mii_id, int regnum, int valu /* Setting up the MII Mangement Control Register with the value */ out_be32 (&ug_regs->miimcon, (u32) value); + sync(); /* Wait till MII management write is complete */ while ((in_be32 (&ug_regs->miimind)) & MIIMIND_BUSY); - - udelay (100000); } /* Reads from register regnum in the PHY for device dev, */ @@ -101,16 +100,17 @@ int uec_read_phy_reg (struct eth_device *dev, int mii_id, int regnum) tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; out_be32 (&ug_regs->miimadd, tmp_reg); - /* Perform an MII management read cycle */ + /* clear MII management command cycle */ out_be32 (&ug_regs->miimcom, 0); + sync(); + + /* Perform an MII management read cycle */ out_be32 (&ug_regs->miimcom, MIIMCOM_READ_CYCLE); /* Wait till MII management write is complete */ while ((in_be32 (&ug_regs->miimind)) & (MIIMIND_NOT_VALID | MIIMIND_BUSY)); - udelay (100000); - /* Read MII management status */ value = (u16) in_be32 (&ug_regs->miimstat); if (value == 0xffff) @@ -270,20 +270,38 @@ static int genmii_update_link (struct uec_mii_info *mii_info) { u16 status; - /* Do a fake read */ + /* Status is read once to clear old link state */ phy_read (mii_info, PHY_BMSR); - /* Read link and autonegotiation status */ - status = phy_read (mii_info, PHY_BMSR); - if ((status & PHY_BMSR_LS) == 0) - mii_info->link = 0; - else + /* + * Wait if the link is up, and autonegotiation is in progress + * (ie - we're capable and it's not done) + */ + status = phy_read(mii_info, PHY_BMSR); + if ((status & PHY_BMSR_LS) && (status & PHY_BMSR_AUTN_ABLE) + && !(status & PHY_BMSR_AUTN_COMP)) { + int i = 0; + + while (!(status & PHY_BMSR_AUTN_COMP)) { + /* + * Timeout reached ? + */ + if (i > UGETH_AN_TIMEOUT) { + mii_info->link = 0; + return 0; + } + + udelay(1000); /* 1 ms */ + status = phy_read(mii_info, PHY_BMSR); + } mii_info->link = 1; - - /* If we are autonegotiating, and not done, - * return an error */ - if (mii_info->autoneg && !(status & PHY_BMSR_AUTN_COMP)) - return -EAGAIN; + udelay(500000); /* another 500 ms (results in faster booting) */ + } else { + if (status & PHY_BMSR_LS) + mii_info->link = 1; + else + mii_info->link = 0; + } return 0; } @@ -389,16 +407,12 @@ static int dm9161_init (struct uec_mii_info *mii_info) /* PHY and MAC connect */ phy_write (mii_info, PHY_BMCR, phy_read (mii_info, PHY_BMCR) & ~PHY_BMCR_ISO); -#ifdef CONFIG_RMII_MODE - phy_write (mii_info, MII_DM9161_SCR, MII_DM9161_SCR_RMII_INIT); -#else + phy_write (mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT); -#endif + config_genmii_advert (mii_info); /* Start/restart aneg */ genmii_config_aneg (mii_info); - /* Delay to wait the aneg compeleted */ - udelay (3000000); return 0; } -- cgit v1.2.3