- /* Access TBI PHY registers at given TSEC register offset as opposed to the
- * register offset used for external PHY accesses */
- tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, TBI_ANA,
- TBIANA_SETTINGS);
- tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, TBI_TBICON,
- TBICON_CLK_SELECT);
- tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, 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
- * (failure). Otherwise, return 1
- */
-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 = priv->regs;
-
- /* Assign a Physical address to the TBI */
- regs->tbipa = CONFIG_SYS_TBIPA_VALUE;
- asm("sync");
-
- /* Reset MII (due to new addresses) */
- priv->phyregs->miimcfg = MIIMCFG_RESET;
- asm("sync");
- priv->phyregs->miimcfg = MIIMCFG_INIT_VALUE;
- asm("sync");
- while (priv->phyregs->miimind & MIIMIND_BUSY) ;
-
- /* Get the cmd structure corresponding to the attached
- * PHY */
- curphy = get_phy_info(dev);
-
- if (curphy == NULL) {
- priv->phyinfo = NULL;
- printf("%s: No PHY found\n", dev->name);
-
- return 0;
- }
-
- if (regs->ecntrl & ECNTRL_SGMII_MODE)
- tsec_configure_serdes(priv);
-
- priv->phyinfo = curphy;
-
- phy_run_commands(priv, priv->phyinfo->config);
-
- return 1;
-}
-
-/*
- * Returns which value to write to the control register.
- * For 10/100, the value is slightly different
- */
-uint mii_cr_init(uint mii_reg, struct tsec_private * priv)
-{
- if (priv->flags & TSEC_GIGABIT)
- return MIIM_CONTROL_INIT;
- else
- return MIIM_CR_INIT;
-}
-
-/*
- * Wait for auto-negotiation to complete, then determine link
- */
-uint mii_parse_sr(uint mii_reg, struct tsec_private * priv)
-{
- /*
- * Wait if the link is up, and autonegotiation is in progress
- * (ie - we're capable and it's not done)
- */
- mii_reg = read_phy_reg(priv, MIIM_STATUS);
- if ((mii_reg & PHY_BMSR_AUTN_ABLE) && !(mii_reg & PHY_BMSR_AUTN_COMP)) {
- int i = 0;
-
- puts("Waiting for PHY auto negotiation to complete");
- while (!(mii_reg & PHY_BMSR_AUTN_COMP)) {
- /*
- * Timeout reached ?
- */
- if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
- puts(" TIMEOUT !\n");
- priv->link = 0;
- return 0;
- }
-
- if (ctrlc()) {
- puts("user interrupt!\n");
- priv->link = 0;
- return -EINTR;
- }
-
- if ((i++ % 1000) == 0) {
- putc('.');
- }
- udelay(1000); /* 1 ms */
- mii_reg = read_phy_reg(priv, MIIM_STATUS);
- }
- puts(" done\n");
-
- /* Link status bit is latched low, read it again */
- mii_reg = read_phy_reg(priv, MIIM_STATUS);
-
- udelay(500000); /* another 500 ms (results in faster booting) */
- }
-
- priv->link = mii_reg & MIIM_STATUS_LINK ? 1 : 0;
-
- 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;
-}
-
-/*
- * "Ethernet@Wirespeed" needs to be enabled to achieve link in certain
- * circumstances. eg a gigabit TSEC connected to a gigabit switch with
- * a 4-wire ethernet cable. Both ends advertise gigabit, but can't
- * link. "Ethernet@Wirespeed" reduces advertised speed until link
- * can be achieved.
- */
-uint mii_BCM54xx_wirespeed(uint mii_reg, struct tsec_private *priv)
-{
- return (read_phy_reg(priv, mii_reg) & 0x8FFF) | 0x8010;
-}
-
-/*
- * 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
- */
-uint mii_parse_88E1011_psr(uint mii_reg, struct tsec_private * priv)
-{
- uint speed;
-
- mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);
-
- if ((mii_reg & MIIM_88E1011_PHYSTAT_LINK) &&
- !(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
- int i = 0;
-
- puts("Waiting for PHY realtime link");
- while (!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
- /* Timeout reached ? */
- if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
- puts(" TIMEOUT !\n");
- priv->link = 0;
- break;
- }
-
- if ((i++ % 1000) == 0) {
- putc('.');
- }
- udelay(1000); /* 1 ms */
- mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS);
- }
- puts(" done\n");
- udelay(500000); /* another 500 ms (results in faster booting) */
- } else {
- if (mii_reg & MIIM_88E1011_PHYSTAT_LINK)
- priv->link = 1;
- else
- priv->link = 0;
- }
-
- if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX)
- priv->duplexity = 1;
- else
- priv->duplexity = 0;
-
- speed = (mii_reg & MIIM_88E1011_PHYSTAT_SPEED);
-
- switch (speed) {
- case MIIM_88E1011_PHYSTAT_GBIT:
- priv->speed = 1000;
- break;
- case MIIM_88E1011_PHYSTAT_100:
- priv->speed = 100;
- break;
- default:
- priv->speed = 10;
- }
-
- return 0;
-}
-
-/* Parse the RTL8211B's status register for speed and duplex
- * information
- */
-uint mii_parse_RTL8211B_sr(uint mii_reg, struct tsec_private * priv)
-{
- uint speed;
-
- mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS);
- if (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
- int i = 0;
-
- /* in case of timeout ->link is cleared */
- priv->link = 1;
- puts("Waiting for PHY realtime link");
- while (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
- /* Timeout reached ? */
- if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
- puts(" TIMEOUT !\n");
- priv->link = 0;
- break;
- }
-
- if ((i++ % 1000) == 0) {
- putc('.');
- }
- udelay(1000); /* 1 ms */
- mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS);
- }
- puts(" done\n");
- udelay(500000); /* another 500 ms (results in faster booting) */
- } else {
- if (mii_reg & MIIM_RTL8211B_PHYSTAT_LINK)
- priv->link = 1;
- else
- priv->link = 0;
- }
-
- if (mii_reg & MIIM_RTL8211B_PHYSTAT_DUPLEX)
- priv->duplexity = 1;
- else
- priv->duplexity = 0;
-
- speed = (mii_reg & MIIM_RTL8211B_PHYSTAT_SPEED);
-
- switch (speed) {
- case MIIM_RTL8211B_PHYSTAT_GBIT:
- priv->speed = 1000;
- break;
- case MIIM_RTL8211B_PHYSTAT_100:
- priv->speed = 100;
- break;
- default:
- priv->speed = 10;
- }
-
- return 0;
-}
-
-/* Parse the cis8201's status register for speed and duplex
- * information
- */
-uint mii_parse_cis8201(uint mii_reg, struct tsec_private * priv)
-{
- uint speed;
-
- if (mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX)
- priv->duplexity = 1;
- else
- priv->duplexity = 0;
-
- speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED;
- switch (speed) {
- case MIIM_CIS8201_AUXCONSTAT_GBIT:
- priv->speed = 1000;
- break;
- case MIIM_CIS8201_AUXCONSTAT_100:
- priv->speed = 100;
- break;
- default:
- priv->speed = 10;
- break;
- }
-
- return 0;
-}
-
-/* Parse the vsc8244's status register for speed and duplex
- * information
- */
-uint mii_parse_vsc8244(uint mii_reg, struct tsec_private * priv)
-{
- uint speed;
-
- if (mii_reg & MIIM_VSC8244_AUXCONSTAT_DUPLEX)
- priv->duplexity = 1;
- else
- priv->duplexity = 0;
-
- speed = mii_reg & MIIM_VSC8244_AUXCONSTAT_SPEED;
- switch (speed) {
- case MIIM_VSC8244_AUXCONSTAT_GBIT:
- priv->speed = 1000;
- break;
- case MIIM_VSC8244_AUXCONSTAT_100:
- priv->speed = 100;
- break;
- default:
- priv->speed = 10;
- break;
- }
-
- return 0;