[NIU]: Support for Marvell PHY
authorMirko Lindner <mlindner@marvell.com>
Thu, 10 Jan 2008 10:12:44 +0000 (02:12 -0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 10 Jan 2008 10:12:44 +0000 (02:12 -0800)
From: Mirko Lindner <mlindner@marvell.com>

This patch makes necessary changes in the Neptune driver to support
the new Marvell PHY. It also adds support for the LED blinking
on Neptune cards with Marvell PHY. All registers are using defines
in the niu.h header file as is already done for the BCM8704 registers.

[ Coding style, etc. cleanups -DaveM ]

Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/niu.c
drivers/net/niu.h

index 9a0c6d3..3bbcea1 100644 (file)
@@ -801,22 +801,90 @@ static int bcm8704_init_user_dev3(struct niu *np)
        return 0;
 }
 
        return 0;
 }
 
-static int xcvr_init_10g(struct niu *np)
+static int mrvl88x2011_act_led(struct niu *np, int val)
+{
+       int     err;
+
+       err  = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR,
+               MRVL88X2011_LED_8_TO_11_CTL);
+       if (err < 0)
+               return err;
+
+       err &= ~MRVL88X2011_LED(MRVL88X2011_LED_ACT,MRVL88X2011_LED_CTL_MASK);
+       err |=  MRVL88X2011_LED(MRVL88X2011_LED_ACT,val);
+
+       return mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR,
+                         MRVL88X2011_LED_8_TO_11_CTL, err);
+}
+
+static int mrvl88x2011_led_blink_rate(struct niu *np, int rate)
+{
+       int     err;
+
+       err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR,
+                       MRVL88X2011_LED_BLINK_CTL);
+       if (err >= 0) {
+               err &= ~MRVL88X2011_LED_BLKRATE_MASK;
+               err |= (rate << 4);
+
+               err = mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV2_ADDR,
+                                MRVL88X2011_LED_BLINK_CTL, err);
+       }
+
+       return err;
+}
+
+static int xcvr_init_10g_mrvl88x2011(struct niu *np)
+{
+       int     err;
+
+       /* Set LED functions */
+       err = mrvl88x2011_led_blink_rate(np, MRVL88X2011_LED_BLKRATE_134MS);
+       if (err)
+               return err;
+
+       /* led activity */
+       err = mrvl88x2011_act_led(np, MRVL88X2011_LED_CTL_OFF);
+       if (err)
+               return err;
+
+       err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR,
+                       MRVL88X2011_GENERAL_CTL);
+       if (err < 0)
+               return err;
+
+       err |= MRVL88X2011_ENA_XFPREFCLK;
+
+       err = mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR,
+                        MRVL88X2011_GENERAL_CTL, err);
+       if (err < 0)
+               return err;
+
+       err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR,
+                       MRVL88X2011_PMA_PMD_CTL_1);
+       if (err < 0)
+               return err;
+
+       if (np->link_config.loopback_mode == LOOPBACK_MAC)
+               err |= MRVL88X2011_LOOPBACK;
+       else
+               err &= ~MRVL88X2011_LOOPBACK;
+
+       err = mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR,
+                        MRVL88X2011_PMA_PMD_CTL_1, err);
+       if (err < 0)
+               return err;
+
+       /* Enable PMD  */
+       return mdio_write(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR,
+                         MRVL88X2011_10G_PMD_TX_DIS, MRVL88X2011_ENA_PMDTX);
+}
+
+static int xcvr_init_10g_bcm8704(struct niu *np)
 {
        struct niu_link_config *lp = &np->link_config;
        u16 analog_stat0, tx_alarm_status;
        int err;
 {
        struct niu_link_config *lp = &np->link_config;
        u16 analog_stat0, tx_alarm_status;
        int err;
-       u64 val;
-
-       val = nr64_mac(XMAC_CONFIG);
-       val &= ~XMAC_CONFIG_LED_POLARITY;
-       val |= XMAC_CONFIG_FORCE_LED_ON;
-       nw64_mac(XMAC_CONFIG, val);
-
-       /* XXX shared resource, lock parent XXX */
-       val = nr64(MIF_CONFIG);
-       val |= MIF_CONFIG_INDIRECT_MODE;
-       nw64(MIF_CONFIG, val);
 
        err = bcm8704_reset(np);
        if (err)
 
        err = bcm8704_reset(np);
        if (err)
@@ -896,6 +964,38 @@ static int xcvr_init_10g(struct niu *np)
        return 0;
 }
 
        return 0;
 }
 
