[U-Boot-Users] [PATCH] net: reduce boot latency on QE UEC based boards
Kim Phillips
kim.phillips at freescale.com
Tue Jan 15 21:11:00 CET 2008
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 <kim.phillips at freescale.com>
---
tested on mpc8360emds, mpc832xemds, and mpc8323erdb.
Ben, this should probably go through your net tree.
Joakim, your Acked-by: (or Signed-off-by: even) is welcome here.
Thank you,
Kim
drivers/qe/uec.c | 69 +++++++++++++++++++++++++++++++-------------------
drivers/qe/uec_phy.c | 58 ++++++++++++++++++++++++++----------------
2 files changed, 79 insertions(+), 48 deletions(-)
diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c
index 6cb25bf..b1a952c 100644
--- a/drivers/qe/uec.c
+++ b/drivers/qe/uec.c
@@ -475,6 +475,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;
@@ -581,21 +583,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)
@@ -1120,27 +1113,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);
}
@@ -1289,14 +1314,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 ca6faa6..f890d4f 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;
}
--
1.5.3
More information about the U-Boot
mailing list