This patch add support for (10G) high speed mac, usxgmii pcs
and usxgmii interface in Cadence ethernet controller driver.

Signed-off-by: Parshuram Thombare <pthom...@cadence.com>
---
 drivers/net/ethernet/cadence/macb.h      |   33 +++++++++
 drivers/net/ethernet/cadence/macb_main.c |  110 ++++++++++++++++++++++++++++--
 include/linux/phy.h                      |    3 +
 3 files changed, 140 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/cadence/macb.h 
b/drivers/net/ethernet/cadence/macb.h
index 59c23e0..34df014 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -84,6 +84,7 @@
 #define GEM_USRIO              0x000c /* User IO */
 #define GEM_DMACFG             0x0010 /* DMA Configuration */
 #define GEM_JML                        0x0048 /* Jumbo Max Length */
+#define GEM_HS_MAC_CONFIG      0x0050 /* GEM high speed config */
 #define GEM_HRB                        0x0080 /* Hash Bottom */
 #define GEM_HRT                        0x0084 /* Hash Top */
 #define GEM_SA1B               0x0088 /* Specific1 Bottom */
@@ -168,6 +169,9 @@
 #define GEM_DCFG7              0x0298 /* Design Config 7 */
 #define GEM_DCFG8              0x029C /* Design Config 8 */
 #define GEM_DCFG10             0x02A4 /* Design Config 10 */
+#define GEM_DCFG12             0x02AC /* Design Config 12 */
+#define GEM_USX_CONTROL                0x0A80 /* USXGMII control register */
+#define GEM_USX_STATUS         0x0A88 /* USXGMII status register */
 
 #define GEM_TXBDCTRL   0x04cc /* TX Buffer Descriptor control register */
 #define GEM_RXBDCTRL   0x04d0 /* RX Buffer Descriptor control register */
@@ -275,6 +279,8 @@
 #define MACB_IRXFCS_SIZE       1
 
 /* GEM specific NCR bitfields. */
+#define GEM_ENABLE_HS_MAC_OFFSET       31
+#define GEM_ENABLE_HS_MAC_SIZE         1
 #define GEM_TWO_PT_FIVE_GIG_OFFSET     29
 #define GEM_TWO_PT_FIVE_GIG_SIZE       1
 
@@ -463,6 +469,10 @@
 #define MACB_REV_OFFSET                                0
 #define MACB_REV_SIZE                          16
 
+/* Bitfield in HS_MAC_CONFIG */
+#define GEM_HS_MAC_SPEED_OFFSET                        0
+#define GEM_HS_MAC_SPEED_SIZE                  3
+
 /* Bitfields in DCFG1. */
 #define GEM_IRQCOR_OFFSET                      23
 #define GEM_IRQCOR_SIZE                                1
@@ -504,6 +514,28 @@
 #define GEM_RXBD_RDBUFF_OFFSET                 8
 #define GEM_RXBD_RDBUFF_SIZE                   4
 
+/* Bitfields in DCFG12. */
+#define GEM_HIGH_SPEED_OFFSET                  26
+#define GEM_HIGH_SPEED_SIZE                    1
+
+/* Bitfields in USX_CONTROL. */
+#define GEM_USX_CTRL_SPEED_OFFSET              14
+#define GEM_USX_CTRL_SPEED_SIZE                        3
+#define GEM_SERDES_RATE_OFFSET                 12
+#define GEM_SERDES_RATE_SIZE                   2
+#define GEM_TX_EN_OFFSET                       1
+#define GEM_TX_EN_SIZE                         1
+#define GEM_SIGNAL_OK_OFFSET                   0
+#define GEM_SIGNAL_OK_SIZE                     1
+
+/* Bitfields in USX_STATUS. */
+#define GEM_USX_TX_FAULT_OFFSET                        28
+#define GEM_USX_TX_FAULT_SIZE                  1
+#define GEM_USX_RX_FAULT_OFFSET                        27
+#define GEM_USX_RX_FAULT_SIZE                  1
+#define GEM_USX_BLOCK_LOCK_OFFSET              0
+#define GEM_USX_BLOCK_LOCK_SIZE                        1
+
 /* Bitfields in TISUBN */
 #define GEM_SUBNSINCR_OFFSET                   0
 #define GEM_SUBNSINCR_SIZE                     16