+static int xcvr_init_10g(struct niu *np)
+{
+       int phy_id, err;
+       u64 val;
+
+       val = nr64_mac(XMAC_CONFIG);
+       val &= ~XMAC_CONFIG_LED_POLARITY;
+       val |= XMAC_CONFIG_FORCE_LED_ON;
+       nw64_mac(XMAC_CONFIG, val);
+
+       /* XXX shared resource, lock parent XXX */
+       val = nr64(MIF_CONFIG);
+       val |= MIF_CONFIG_INDIRECT_MODE;
+       nw64(MIF_CONFIG, val);
+
+       phy_id = phy_decode(np->parent->port_phy, np->port);
+       phy_id = np->parent->phy_probe_info.phy_id[phy_id][np->port];
+
+       /* handle different phy types */
+       switch (phy_id & NIU_PHY_ID_MASK) {
+       case NIU_PHY_ID_MRVL88X2011:
+               err = xcvr_init_10g_mrvl88x2011(np);
+               break;
+
+       default: /* bcom 8704 */
+               err = xcvr_init_10g_bcm8704(np);
+               break;
+       }
+
+       return 0;
+}
+
 static int mii_reset(struct niu *np)
 {
        int limit, err;
 static int mii_reset(struct niu *np)
 {
        int limit, err;
@@ -1082,19 +1182,68 @@ static int niu_link_status_common(struct niu *np, int link_up)
        return 0;
 }
 
        return 0;
 }
 
-static int link_status_10g(struct niu *np, int *link_up_p)
+static int link_status_10g_mrvl(struct niu *np, int *link_up_p)
 {
 {
-       unsigned long flags;
-       int err, link_up;
+       int err, link_up, pma_status, pcs_status;
 
        link_up = 0;
 
 
        link_up = 0;
 
-       spin_lock_irqsave(&np->lock, flags);
+       err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR,
+                       MRVL88X2011_10G_PMD_STATUS_2);
+       if (err < 0)
+               goto out;
 
 
-       err = -EINVAL;
-       if (np->link_config.loopback_mode != LOOPBACK_DISABLED)
+       /* Check PMA/PMD Register: 1.0001.2 == 1 */
+       err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV1_ADDR,
+                       MRVL88X2011_PMA_PMD_STATUS_1);
+       if (err < 0)
+               goto out;
+
+       pma_status = ((err & MRVL88X2011_LNK_STATUS_OK) ? 1 : 0);
+
+        /* Check PMC Register : 3.0001.2 == 1: read twice */
+       err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR,
+                       MRVL88X2011_PMA_PMD_STATUS_1);
+       if (err < 0)
+               goto out;
+
+       err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV3_ADDR,
+                       MRVL88X2011_PMA_PMD_STATUS_1);
+       if (err < 0)
+               goto out;
+
+       pcs_status = ((err & MRVL88X2011_LNK_STATUS_OK) ? 1 : 0);
+
+        /* Check XGXS Register : 4.0018.[0-3,12] */
+       err = mdio_read(np, np->phy_addr, MRVL88X2011_USER_DEV4_ADDR,
+                       MRVL88X2011_10G_XGXS_LANE_STAT);
+       if (err < 0)
                goto out;
 
                goto out;
 
+       if (err == (PHYXS_XGXS_LANE_STAT_ALINGED | PHYXS_XGXS_LANE_STAT_LANE3 |
+                   PHYXS_XGXS_LANE_STAT_LANE2 | PHYXS_XGXS_LANE_STAT_LANE1 |
+                   PHYXS_XGXS_LANE_STAT_LANE0 | PHYXS_XGXS_LANE_STAT_MAGIC |
+                   0x800))
+               link_up = (pma_status && pcs_status) ? 1 : 0;
+
+       np->link_config.active_speed = SPEED_10000;
+       np->link_config.active_duplex = DUPLEX_FULL;
+       err = 0;
+out:
+       mrvl88x2011_act_led(np, (link_up ?
+                                MRVL88X2011_LED_CTL_PCS_ACT :
+                                MRVL88X2011_LED_CTL_OFF));
+
+       *link_up_p = link_up;
+       return err;
+}
+
+static int link_status_10g_bcom(struct niu *np, int *link_up_p)
+{
+       int err, link_up;
+
+       link_up = 0;
+
        err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR,
                        BCM8704_PMD_RCV_SIGDET);
        if (err < 0)
        err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR,
                        BCM8704_PMD_RCV_SIGDET);
        if (err < 0)
@@ -1134,9 +1283,37 @@ static int link_status_10g(struct niu *np, int *link_up_p)
        err = 0;
 
 out:
        err = 0;
 
 out:
