Merge with /home/stefan/git/u-boot/bamboo-nand
[oweals/u-boot.git] / drivers / tsec.c
index 770517b87e468db5ee453f6ed0c70fdb99706959..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
@@ -313,7 +317,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;
@@ -380,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
  */
@@ -609,11 +739,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);
@@ -661,7 +790,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 */
@@ -765,9 +896,38 @@ 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_M88E1011S = {
        0x01410c6,
        "Marvell 88E1011S",
@@ -813,6 +973,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},
@@ -1002,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)
 {
@@ -1107,10 +1289,9 @@ 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_M88E1011S,
        &phy_info_M88E1111S,
        &phy_info_M88E1145,
@@ -1118,6 +1299,7 @@ struct phy_info *phy_info[] = {
        &phy_info_lxt971,
        &phy_info_VSC8244,
        &phy_info_dp83865,
+       &phy_info_generic,
        NULL
 };