|
@@ -385,6 +385,76 @@ 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.
|
|
@@ -722,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 */
|
|
@@ -1092,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)
|
|
|
{
|
|
@@ -1207,6 +1299,7 @@ struct phy_info *phy_info[] = {
|
|
|
&phy_info_lxt971,
|
|
|
&phy_info_VSC8244,
|
|
|
&phy_info_dp83865,
|
|
|
+ &phy_info_generic,
|
|
|
NULL
|
|
|
};
|
|
|
|