diff options
Diffstat (limited to 'drivers/tsec.c')
| -rw-r--r-- | drivers/tsec.c | 183 | 
1 files changed, 182 insertions, 1 deletions
| diff --git a/drivers/tsec.c b/drivers/tsec.c index 2524e4f6d..b4187739c 100644 --- a/drivers/tsec.c +++ b/drivers/tsec.c @@ -5,7 +5,7 @@   * terms of the GNU Public License, Version 2, incorporated   * herein by reference.   * - * Copyright 2004 Freescale Semiconductor. + * Copyright 2004, 2007 Freescale Semiconductor, Inc.   * (C) Copyright 2003, Motorola, Inc.   * author Andy Fleming   * @@ -66,7 +66,11 @@ struct tsec_info_struct {   */  static struct tsec_info_struct tsec_info[] = {  #if defined(CONFIG_MPC85XX_TSEC1) || defined(CONFIG_MPC83XX_TSEC1) +#if defined(CONFIG_MPC8544DS) +	{TSEC1_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC1_PHYIDX}, +#else  	{TSEC1_PHY_ADDR, TSEC_GIGABIT, TSEC1_PHYIDX}, +#endif  #elif defined(CONFIG_MPC86XX_TSEC1)  	{TSEC1_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC1_PHYIDX},  #else @@ -381,6 +385,131 @@ uint mii_parse_sr(uint mii_reg, struct tsec_private * priv)  	return 0;  } +/* Generic function which updates the speed and duplex.  If + * autonegotiation is enabled, it uses the AND of the link + * partner's advertised capabilities and our advertised + * capabilities.  If autonegotiation is disabled, we use the + * appropriate bits in the control register. + * + * Stolen from Linux's mii.c and phy_device.c + */ +uint mii_parse_link(uint mii_reg, struct tsec_private *priv) +{ +	/* We're using autonegotiation */ +	if (mii_reg & PHY_BMSR_AUTN_ABLE) { +		uint lpa = 0; +		uint gblpa = 0; + +		/* Check for gigabit capability */ +		if (mii_reg & PHY_BMSR_EXT) { +			/* We want a list of states supported by +			 * both PHYs in the link +			 */ +			gblpa = read_phy_reg(priv, PHY_1000BTSR); +			gblpa &= read_phy_reg(priv, PHY_1000BTCR) << 2; +		} + +		/* Set the baseline so we only have to set them +		 * if they're different +		 */ +		priv->speed = 10; +		priv->duplexity = 0; + +		/* Check the gigabit fields */ +		if (gblpa & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) { +			priv->speed = 1000; + +			if (gblpa & PHY_1000BTSR_1000FD) +				priv->duplexity = 1; + +			/* We're done! */ +			return 0; +		} + +		lpa = read_phy_reg(priv, PHY_ANAR); +		lpa &= read_phy_reg(priv, PHY_ANLPAR); + +		if (lpa & (PHY_ANLPAR_TXFD | PHY_ANLPAR_TX)) { +			priv->speed = 100; + +			if (lpa & PHY_ANLPAR_TXFD) +				priv->duplexity = 1; + +		} else if (lpa & PHY_ANLPAR_10FD) +			priv->duplexity = 1; +	} else { +		uint bmcr = read_phy_reg(priv, PHY_BMCR); + +		priv->speed = 10; +		priv->duplexity = 0; + +		if (bmcr & PHY_BMCR_DPLX) +			priv->duplexity = 1; + +		if (bmcr & PHY_BMCR_1000_MBPS) +			priv->speed = 1000; +		else if (bmcr & PHY_BMCR_100_MBPS) +			priv->speed = 100; +	} + +	return 0; +} + +/* + * Parse the BCM54xx status register for speed and duplex information. + * The linux sungem_phy has this information, but in a table format. + */ +uint mii_parse_BCM54xx_sr(uint mii_reg, struct tsec_private *priv) +{ + +	switch((mii_reg & MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK) >> MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT){ + +		case 1: +			printf("Enet starting in 10BT/HD\n"); +			priv->duplexity = 0; +			priv->speed = 10; +			break; + +		case 2: +			printf("Enet starting in 10BT/FD\n"); +			priv->duplexity = 1; +			priv->speed = 10; +			break; + +		case 3: +			printf("Enet starting in 100BT/HD\n"); +			priv->duplexity = 0; +			priv->speed = 100; +			break; + +		case 5: +			printf("Enet starting in 100BT/FD\n"); +			priv->duplexity = 1; +			priv->speed = 100; +			break; + +		case 6: +			printf("Enet starting in 1000BT/HD\n"); +			priv->duplexity = 0; +			priv->speed = 1000; +			break; + +		case 7: +			printf("Enet starting in 1000BT/FD\n"); +			priv->duplexity = 1; +			priv->speed = 1000; +			break; + +		default: +			printf("Auto-neg error, defaulting to 10BT/HD\n"); +			priv->duplexity = 0; +			priv->speed = 10; +			break; +	} + +	return 0; + +}  /* Parse the 88E1011's status register for speed and duplex   * information   */ @@ -663,6 +792,7 @@ static void startup_tsec(struct eth_device *dev)  	/* Start up the PHY */  	if(priv->phyinfo)  		phy_run_commands(priv, priv->phyinfo->startup); +  	adjust_link(dev);  	/* Enable Transmit and Receive */ @@ -770,6 +900,34 @@ static void tsec_halt(struct eth_device *dev)  		phy_run_commands(priv, priv->phyinfo->shutdown);  } +/* The 5411 id is 0x206070, the 5421 is 0x2060e0 */ +struct phy_info phy_info_BCM5461S = { +	0x02060c1,	/* 5461 ID */ +	"Broadcom BCM5461S", +	0, /* not clear to me what minor revisions we can shift away */ +	(struct phy_cmd[]) { /* config */ +		/* Reset and configure the PHY */ +		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, +		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, +		{MIIM_ANAR, MIIM_ANAR_INIT, NULL}, +		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, +		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* startup */ +		/* Status is read once to clear old link state */ +		{MIIM_STATUS, miim_read, NULL}, +		/* Auto-negotiate */ +		{MIIM_STATUS, miim_read, &mii_parse_sr}, +		/* Read the status */ +		{MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* shutdown */ +		{miim_end,} +	}, +}; +  struct phy_info phy_info_M88E1011S = {  	0x01410c6,  	"Marvell 88E1011S", @@ -1005,6 +1163,27 @@ struct phy_info phy_info_dm9161 = {  			   {miim_end,}  			   },  }; +/* a generic flavor.  */ +struct phy_info phy_info_generic =  { +	0, +	"Unknown/Generic PHY", +	32, +	(struct phy_cmd[]) { /* config */ +		{PHY_BMCR, PHY_BMCR_RESET, NULL}, +		{PHY_BMCR, PHY_BMCR_AUTON|PHY_BMCR_RST_NEG, NULL}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* startup */ +		{PHY_BMSR, miim_read, NULL}, +		{PHY_BMSR, miim_read, &mii_parse_sr}, +		{PHY_BMSR, miim_read, &mii_parse_link}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* shutdown */ +		{miim_end,} +	} +}; +  uint mii_parse_lxt971_sr2(uint mii_reg, struct tsec_private *priv)  { @@ -1112,6 +1291,7 @@ struct phy_info phy_info_dp83865 = {  struct phy_info *phy_info[] = {  	&phy_info_cis8204,  	&phy_info_cis8201, +	&phy_info_BCM5461S,  	&phy_info_M88E1011S,  	&phy_info_M88E1111S,  	&phy_info_M88E1145, @@ -1119,6 +1299,7 @@ struct phy_info *phy_info[] = {  	&phy_info_lxt971,  	&phy_info_VSC8244,  	&phy_info_dp83865, +	&phy_info_generic,  	NULL  }; |