[U-Boot-Users] [PATCH] 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 kim.phillips@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; }

On Tue, 2008-01-15 at 14:11 -0600, Kim Phillips wrote:
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@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
Great!
Tested on my 2 boards with current git. Happy to add my signed off:
Signed-off-by: Joakim Tjernlund Joakim.Tjernlund@transmode.se
I would like to add this tiny patch on top though:
From a50cec4bd95e9ec37d0a63e19a6c02c499e76799 Mon Sep 17 00:00:00 2001
From: Joakim Tjernlund Joakim.Tjernlund@transmode.se Date: Wed, 16 Jan 2008 09:40:41 +0100 Subject: [PATCH] Remove annoying debug printout for PHY less boards.
PHY less board prints out lots of "read wrong ...": read wrong value : mii_id 3,mii_reg 2, base e0102320 read wrong value : mii_id 3,mii_reg 3, base e0102320 UEC: PHY is Generic MII (ffffffff) read wrong value : mii_id 3,mii_reg 4, base e0102320 read wrong value : mii_id 3,mii_reg 0, base e0102320 read wrong value : mii_id 3,mii_reg 1, base e0102320 read wrong value : mii_id 3,mii_reg 1, base e0102320 read wrong value : mii_id 3,mii_reg 5, base e0102320 read wrong value : mii_id 3,mii_reg 1, base e0102320 read wrong value : mii_id 3,mii_reg 1, base e0102320 read wrong value : mii_id 3,mii_reg 5, base e0102320 FSL UEC0: Full Duplex FSL UEC0: Speed 100BT FSL UEC0: Link is up Using FSL UEC0 device
Make this printout depend on UEC_VERBOSE_DEBUG and remove its definition in uec_phy.c
Signed-off-by: Joakim Tjernlund Joakim.Tjernlund@transmode.se --- drivers/qe/uec_phy.c | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-)
diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c index f890d4f..c549b6b 100644 --- a/drivers/qe/uec_phy.c +++ b/drivers/qe/uec_phy.c @@ -28,7 +28,6 @@
#if defined(CONFIG_QE)
-#define UEC_VERBOSE_DEBUG #define ugphy_printk(format, arg...) \ printf(format "\n", ## arg)
@@ -114,7 +113,7 @@ int uec_read_phy_reg (struct eth_device *dev, int mii_id, int regnum) /* Read MII management status */ value = (u16) in_be32 (&ug_regs->miimstat); if (value == 0xffff) - ugphy_warn + ugphy_vdbg ("read wrong value : mii_id %d,mii_reg %d, base %08x", mii_id, mii_reg, (u32) & (ug_regs->miimcfg));
participants (2)
-
Joakim Tjernlund
-
Kim Phillips