net: reduce boot latency on QE UEC based boards
authorKim Phillips <kim.phillips@freescale.com>
Tue, 15 Jan 2008 20:11:00 +0000 (14:11 -0600)
committerBen Warren <biggerbadderben@gmail.com>
Wed, 16 Jan 2008 21:54:20 +0000 (16:54 -0500)
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>
Signed-off-by: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
Signed-off-by: Ben Warren <biggerbadderben@gmail.com>
drivers/qe/uec.c
drivers/qe/uec_phy.c

index 9094643912a40a6637783988dd670509bc3d48d4..55f37cb55c3007647b07ee136aa3faf94b11a73f 100644 (file)
@@ -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 */
index ca6faa6ef4e25cadbd1ddc3d6e13c6150e649438..f890d4fbfb21a6a83e67345522e8228c4442cfaa 100644 (file)
@@ -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;
 }