tsec: Add support for using the BCM5482 PHY in fiber mode

The BCM5482 PHY supports both copper and fiber as an ethernet medium.
By enabling its copper/fiber mode auto-detection feature it can
dynamically determine if it should be configured for copper or fiber.

Signed-off-by: Peter Tyser <ptyser@xes-inc.com>
Signed-off-by: Ben Warren <biggerbadderben@gmail.com>
This commit is contained in:
Peter Tyser 2009-11-09 13:09:47 -06:00 committed by Ben Warren
parent c6dbdfda53
commit 8abb8dcc8d
2 changed files with 120 additions and 5 deletions

View file

@ -530,8 +530,105 @@ static uint mii_parse_BCM54xx_sr(uint mii_reg, struct tsec_private *priv)
}
return 0;
}
/*
* Find out if PHY is in copper or serdes mode by looking at Expansion Reg
* 0x42 - "Operating Mode Status Register"
*/
static int BCM8482_is_serdes(struct tsec_private *priv)
{
u16 val;
int serdes = 0;
write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_ER | 0x42);
val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA);
switch (val & 0x1f) {
case 0x0d: /* RGMII-to-100Base-FX */
case 0x0e: /* RGMII-to-SGMII */
case 0x0f: /* RGMII-to-SerDes */
case 0x12: /* SGMII-to-SerDes */
case 0x13: /* SGMII-to-100Base-FX */
case 0x16: /* SerDes-to-Serdes */
serdes = 1;
break;
case 0x6: /* RGMII-to-Copper */
case 0x14: /* SGMII-to-Copper */
case 0x17: /* SerDes-to-Copper */
break;
default:
printf("ERROR, invalid PHY mode (0x%x\n)", val);
break;
}
return serdes;
}
/*
* Determine SerDes link speed and duplex from Expansion reg 0x42 "Operating
* Mode Status Register"
*/
uint mii_parse_BCM5482_serdes_sr(struct tsec_private *priv)
{
u16 val;
int i = 0;
/* Wait 1s for link - Clause 37 autonegotiation happens very fast */
while (1) {
write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL,
MIIM_BCM54XX_EXP_SEL_ER | 0x42);
val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA);
if (val & 0x8000)
break;
if (i++ > 1000) {
priv->link = 0;
return 1;
}
udelay(1000); /* 1 ms */
}
priv->link = 1;
switch ((val >> 13) & 0x3) {
case (0x00):
priv->speed = 10;
break;
case (0x01):
priv->speed = 100;
break;
case (0x02):
priv->speed = 1000;
break;
}
priv->duplexity = (val & 0x1000) == 0x1000;
return 0;
}
/*
* Figure out if BCM5482 is in serdes or copper mode and determine link
* configuration accordingly
*/
static uint mii_parse_BCM5482_sr(uint mii_reg, struct tsec_private *priv)
{
if (BCM8482_is_serdes(priv)) {
mii_parse_BCM5482_serdes_sr(priv);
} else {
/* Wait for auto-negotiation to complete or fail */
mii_parse_sr(mii_reg, priv);
/* Parse BCM54xx copper aux status register */
mii_reg = read_phy_reg(priv, MIIM_BCM54xx_AUXSTATUS);
mii_parse_BCM54xx_sr(mii_reg, priv);
}
return 0;
}
/* Parse the 88E1011's status register for speed and duplex
* information
*/
@ -1091,15 +1188,20 @@ static struct phy_info phy_info_BCM5482S = {
/* Read Misc Control register and or in Ethernet@Wirespeed */
{MIIM_BCM54xx_AUXCNTL, 0, &mii_BCM54xx_wirespeed},
{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
/* Initial config/enable of secondary SerDes interface */
{MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x14, 0xf), NULL},
/* Write intial value to secondary SerDes Contol */
{MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_SSD | 0, NULL},
{MIIM_BCM54XX_EXP_DATA, MIIM_CONTROL_RESTART, NULL},
/* Enable copper/fiber auto-detect */
{MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x1e, 0x201)},
{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},
/* Determine copper/fiber, auto-negotiate, and read the result */
{MIIM_STATUS, miim_read, &mii_parse_BCM5482_sr},
{miim_end,}
},
(struct phy_cmd[]) { /* shutdown */

View file

@ -153,6 +153,19 @@
#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK 0x0700
#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT 8
#define MIIM_BCM54XX_SHD 0x1c /* 0x1c shadow registers */
#define MIIM_BCM54XX_SHD_WRITE 0x8000
#define MIIM_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10)
#define MIIM_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0)
#define MIIM_BCM54XX_SHD_WR_ENCODE(val, data) \
(MIIM_BCM54XX_SHD_WRITE | MIIM_BCM54XX_SHD_VAL(val) | \
MIIM_BCM54XX_SHD_DATA(data))
#define MIIM_BCM54XX_EXP_DATA 0x15 /* Expansion register data */
#define MIIM_BCM54XX_EXP_SEL 0x17 /* Expansion register select */
#define MIIM_BCM54XX_EXP_SEL_SSD 0x0e00 /* Secondary SerDes select */
#define MIIM_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */
/* Cicada Auxiliary Control/Status Register */
#define MIIM_CIS8201_AUX_CONSTAT 0x1c
#define MIIM_CIS8201_AUXCONSTAT_INIT 0x0004