[PATCH 5/6] net: macb: add support for high speed interface
From: Parshuram Thombare
Date: Sun Jun 16 2019 - 03:10:37 EST
This patch add support for high speed USXGMII PCS and 10G
speed in Cadence ethernet controller driver.
Signed-off-by: Parshuram Thombare <pthombar@xxxxxxxxxxx>
---
drivers/net/ethernet/cadence/macb.h | 42 +++++
drivers/net/ethernet/cadence/macb_main.c | 215 +++++++++++++++++++----
2 files changed, 224 insertions(+), 33 deletions(-)
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 75f093bc52fe..e00b9f647757 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -85,6 +85,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 */
@@ -172,6 +173,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 */
@@ -279,6 +283,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
@@ -470,6 +476,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 PCS_CONTROL. */
#define GEM_PCS_CTRL_RST_OFFSET 15
#define GEM_PCS_CTRL_RST_SIZE 1
@@ -535,6 +545,34 @@
#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_RX_SCR_BYPASS_OFFSET 9
+#define GEM_RX_SCR_BYPASS_SIZE 1
+#define GEM_TX_SCR_BYPASS_OFFSET 8
+#define GEM_TX_SCR_BYPASS_SIZE 1
+#define GEM_RX_SYNC_RESET_OFFSET 2
+#define GEM_RX_SYNC_RESET_SIZE 1
+#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
@@ -695,6 +733,7 @@
#define MACB_CAPS_MACB_IS_GEM BIT(31)
#define MACB_CAPS_PCS BIT(24)
#define MACB_CAPS_MACB_IS_GEM_GXL BIT(25)
+#define MACB_CAPS_HIGH_SPEED BIT(26)
#define MACB_GEM7010_IDNUM 0x009
#define MACB_GEM7014_IDNUM 0x107
@@ -774,6 +813,7 @@
})
#define MACB_READ_NSR(bp) macb_readl(bp, NSR)
+#define GEM_READ_USX_STATUS(bp) gem_readl(bp, USX_STATUS)
/* struct macb_dma_desc - Hardware DMA descriptor
* @addr: DMA address of data buffer
@@ -1287,6 +1327,8 @@ struct macb {
struct macb_pm_data pm_data;
struct phylink *pl;
struct phylink_config pl_config;
+ u32 serdes_rate;
+ u32 fixed_speed;
};
#ifdef CONFIG_MACB_USE_HWSTAMP
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index 57ffc4e9d2b9..8739f815bcae 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -77,6 +77,20 @@
#define MACB_WOL_HAS_MAGIC_PACKET (0x1 << 0)
#define MACB_WOL_ENABLED (0x1 << 1)
+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,
+};
+
/* Graceful stop timeouts in us. We should allow up to
* 1 frame time (10 Mbits/s, full-duplex, ignoring collisions)
*/
@@ -86,6 +100,8 @@
#define MACB_MDIO_TIMEOUT 1000000 /* in usecs */
+#define MACB_USX_BLOCK_LOCK_TIMEOUT 1000000 /* in usecs */
+
/* DMA buffer descriptor might be different size
* depends on hardware configuration:
*
@@ -438,24 +454,37 @@ static void macb_set_tx_clk(struct clk *clk, int speed, struct net_device *dev)
if (!clk)
return;
- switch (speed) {
- case SPEED_10:
- rate = 2500000;
- break;
- case SPEED_100:
- rate = 25000000;
- break;
- case SPEED_1000:
- rate = 125000000;
- break;
- case SPEED_2500:
- if (bp->caps & MACB_CAPS_MACB_IS_GEM_GXL)
- rate = 312500000;
- else
+ if (bp->phy_interface == PHY_INTERFACE_MODE_USXGMII) {
+ switch (bp->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 {
+ switch (speed) {
+ case SPEED_10:
+ rate = 2500000;
+ break;
+ case SPEED_100:
+ rate = 25000000;
+ break;
+ case SPEED_1000:
rate = 125000000;
- break;
- default:
- return;
+ break;
+ case SPEED_2500:
+ if (bp->caps & MACB_CAPS_MACB_IS_GEM_GXL)
+ rate = 312500000;
+ else
+ return;
+ break;
+ default:
+ return;
+ }
}
rate_rounded = clk_round_rate(clk, rate);
@@ -484,6 +513,22 @@ static void gem_phylink_validate(struct phylink_config *pl_config,
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
switch (state->interface) {
+ case PHY_INTERFACE_MODE_NA:
+ case PHY_INTERFACE_MODE_USXGMII:
+ case PHY_INTERFACE_MODE_10GKR:
+ if (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) {
+ phylink_set(mask, 10000baseCR_Full);
+ phylink_set(mask, 10000baseER_Full);
+ phylink_set(mask, 10000baseKR_Full);
+ phylink_set(mask, 10000baseLR_Full);
+ phylink_set(mask, 10000baseLRM_Full);
+ phylink_set(mask, 10000baseSR_Full);
+ phylink_set(mask, 10000baseT_Full);
+ phylink_set(mask, 5000baseT_Full);
+ phylink_set(mask, 2500baseX_Full);
+ phylink_set(mask, 1000baseX_Full);
+ }
+ /* Fall-through */
case PHY_INTERFACE_MODE_SGMII:
if (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)
phylink_set(mask, 2500baseT_Full);
@@ -594,17 +639,55 @@ static void gem_mac_config(struct phylink_config *pl_config, unsigned int mode,
reg |= MACB_BIT(FD);
macb_or_gem_writel(bp, NCFGR, reg);
- if (state->speed == SPEED_2500) {
- gem_writel(bp, NCFGR, GEM_BIT(GBE) |
- gem_readl(bp, NCFGR));
- gem_writel(bp, NCR, GEM_BIT(TWO_PT_FIVE_GIG) |
- gem_readl(bp, NCR));
- } else if (state->speed == SPEED_1000) {
- gem_writel(bp, NCFGR, GEM_BIT(GBE) |
- gem_readl(bp, NCFGR));
- } else if (state->speed == SPEED_100) {
- macb_writel(bp, NCFGR, MACB_BIT(SPD) |
- macb_readl(bp, NCFGR));
+ if (bp->phy_interface == PHY_INTERFACE_MODE_USXGMII) {
+ u32 speed;
+
+ switch (state->speed) {
+ case SPEED_10000:
+ if (bp->serdes_rate ==
+ MACB_SERDES_RATE_10_PT_3125Gbps) {
+ speed = HS_MAC_SPEED_10000M;
+ } else {
+ netdev_warn(netdev,
+ "10G not supported by HW");
+ netdev_warn(netdev, "Setting speed to 1G");
+ speed = HS_MAC_SPEED_1000M;
+ }
+ 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 (state->speed == SPEED_2500) {
+ gem_writel(bp, NCFGR, GEM_BIT(GBE) |
+ gem_readl(bp, NCFGR));
+ gem_writel(bp, NCR, GEM_BIT(TWO_PT_FIVE_GIG) |
+ gem_readl(bp, NCR));
+ } else if (state->speed == SPEED_1000) {
+ gem_writel(bp, NCFGR, GEM_BIT(GBE) |
+ gem_readl(bp, NCFGR));
+ } else if (state->speed == SPEED_100) {
+ macb_writel(bp, NCFGR, MACB_BIT(SPD) |
+ macb_readl(bp, NCFGR));
+ }
}
bp->speed = state->speed;
@@ -649,6 +732,16 @@ static const struct phylink_mac_ops gem_phylink_ops = {
.mac_link_down = gem_mac_link_down,
};
+void gem_usx_fixed_state(struct net_device *dev,
+ struct phylink_link_state *state)
+{
+ struct macb *bp = netdev_priv(dev);
+
+ state->speed = (bp->fixed_speed == SPEED_UNKNOWN) ? SPEED_1000
+ : bp->fixed_speed;
+ state->duplex = 1;
+}
+
/* based on au1000_eth. c*/
static int macb_mii_probe(struct net_device *dev)
{
@@ -670,6 +763,9 @@ static int macb_mii_probe(struct net_device *dev)
return PTR_ERR(bp->pl);
}
+ if (bp->phy_interface == PHY_INTERFACE_MODE_USXGMII)
+ phylink_fixed_state_cb(bp->pl, gem_usx_fixed_state);
+
ret = phylink_of_phy_connect(bp->pl, np, 0);
if (ret == -ENODEV && bp->mii_bus) {
phydev = phy_find_first(bp->mii_bus);
@@ -2337,11 +2433,19 @@ static void macb_configure_dma(struct macb *bp)
}
}
-static void macb_init_hw(struct macb *bp)
+static int macb_wait_for_usx_block_lock(struct macb *bp)
+{
+ u32 val;
+
+ return readx_poll_timeout(GEM_READ_USX_STATUS, bp, val,
+ val & GEM_BIT(USX_BLOCK_LOCK),
+ 1, MACB_USX_BLOCK_LOCK_TIMEOUT);
+}
+
+static int macb_init_hw(struct macb *bp)
{
struct macb_queue *queue;
unsigned int q;
-
u32 config;
macb_reset_hw(bp);
@@ -2375,6 +2479,23 @@ static void macb_init_hw(struct macb *bp)
if (bp->caps & MACB_CAPS_JUMBO)
bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK;
+ if (bp->phy_interface == PHY_INTERFACE_MODE_USXGMII) {
+ gem_writel(bp, NCR, gem_readl(bp, NCR) |
+ GEM_BIT(ENABLE_HS_MAC));
+ gem_writel(bp, NCFGR, gem_readl(bp, NCFGR) |
+ MACB_BIT(FD) | GEM_BIT(PCSSEL));
+ config = gem_readl(bp, USX_CONTROL);
+ config = GEM_BFINS(SERDES_RATE, bp->serdes_rate, config);
+ config &= ~GEM_BIT(TX_SCR_BYPASS);
+ config &= ~GEM_BIT(RX_SCR_BYPASS);
+ gem_writel(bp, USX_CONTROL, config |
+ GEM_BIT(TX_EN));
+ config = gem_readl(bp, USX_CONTROL);
+ gem_writel(bp, USX_CONTROL, config | GEM_BIT(SIGNAL_OK));
+ if (macb_wait_for_usx_block_lock(bp) < 0)
+ return -ETIMEDOUT;
+ }
+
if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII ||
bp->phy_interface == PHY_INTERFACE_MODE_1000BASEX ||
bp->phy_interface == PHY_INTERFACE_MODE_2500BASEX) {
@@ -2410,6 +2531,7 @@ static void macb_init_hw(struct macb *bp)
/* Enable TX and RX */
macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(RE) | MACB_BIT(TE));
+ return 0;
}
/* The hash address register is 64 bits long and takes up two
@@ -2568,7 +2690,9 @@ static int macb_open(struct net_device *dev)
napi_enable(&queue->napi);
bp->macbgem_ops.mog_init_rings(bp);
- macb_init_hw(bp);
+ err = macb_init_hw(bp);
+ if (err)
+ goto init_hw_exit;
/* schedule a link state check */
phylink_start(bp->pl);
@@ -2578,6 +2702,9 @@ static int macb_open(struct net_device *dev)
if (bp->ptp_info)
bp->ptp_info->ptp_init(dev);
+init_hw_exit:
+ if (err)
+ macb_free_consistent(bp);
pm_exit:
if (err) {
pm_runtime_put_sync(&bp->pdev->dev);
@@ -3493,6 +3620,9 @@ static void macb_configure_caps(struct macb *bp,
default:
break;
}
+ dcfg = gem_readl(bp, DCFG12);
+ if (GEM_BFEXT(HIGH_SPEED, dcfg) == 1)
+ bp->caps |= MACB_CAPS_HIGH_SPEED;
dcfg = gem_readl(bp, DCFG2);
if ((dcfg & (GEM_BIT(RX_PKT_BUFF) | GEM_BIT(TX_PKT_BUFF))) == 0)
bp->caps |= MACB_CAPS_FIFO_MODE;
@@ -3784,7 +3914,12 @@ static int macb_init(struct platform_device *pdev)
if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII ||
bp->phy_interface == PHY_INTERFACE_MODE_1000BASEX ||
bp->phy_interface == PHY_INTERFACE_MODE_2500BASEX)
- val |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL);
+ val |= GEM_BIT(SGMIIEN);
+ if (bp->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
+ bp->phy_interface == PHY_INTERFACE_MODE_SGMII ||
+ bp->phy_interface == PHY_INTERFACE_MODE_1000BASEX ||
+ bp->phy_interface == PHY_INTERFACE_MODE_2500BASEX)
+ val |= GEM_BIT(PCSSEL);
macb_writel(bp, NCFGR, val);
return 0;
@@ -4372,7 +4507,21 @@ static int macb_probe(struct platform_device *pdev)
} else if (bp->caps & MACB_CAPS_MACB_IS_GEM_GXL) {
u32 interface_supported = 1;
- if (err == PHY_INTERFACE_MODE_SGMII ||
+ if (err == PHY_INTERFACE_MODE_USXGMII) {
+ if (!(bp->caps & MACB_CAPS_HIGH_SPEED &&
+ bp->caps & MACB_CAPS_PCS))
+ interface_supported = 0;
+
+ if (of_property_read_u32(np, "serdes-rate",
+ &bp->serdes_rate)) {
+ netdev_err(dev,
+ "GEM serdes_rate not specified");
+ interface_supported = 0;
+ }
+ if (of_property_read_u32(np, "fixed-speed",
+ &bp->fixed_speed))
+ bp->fixed_speed = SPEED_UNKNOWN;
+ } else if (err == PHY_INTERFACE_MODE_SGMII ||
err == PHY_INTERFACE_MODE_1000BASEX ||
err == PHY_INTERFACE_MODE_2500BASEX) {
if (!(bp->caps & MACB_CAPS_PCS))
--
2.17.1