|
@@ -1,5 +1,5 @@
|
|
/*
|
|
/*
|
|
- * Copyright (C) 2006-2007 Freescale Semicondutor, Inc. All rights reserved.
|
|
|
|
|
|
+ * Copyright (C) 2006-2009 Freescale Semicondutor, Inc. All rights reserved.
|
|
*
|
|
*
|
|
* Author: Shlomi Gridish <gridish@freescale.com>
|
|
* Author: Shlomi Gridish <gridish@freescale.com>
|
|
* Li Yang <leoli@freescale.com>
|
|
* Li Yang <leoli@freescale.com>
|
|
@@ -1410,6 +1410,9 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
|
|
(ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
|
|
(ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
|
|
upsmr |= UCC_GETH_UPSMR_TBIM;
|
|
upsmr |= UCC_GETH_UPSMR_TBIM;
|
|
}
|
|
}
|
|
|
|
+ if ((ugeth->phy_interface == PHY_INTERFACE_MODE_SGMII))
|
|
|
|
+ upsmr |= UCC_GETH_UPSMR_SGMM;
|
|
|
|
+
|
|
out_be32(&uf_regs->upsmr, upsmr);
|
|
out_be32(&uf_regs->upsmr, upsmr);
|
|
|
|
|
|
/* Disable autonegotiation in tbi mode, because by default it
|
|
/* Disable autonegotiation in tbi mode, because by default it
|
|
@@ -1531,6 +1534,49 @@ static void adjust_link(struct net_device *dev)
|
|
spin_unlock_irqrestore(&ugeth->lock, flags);
|
|
spin_unlock_irqrestore(&ugeth->lock, flags);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* Initialize TBI PHY interface for communicating with the
|
|
|
|
+ * SERDES lynx PHY on the chip. We communicate with this PHY
|
|
|
|
+ * through the MDIO bus on each controller, treating it as a
|
|
|
|
+ * "normal" PHY at the address found in the UTBIPA register. We assume
|
|
|
|
+ * that the UTBIPA register is valid. Either the MDIO bus code will set
|
|
|
|
+ * it to a value that doesn't conflict with other PHYs on the bus, or the
|
|
|
|
+ * value doesn't matter, as there are no other PHYs on the bus.
|
|
|
|
+ */
|
|
|
|
+static void uec_configure_serdes(struct net_device *dev)
|
|
|
|
+{
|
|
|
|
+ struct ucc_geth_private *ugeth = netdev_priv(dev);
|
|
|
|
+ struct ucc_geth_info *ug_info = ugeth->ug_info;
|
|
|
|
+ struct phy_device *tbiphy;
|
|
|
|
+
|
|
|
|
+ if (!ug_info->tbi_node) {
|
|
|
|
+ dev_warn(&dev->dev, "SGMII mode requires that the device "
|
|
|
|
+ "tree specify a tbi-handle\n");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ tbiphy = of_phy_find_device(ug_info->tbi_node);
|
|
|
|
+ if (!tbiphy) {
|
|
|
|
+ dev_err(&dev->dev, "error: Could not get TBI device\n");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * If the link is already up, we must already be ok, and don't need to
|
|
|
|
+ * configure and reset the TBI<->SerDes link. Maybe U-Boot configured
|
|
|
|
+ * everything for us? Resetting it takes the link down and requires
|
|
|
|
+ * several seconds for it to come back.
|
|
|
|
+ */
|
|
|
|
+ if (phy_read(tbiphy, ENET_TBI_MII_SR) & TBISR_LSTATUS)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ /* Single clk mode, mii mode off(for serdes communication) */
|
|
|
|
+ phy_write(tbiphy, ENET_TBI_MII_ANA, TBIANA_SETTINGS);
|
|
|
|
+
|
|
|
|
+ phy_write(tbiphy, ENET_TBI_MII_TBICON, TBICON_CLK_SELECT);
|
|
|
|
+
|
|
|
|
+ phy_write(tbiphy, ENET_TBI_MII_CR, TBICR_SETTINGS);
|
|
|
|
+}
|
|
|
|
+
|
|
/* Configure the PHY for dev.
|
|
/* Configure the PHY for dev.
|
|
* returns 0 if success. -1 if failure
|
|
* returns 0 if success. -1 if failure
|
|
*/
|
|
*/
|
|
@@ -1554,6 +1600,9 @@ static int init_phy(struct net_device *dev)
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII)
|
|
|
|
+ uec_configure_serdes(dev);
|
|
|
|
+
|
|
phydev->supported &= (ADVERTISED_10baseT_Half |
|
|
phydev->supported &= (ADVERTISED_10baseT_Half |
|
|
ADVERTISED_10baseT_Full |
|
|
ADVERTISED_10baseT_Full |
|
|
ADVERTISED_100baseT_Half |
|
|
ADVERTISED_100baseT_Half |
|
|
@@ -3523,6 +3572,8 @@ static phy_interface_t to_phy_interface(const char *phy_connection_type)
|
|
return PHY_INTERFACE_MODE_RGMII_RXID;
|
|
return PHY_INTERFACE_MODE_RGMII_RXID;
|
|
if (strcasecmp(phy_connection_type, "rtbi") == 0)
|
|
if (strcasecmp(phy_connection_type, "rtbi") == 0)
|
|
return PHY_INTERFACE_MODE_RTBI;
|
|
return PHY_INTERFACE_MODE_RTBI;
|
|
|
|
+ if (strcasecmp(phy_connection_type, "sgmii") == 0)
|
|
|
|
+ return PHY_INTERFACE_MODE_SGMII;
|
|
|
|
|
|
return PHY_INTERFACE_MODE_MII;
|
|
return PHY_INTERFACE_MODE_MII;
|
|
}
|
|
}
|
|
@@ -3567,6 +3618,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
|
|
PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII,
|
|
PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII,
|
|
PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII,
|
|
PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII,
|
|
PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI,
|
|
PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI,
|
|
|
|
+ PHY_INTERFACE_MODE_SGMII,
|
|
};
|
|
};
|
|
|
|
|
|
ugeth_vdbg("%s: IN", __func__);
|
|
ugeth_vdbg("%s: IN", __func__);
|
|
@@ -3658,6 +3710,9 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
|
|
}
|
|
}
|
|
ug_info->phy_node = phy;
|
|
ug_info->phy_node = phy;
|
|
|
|
|
|
|
|
+ /* Find the TBI PHY node. If it's not there, we don't support SGMII */
|
|
|
|
+ ug_info->tbi_node = of_parse_phandle(np, "tbi-handle", 0);
|
|
|
|
+
|
|
/* get the phy interface type, or default to MII */
|
|
/* get the phy interface type, or default to MII */
|
|
prop = of_get_property(np, "phy-connection-type", NULL);
|
|
prop = of_get_property(np, "phy-connection-type", NULL);
|
|
if (!prop) {
|
|
if (!prop) {
|
|
@@ -3682,6 +3737,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
|
|
case PHY_INTERFACE_MODE_RGMII_TXID:
|
|
case PHY_INTERFACE_MODE_RGMII_TXID:
|
|
case PHY_INTERFACE_MODE_TBI:
|
|
case PHY_INTERFACE_MODE_TBI:
|
|
case PHY_INTERFACE_MODE_RTBI:
|
|
case PHY_INTERFACE_MODE_RTBI:
|
|
|
|
+ case PHY_INTERFACE_MODE_SGMII:
|
|
max_speed = SPEED_1000;
|
|
max_speed = SPEED_1000;
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|