@@ -664,6 +696,7 @@
 #define MACB_CAPS_MACB_IS_GEM                  0x80000000
 #define MACB_CAPS_PCS                          0x01000000
 #define MACB_CAPS_TWO_PT_FIVE_GIG_SPEED                0x02000000
+#define MACB_CAPS_HIGH_SPEED                   0x04000000
 
 #define MACB_GEM7010_IDNUM                     0x009
 #define MACB_GEM7014_IDNUM                     0x107
diff --git a/drivers/net/ethernet/cadence/macb_main.c 
b/drivers/net/ethernet/cadence/macb_main.c
index 2494abf..0e0acf9 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -79,6 +79,21 @@
  */
 #define MACB_HALT_TIMEOUT      1230
 
+enum {
+       HS_MAC_SPEED_100M,
+       HS_MAC_SPEED_1000M,
+       HS_MAC_SPEED_2500M,
+       HS_MAC_SPEED_5000M,
+       HS_MAC_SPEED_10000M,
+       HS_MAC_SPEED_25000M,
+};
+
+enum {
+       MACB_SERDES_RATE_5_PT_15625Gbps,
+       MACB_SERDES_RATE_10_PT_3125Gbps,
+       MACB_SERDES_RATE_25_PT_78125Gbps,
+};
+
 /* DMA buffer descriptor might be different size
  * depends on hardware configuration:
  *
@@ -443,6 +458,20 @@ static void macb_set_tx_clk(struct clk *clk, int speed,
                default:
                return;
                }
+       } else if (interface == PHY_INTERFACE_MODE_USXGMII) {
+               struct macb *bp = netdev_priv(dev);
+               u32 serdes_rate = GEM_BFEXT(SERDES_RATE,
+                                           gem_readl(bp, USX_CONTROL));
+               switch (serdes_rate) {
+               case MACB_SERDES_RATE_5_PT_15625Gbps:
+               rate = 78125000;
+               break;
+               case MACB_SERDES_RATE_10_PT_3125Gbps:
+               rate = 156250000;
+               break;
+               default:
+               return;
+               }
        } else {
                return;
        }
@@ -475,7 +504,7 @@ static void macb_handle_link_change(struct net_device *dev)
 
        if (phydev->link && (bp->speed != phydev->speed ||
                             bp->duplex != phydev->duplex)) {
-               u32 reg;
+               u32 reg, speed;
 
                reg = macb_readl(bp, NCFGR);
                reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
@@ -485,7 +514,53 @@ static void macb_handle_link_change(struct net_device *dev)
                        reg |= MACB_BIT(FD);
                macb_or_gem_writel(bp, NCFGR, reg);
 
-               if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII &&
+               if ((bp->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
+                    bp->phy_interface == PHY_INTERFACE_MODE_XGMII) &&
+                       phydev->speed >= SPEED_100) {
+                       gem_writel(bp, NCR, gem_readl(bp, NCR) |
+                                       GEM_BIT(ENABLE_HS_MAC));
+                       if (bp->phy_interface == PHY_INTERFACE_MODE_USXGMII) {
+                               /* Setup USXGMII PCS */
+                               reg = gem_readl(bp, USX_CONTROL);
+                               reg = GEM_BFINS(SERDES_RATE,
+                                               MACB_SERDES_RATE_5_PT_15625Gbps,
+                                               reg);
+                               gem_writel(bp, USX_CONTROL, reg |
+                                               GEM_BIT(TX_EN) |
+                                               GEM_BIT(SIGNAL_OK));
+                               while (!GEM_BFEXT(USX_BLOCK_LOCK,
+                                                 gem_readl(bp, USX_STATUS)))
+                                       cpu_relax();
+                       }
+                       switch (phydev->speed) {
+                       case SPEED_10000:
+                       speed = HS_MAC_SPEED_10000M;
+                       break;
+
+                       case SPEED_5000:
+                       speed = HS_MAC_SPEED_5000M;
+                       break;
+
+                       case SPEED_2500:
+                       speed = HS_MAC_SPEED_2500M;
+                       break;
+
+                       case SPEED_1000:
+                       speed = HS_MAC_SPEED_1000M;
+                       break;
+
+                       default:
+                       case SPEED_100:
+                       speed = HS_MAC_SPEED_100M;
+                       break;
+                       }
+                       gem_writel(bp, HS_MAC_CONFIG,
+                                  GEM_BFINS(HS_MAC_SPEED, speed,
+                                            gem_readl(bp, HS_MAC_CONFIG)));
+                       gem_writel(bp, USX_CONTROL,
+                                  GEM_BFINS(USX_CTRL_SPEED, speed,
+                                            gem_readl(bp, USX_CONTROL)));
+               } else if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII &&
                    (phydev->speed == SPEED_1000 ||
                     phydev->speed == SPEED_2500)) {
                        if (bp->caps & MACB_CAPS_TWO_PT_FIVE_GIG_SPEED) {
@@ -627,10 +702,15 @@ static int macb_mii_probe(struct net_device *dev)
 
        /* mask with MAC supported features */
        if (macb_is_gem(bp)) {
-               linkmode_copy(phydev->supported, PHY_GBIT_FEATURES);
-               if (bp->caps & MACB_CAPS_TWO_PT_FIVE_GIG_SPEED)
-                       linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
-                                        phydev->supported);
+               if (bp->caps & MACB_CAPS_HIGH_SPEED) {
+                       linkmode_copy(phydev->supported, PHY_10GBIT_FEATURES);
+               } else {
+                       u32 bitmask = ETHTOOL_LINK_MODE_2500baseT_Full_BIT;
+
+                       linkmode_copy(phydev->supported, PHY_GBIT_FEATURES);
+                       if (bp->caps & MACB_CAPS_TWO_PT_FIVE_GIG_SPEED)
+                               linkmode_set_bit(bitmask, phydev->supported);
+               }
        } else {
                linkmode_copy(phydev->supported, PHY_BASIC_FEATURES);
        }
@@ -3344,6 +3424,9 @@ static void macb_configure_caps(struct macb *bp,
                        bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE;
                if (GEM_BFEXT(NO_PCS, dcfg) == 0)
                        bp->caps |= MACB_CAPS_PCS;
+               dcfg = gem_readl(bp, DCFG12);
+               if (GEM_BFEXT(HIGH_SPEED, dcfg) == 1)
+                       bp->caps |= MACB_CAPS_HIGH_SPEED;
                switch (MACB_BFEXT(IDNUM, macb_readl(bp, MID))) {
                case MACB_GEM7016_IDNUM:
                case MACB_GEM7017_IDNUM:
@@ -4215,6 +4298,21 @@ static int macb_probe(struct platform_device *pdev)
                        bp->phy_interface = PHY_INTERFACE_MODE_MII;
        } else {
                switch (err) {
+               case PHY_INTERFACE_MODE_USXGMII:
+               if ((bp->caps & MACB_CAPS_HIGH_SPEED) &&
+                   (bp->caps & MACB_CAPS_PCS)) {
+                       bp->phy_interface = PHY_INTERFACE_MODE_USXGMII;
+                       break;
+               }
+               /* Fallthrough */
+
+               case PHY_INTERFACE_MODE_XGMII:
+               if (bp->caps & MACB_CAPS_HIGH_SPEED) {
+                       bp->phy_interface = PHY_INTERFACE_MODE_XGMII;
+                       break;
+               }
+               /* Fallthrough */
+
                case PHY_INTERFACE_MODE_SGMII:
                if (bp->caps & MACB_CAPS_PCS) {
                        bp->phy_interface = PHY_INTERFACE_MODE_SGMII;
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 8e9fc57..b627e30 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -94,6 +94,7 @@
        PHY_INTERFACE_MODE_RTBI,
        PHY_INTERFACE_MODE_SMII,
        PHY_INTERFACE_MODE_XGMII,
+       PHY_INTERFACE_MODE_USXGMII,
        PHY_INTERFACE_MODE_MOCA,
        PHY_INTERFACE_MODE_QSGMII,
        PHY_INTERFACE_MODE_TRGMII,
@@ -162,6 +163,8 @@ unsigned int phy_supported_speeds(struct phy_device *phy,
                return "smii";
        case PHY_INTERFACE_MODE_XGMII:
                return "xgmii";
+       case PHY_INTERFACE_MODE_USXGMII:
+               return "usxgmii";
        case PHY_INTERFACE_MODE_MOCA:
                return "moca";
        case PHY_INTERFACE_MODE_QSGMII:
-- 
1.7.1

Reply via email to