
Adds support for configuring the TBI to talk properly with the SerDes.
Signed-off-by: Andy Fleming afleming@freescale.com --- drivers/net/tsec.c | 74 +++++++++++++++++++++++++++++++++------------------ include/tsec.h | 25 +++++++++++++++++- 2 files changed, 72 insertions(+), 27 deletions(-)
diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index d723b74..d5c1da2 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -216,61 +216,80 @@ int tsec_init(struct eth_device *dev, bd_t * bd) return (priv->link ? 0 : -1); }
-/* Write value to the device's PHY through the registers - * specified in priv, modifying the register specified in regnum. - * It will wait for the write to be done (or for a timeout to - * expire) before exiting - */ -void write_any_phy_reg(struct tsec_private *priv, uint phyid, uint regnum, uint value) +/* Writes the given phy's reg with value, using the specified MDIO regs */ +static void tsec_local_mdio_write(volatile tsec_t *phyregs, uint addr, + uint reg, uint value) { - volatile tsec_t *regbase = priv->phyregs; int timeout = 1000000;
- regbase->miimadd = (phyid << 8) | regnum; - regbase->miimcon = value; + phyregs->miimadd = (addr << 8) | reg; + phyregs->miimcon = value; asm("sync");
timeout = 1000000; - while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ; + while ((phyregs->miimind & MIIMIND_BUSY) && timeout--) ; }
-/* #define to provide old write_phy_reg functionality without duplicating code */ -#define write_phy_reg(priv, regnum, value) write_any_phy_reg(priv,priv->phyaddr,regnum,value) + +/* Provide the default behavior of writing the PHY of this ethernet device */ +#define write_phy_reg(priv, regnum, value) tsec_local_mdio_write(priv->phyregs,priv->phyaddr,regnum,value)
/* Reads register regnum on the device's PHY through the - * registers specified in priv. It lowers and raises the read + * specified registers. It lowers and raises the read * command, and waits for the data to become valid (miimind * notvalid bit cleared), and the bus to cease activity (miimind * busy bit cleared), and then returns the value */ -uint read_any_phy_reg(struct tsec_private *priv, uint phyid, uint regnum) +uint tsec_local_mdio_read(volatile tsec_t *phyregs, uint phyid, uint regnum) { uint value; - volatile tsec_t *regbase = priv->phyregs;
/* Put the address of the phy, and the register * number into MIIMADD */ - regbase->miimadd = (phyid << 8) | regnum; + phyregs->miimadd = (phyid << 8) | regnum;
/* Clear the command register, and wait */ - regbase->miimcom = 0; + phyregs->miimcom = 0; asm("sync");
/* Initiate a read command, and wait */ - regbase->miimcom = MIIM_READ_COMMAND; + phyregs->miimcom = MIIM_READ_COMMAND; asm("sync");
/* Wait for the the indication that the read is done */ - while ((regbase->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))) ; + while ((phyregs->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))) ;
/* Grab the value read from the PHY */ - value = regbase->miimstat; + value = phyregs->miimstat;
return value; }
/* #define to provide old read_phy_reg functionality without duplicating code */ -#define read_phy_reg(priv,regnum) read_any_phy_reg(priv,priv->phyaddr,regnum) +#define read_phy_reg(priv,regnum) tsec_local_mdio_read(priv->phyregs,priv->phyaddr,regnum) + +#define TBIANA_SETTINGS ( \ + TBIANA_ASYMMETRIC_PAUSE \ + | TBIANA_SYMMETRIC_PAUSE \ + | TBIANA_FULL_DUPLEX \ + ) + +#define TBICR_SETTINGS ( \ + TBICR_PHY_RESET \ + | TBICR_ANEG_ENABLE \ + | TBICR_FULL_DUPLEX \ + | TBICR_SPEED1_SET \ + ) +/* Configure the TBI for SGMII operation */ +static void tsec_configure_serdes(struct tsec_private *priv) +{ + tsec_local_mdio_write(priv->phyregs, CFG_TBIPA_VALUE, TBI_ANA, + TBIANA_SETTINGS); + tsec_local_mdio_write(priv->phyregs, CFG_TBIPA_VALUE, TBI_TBICON, + TBICON_CLK_SELECT); + tsec_local_mdio_write(priv->phyregs, CFG_TBIPA_VALUE, TBI_CR, + TBICR_SETTINGS); +}
/* Discover which PHY is attached to the device, and configure it * properly. If the PHY is not recognized, then return 0 @@ -280,12 +299,12 @@ static int init_phy(struct eth_device *dev) { struct tsec_private *priv = (struct tsec_private *)dev->priv; struct phy_info *curphy; - volatile tsec_t *regs = (volatile tsec_t *)(TSEC_BASE_ADDR); + volatile tsec_t *phyregs = priv->phyregs; + volatile tsec_t *regs = priv->regs;
/* Assign a Physical address to the TBI */ regs->tbipa = CFG_TBIPA_VALUE; - regs = (volatile tsec_t *)(TSEC_BASE_ADDR + TSEC_SIZE); - regs->tbipa = CFG_TBIPA_VALUE; + phyregs->tbipa = CFG_TBIPA_VALUE; asm("sync");
/* Reset MII (due to new addresses) */ @@ -309,6 +328,9 @@ static int init_phy(struct eth_device *dev) return 0; }
+ if (regs->ecntrl & ECNTRL_SGMII_MODE) + tsec_configure_serdes(priv); + priv->phyinfo = curphy;
phy_run_commands(priv, priv->phyinfo->config); @@ -1651,7 +1673,7 @@ static int tsec_miiphy_read(char *devname, unsigned char addr, return -1; }
- ret = (unsigned short)read_any_phy_reg(priv, addr, reg); + ret = (unsigned short)tsec_local_mdio_read(priv->phyregs, addr, reg); *value = ret;
return 0; @@ -1673,7 +1695,7 @@ static int tsec_miiphy_write(char *devname, unsigned char addr, return -1; }
- write_any_phy_reg(priv, addr, reg, value); + tsec_local_mdio_write(priv->phyregs, addr, reg, value);
return 0; } diff --git a/include/tsec.h b/include/tsec.h index fece074..4959bdb 100644 --- a/include/tsec.h +++ b/include/tsec.h @@ -60,6 +60,27 @@
#define PHY_AUTONEGOTIATE_TIMEOUT 5000 /* in ms */
+/* TBI register addresses */ +#define TBI_CR 0x00 +#define TBI_SR 0x01 +#define TBI_ANA 0x04 +#define TBI_ANLPBPA 0x05 +#define TBI_ANEX 0x06 +#define TBI_TBICON 0x11 + +/* TBI MDIO register bit fields*/ +#define TBICON_CLK_SELECT 0x0020 +#define TBIANA_ASYMMETRIC_PAUSE 0x0100 +#define TBIANA_SYMMETRIC_PAUSE 0x0080 +#define TBIANA_HALF_DUPLEX 0x0040 +#define TBIANA_FULL_DUPLEX 0x0020 +#define TBICR_PHY_RESET 0x8000 +#define TBICR_ANEG_ENABLE 0x1000 +#define TBICR_RESTART_ANEG 0x0200 +#define TBICR_FULL_DUPLEX 0x0100 +#define TBICR_SPEED1_SET 0x0040 + + /* MAC register bits */ #define MACCFG1_SOFT_RESET 0x80000000 #define MACCFG1_RESET_RX_MC 0x00080000 @@ -533,7 +554,9 @@ typedef struct tsec
/* This flag currently only has * meaning if we're using the eTSEC */ -#define TSEC_REDUCED (1 << 1) +#define TSEC_REDUCED (1 << 1) + +#define TSEC_SGMII (1 << 2)
struct tsec_private { volatile tsec_t *regs;