+       *link_up_p = link_up;
+       return err;
+}
+
+static int link_status_10g(struct niu *np, int *link_up_p)
+{
+       unsigned long flags;
+       int err = -EINVAL;
+
+       spin_lock_irqsave(&np->lock, flags);
+
+       if (np->link_config.loopback_mode == LOOPBACK_DISABLED) {
+               int phy_id;
+
+               phy_id = phy_decode(np->parent->port_phy, np->port);
+               phy_id = np->parent->phy_probe_info.phy_id[phy_id][np->port];
+
+               /* handle different phy types */
+               switch (phy_id & NIU_PHY_ID_MASK) {
+               case NIU_PHY_ID_MRVL88X2011:
+                       err = link_status_10g_mrvl(np, link_up_p);
+                       break;
+
+               default: /* bcom 8704 */
+                       err = link_status_10g_bcom(np, link_up_p);
+                       break;
+               }
+       }
+
        spin_unlock_irqrestore(&np->lock, flags);
 
        spin_unlock_irqrestore(&np->lock, flags);
 
-       *link_up_p = link_up;
        return err;
 }
 
        return err;
 }
 
@@ -6297,7 +6474,8 @@ static int __devinit phy_record(struct niu_parent *parent,
        if (dev_id_1 < 0 || dev_id_2 < 0)
                return 0;
        if (type == PHY_TYPE_PMA_PMD || type == PHY_TYPE_PCS) {
        if (dev_id_1 < 0 || dev_id_2 < 0)
                return 0;
        if (type == PHY_TYPE_PMA_PMD || type == PHY_TYPE_PCS) {
-               if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8704)
+               if (((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8704) &&
+                   ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_MRVL88X2011))
                        return 0;
        } else {
                if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM5464R)
                        return 0;
        } else {
                if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM5464R)
index 10e3f11..0e8626a 100644 (file)
@@ -2538,6 +2538,39 @@ struct fcram_hash_ipv6 {
 #define NIU_PHY_ID_MASK                        0xfffff0f0
 #define NIU_PHY_ID_BCM8704             0x00206030
 #define NIU_PHY_ID_BCM5464R            0x002060b0
 #define NIU_PHY_ID_MASK                        0xfffff0f0
 #define NIU_PHY_ID_BCM8704             0x00206030
 #define NIU_PHY_ID_BCM5464R            0x002060b0
+#define NIU_PHY_ID_MRVL88X2011         0x01410020
+
+/* MRVL88X2011 register addresses */
+#define MRVL88X2011_USER_DEV1_ADDR     1
+#define MRVL88X2011_USER_DEV2_ADDR     2
+#define MRVL88X2011_USER_DEV3_ADDR     3
+#define MRVL88X2011_USER_DEV4_ADDR     4
+#define MRVL88X2011_PMA_PMD_CTL_1      0x0000
+#define MRVL88X2011_PMA_PMD_STATUS_1   0x0001
+#define MRVL88X2011_10G_PMD_STATUS_2   0x0008
+#define MRVL88X2011_10G_PMD_TX_DIS     0x0009
+#define MRVL88X2011_10G_XGXS_LANE_STAT 0x0018
+#define MRVL88X2011_GENERAL_CTL                0x8300
+#define MRVL88X2011_LED_BLINK_CTL      0x8303
+#define MRVL88X2011_LED_8_TO_11_CTL    0x8306
+
+/* MRVL88X2011 register control */
+#define MRVL88X2011_ENA_XFPREFCLK      0x0001
+#define MRVL88X2011_ENA_PMDTX          0x0000
+#define MRVL88X2011_LOOPBACK            0x1
+#define MRVL88X2011_LED_ACT            0x1
+#define MRVL88X2011_LNK_STATUS_OK      0x4
+#define MRVL88X2011_LED_BLKRATE_MASK   0x70
+#define MRVL88X2011_LED_BLKRATE_034MS  0x0
+#define MRVL88X2011_LED_BLKRATE_067MS  0x1
+#define MRVL88X2011_LED_BLKRATE_134MS  0x2
+#define MRVL88X2011_LED_BLKRATE_269MS  0x3
+#define MRVL88X2011_LED_BLKRATE_538MS  0x4
+#define MRVL88X2011_LED_CTL_OFF                0x0
+#define MRVL88X2011_LED_CTL_PCS_ACT    0x5
+#define MRVL88X2011_LED_CTL_MASK       0x7
+#define MRVL88X2011_LED(n,v)           ((v)<<((n)*4))
+#define MRVL88X2011_LED_STAT(n,v)      ((v)>>((n)*4))
 
 #define BCM8704_PMA_PMD_DEV_ADDR       1
 #define BCM8704_PCS_DEV_ADDR           2
 
 #define BCM8704_PMA_PMD_DEV_ADDR       1
 #define BCM8704_PCS_DEV_ADDR           2