[PATCH 3/3] net: ethernet: add support for high speed mac and usxgmii pcs

From: Parshuram Thombare
Date: Fri Feb 22 2019 - 15:13:49 EST


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

Signed-off-by: Parshuram Thombare <pthombar@xxxxxxxxxxx>
---
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