]> git.sur5r.net Git - u-boot/blobdiff - drivers/tsec.c
Merge git://www.denx.de/git/u-boot into 2007_05_15-testing
[u-boot] / drivers / tsec.c
index 2524e4f6d2b6644a3ec69cb7324f16d37b202e4c..b4187739cb01a341a0c7551f982b64a815e39560 100644 (file)
@@ -5,7 +5,7 @@
  * terms of the GNU Public License, Version 2, incorporated
  * herein by reference.
  *
- * Copyright 2004 Freescale Semiconductor.
+ * Copyright 2004, 2007 Freescale Semiconductor, Inc.
  * (C) Copyright 2003, Motorola, Inc.
  * author Andy Fleming
  *
@@ -66,7 +66,11 @@ struct tsec_info_struct {
  */
 static struct tsec_info_struct tsec_info[] = {
 #if defined(CONFIG_MPC85XX_TSEC1) || defined(CONFIG_MPC83XX_TSEC1)
+#if defined(CONFIG_MPC8544DS)
+       {TSEC1_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC1_PHYIDX},
+#else
        {TSEC1_PHY_ADDR, TSEC_GIGABIT, TSEC1_PHYIDX},
+#endif
 #elif defined(CONFIG_MPC86XX_TSEC1)
        {TSEC1_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC1_PHYIDX},
 #else
@@ -381,6 +385,131 @@ 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.
+ */
+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
  */
@@ -663,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 */
@@ -770,6 +900,34 @@ static void tsec_halt(struct eth_device *dev)
                phy_run_commands(priv, priv->phyinfo->shutdown);
 }
 
+/* The 5411 id is 0x206070, the 5421 is 0x2060e0 */
+struct phy_info phy_info_BCM5461S = {
+       0x02060c1,      /* 5461 ID */
+       "Broadcom BCM5461S",
+       0, /* not clear to me what minor revisions we can shift away */
+       (struct phy_cmd[]) { /* config */
+               /* Reset and configure the PHY */
+               {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+               {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
+               {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
+               {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+               {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+               {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},
+               {miim_end,}
+       },
+       (struct phy_cmd[]) { /* shutdown */
+               {miim_end,}
+       },
+};
+
 struct phy_info phy_info_M88E1011S = {
        0x01410c6,
        "Marvell 88E1011S",
@@ -1005,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)
 {
@@ -1112,6 +1291,7 @@ struct phy_info phy_info_dp83865 = {
 struct phy_info *phy_info[] = {
        &phy_info_cis8204,
        &phy_info_cis8201,
+       &phy_info_BCM5461S,
        &phy_info_M88E1011S,
        &phy_info_M88E1111S,
        &phy_info_M88E1145,
@@ -1119,6 +1299,7 @@ struct phy_info *phy_info[] = {
        &phy_info_lxt971,
        &phy_info_VSC8244,
        &phy_info_dp83865,
+       &phy_info_generic,
        NULL
 };