diff options
| author | Kim Phillips <kim.phillips@freescale.com> | 2008-01-15 14:11:00 -0600 | 
|---|---|---|
| committer | Ben Warren <biggerbadderben@gmail.com> | 2008-01-16 16:54:20 -0500 | 
| commit | ee62ed3286f83b98b7785e0318dc6379e78f7ff6 (patch) | |
| tree | b3cdde40e5e3eeb227186d9171f0c9d0f2d105b5 | |
| parent | 55fe7c57a8b99a130925052dcdbb77f053dc50e3 (diff) | |
| download | olio-uboot-2014.01-ee62ed3286f83b98b7785e0318dc6379e78f7ff6.tar.xz olio-uboot-2014.01-ee62ed3286f83b98b7785e0318dc6379e78f7ff6.zip | |
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>
Signed-off-by: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
Signed-off-by: Ben Warren <biggerbadderben@gmail.com>
| -rw-r--r-- | drivers/qe/uec.c | 69 | ||||
| -rw-r--r-- | 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 909464391..55f37cb55 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 ca6faa6ef..f890d4fbf 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 -		mii_info->link = 1; +	/* +	 * 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; +			} -	/* If we are autonegotiating, and not done, -	 * return an error */ -	if (mii_info->autoneg && !(status & PHY_BMSR_AUTN_COMP)) -		return -EAGAIN; +			udelay(1000);	/* 1 ms */ +			status = phy_read(mii_info, PHY_BMSR); +		} +		mii_info->link = 1; +		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;  } |