Renamed CONFIG_MCFSERIAL to CONFIG_MCFUART
[oweals/u-boot.git] / drivers / tsec.c
index 30dca11522d6fc203528bc30b923e5c24137610e..1298478704fe3cb78709855b8fbbe5078055ef52 100644 (file)
@@ -5,15 +5,13 @@
  * 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
  *
  */
 
 #include <config.h>
-#include <mpc85xx.h>
-#include <mpc86xx.h>
 #include <common.h>
 #include <malloc.h>
 #include <net.h>
@@ -67,29 +65,31 @@ struct tsec_info_struct {
  *   FEC_PHYIDX
  */
 static struct tsec_info_struct tsec_info[] = {
-#if defined(CONFIG_MPC85XX_TSEC1) || defined(CONFIG_MPC83XX_TSEC1)
-       {TSEC1_PHY_ADDR, TSEC_GIGABIT, TSEC1_PHYIDX},
-#elif defined(CONFIG_MPC86XX_TSEC1)
+#if defined(CONFIG_TSEC1)
+#if defined(CONFIG_MPC8544DS) || defined(CONFIG_MPC8641HPCN)
        {TSEC1_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC1_PHYIDX},
 #else
+       {TSEC1_PHY_ADDR, TSEC_GIGABIT, TSEC1_PHYIDX},
+#endif
        {0, 0, 0},
 #endif
-#if defined(CONFIG_MPC85XX_TSEC2) || defined(CONFIG_MPC83XX_TSEC2)
-       {TSEC2_PHY_ADDR, TSEC_GIGABIT, TSEC2_PHYIDX},
-#elif defined(CONFIG_MPC86XX_TSEC2)
+#if defined(CONFIG_TSEC2)
+#if defined(CONFIG_MPC8641HPCN)
        {TSEC2_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC2_PHYIDX},
 #else
+       {TSEC2_PHY_ADDR, TSEC_GIGABIT, TSEC2_PHYIDX},
+#endif
        {0, 0, 0},
 #endif
 #ifdef CONFIG_MPC85XX_FEC
        {FEC_PHY_ADDR, 0, FEC_PHYIDX},
 #else
-#if defined(CONFIG_MPC85XX_TSEC3) || defined(CONFIG_MPC83XX_TSEC3) || defined(CONFIG_MPC86XX_TSEC3)
+#if defined(CONFIG_TSEC3)
        {TSEC3_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC3_PHYIDX},
 #else
        {0, 0, 0},
 #endif
-#if defined(CONFIG_MPC85XX_TSEC4) || defined(CONFIG_MPC83XX_TSEC4) || defined(CONFIG_MPC86XX_TSEC4)
+#if defined(CONFIG_TSEC4)
        {TSEC4_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC4_PHYIDX},
 #else
        {0, 0, 0},
@@ -315,7 +315,8 @@ static int init_phy(struct eth_device *dev)
         * PHY */
        curphy = get_phy_info(dev);
 
-       if (NULL == curphy) {
+       if (curphy == NULL) {
+               priv->phyinfo = NULL;
                printf("%s: No PHY found\n", dev->name);
 
                return 0;
@@ -382,6 +383,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
  */
@@ -611,11 +737,10 @@ static void adjust_link(struct eth_device *dev)
                        regs->maccfg2 = ((regs->maccfg2 & ~(MACCFG2_IF))
                                         | MACCFG2_MII);
 
-                       /* If We're in reduced mode, we need
-                        * to say whether we're 10 or 100 MB.
+                       /* Set R100 bit in all modes although
+                        * it is only used in RGMII mode
                         */
-                       if ((priv->speed == 100)
-                           && (priv->flags & TSEC_REDUCED))
+                       if (priv->speed == 100)
                                regs->ecntrl |= ECNTRL_R100;
                        else
                                regs->ecntrl &= ~(ECNTRL_R100);
@@ -663,7 +788,9 @@ static void startup_tsec(struct eth_device *dev)
        rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP;
 
        /* Start up the PHY */
-       phy_run_commands(priv, priv->phyinfo->startup);
+       if(priv->phyinfo)
+               phy_run_commands(priv, priv->phyinfo->startup);
+
        adjust_link(dev);
 
        /* Enable Transmit and Receive */
@@ -767,9 +894,65 @@ static void tsec_halt(struct eth_device *dev)
        regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN);
 
        /* Shut down the PHY, as needed */
-       phy_run_commands(priv, priv->phyinfo->shutdown);
+       if(priv->phyinfo)
+               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_BCM5464S = {
+       0x02060b1,      /* 5464 ID */
+       "Broadcom BCM5464S",
+       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",
@@ -815,6 +998,7 @@ struct phy_info phy_info_M88E1111S = {
                           {0x1d, 0x5, NULL},
                           {0x1e, 0x0, NULL},
                           {0x1e, 0x100, NULL},
+                          {0x14, 0x0cd2, NULL}, /* Delay RGMII TX and RX */
                           {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
                           {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
                           {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
@@ -838,7 +1022,6 @@ struct phy_info phy_info_M88E1111S = {
 
 static unsigned int m88e1145_setmode(uint mii_reg, struct tsec_private *priv)
 {
-       unsigned int temp;
        uint mii_data = read_phy_reg(priv, mii_reg);
 
        /* Setting MIIM_88E1145_PHY_EXT_CR */
@@ -1005,6 +1188,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)
 {
@@ -1110,10 +1314,10 @@ struct phy_info phy_info_dp83865 = {
 };
 
 struct phy_info *phy_info[] = {
-#if 0
-       &phy_info_cis8201,
-#endif
        &phy_info_cis8204,
+       &phy_info_cis8201,
+       &phy_info_BCM5461S,
+       &phy_info_BCM5464S,
        &phy_info_M88E1011S,
        &phy_info_M88E1111S,
        &phy_info_M88E1145,
@@ -1121,6 +1325,7 @@ struct phy_info *phy_info[] = {
        &phy_info_lxt971,
        &phy_info_VSC8244,
        &phy_info_dp83865,
+       &phy_info_generic,
        NULL
 };