On Mon, Jun 24, 2019 at 01:12:35PM +0100, Parshuram Thombare wrote:
> This patch add support for high speed USXGMII PCS and 10G
> speed in Cadence ethernet controller driver.
> 
> Signed-off-by: Parshuram Thombare <pthom...@cadence.com>
> ---
>  drivers/net/ethernet/cadence/macb.h      |  41 +++++
>  drivers/net/ethernet/cadence/macb_main.c | 189 ++++++++++++++++++++---
>  2 files changed, 207 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/net/ethernet/cadence/macb.h 
> b/drivers/net/ethernet/cadence/macb.h
> index 330da702b946..809acff19be9 100644
> --- a/drivers/net/ethernet/cadence/macb.h
> +++ b/drivers/net/ethernet/cadence/macb.h
> @@ -82,6 +82,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 */
> @@ -167,6 +168,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 */
> @@ -274,6 +278,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
>  
> @@ -465,6 +471,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
> @@ -510,6 +520,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
> @@ -670,6 +708,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_IDNU                    0x107
> @@ -749,6 +788,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
> @@ -1262,6 +1302,7 @@ struct macb {
>       struct macb_pm_data pm_data;
>       struct phylink *pl;
>       struct phylink_config pl_config;
> +     u32 serdes_rate;
>  };
>  
>  #ifdef CONFIG_MACB_USE_HWSTAMP
> diff --git a/drivers/net/ethernet/cadence/macb_main.c 
> b/drivers/net/ethernet/cadence/macb_main.c
> index 1323f9b4d3b8..5afc03299bee 100644
> --- a/drivers/net/ethernet/cadence/macb_main.c
> +++ b/drivers/net/ethernet/cadence/macb_main.c
> @@ -84,6 +84,20 @@ static struct sifive_fu540_macb_mgmt *mgmt;
>  #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_5Gbps = 5,
> +     MACB_SERDES_RATE_10Gbps = 10,
> +};
> +
>  /* Graceful stop timeouts in us. We should allow up to
>   * 1 frame time (10 Mbits/s, full-duplex, ignoring collisions)
>   */
> @@ -93,6 +107,8 @@ static struct sifive_fu540_macb_mgmt *mgmt;
>  
>  #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:
>   *
> @@ -439,23 +455,37 @@ static int macb_mdio_write(struct mii_bus *bus, int 
> mii_id, int regnum,
>   */
>  static void macb_set_tx_clk(struct clk *clk, int speed, struct net_device 
> *dev)
>  {
> +     struct macb *bp = netdev_priv(dev);
>       long ferr, rate, rate_rounded;
>  
>       if (!clk)
>               return;
>  
> -     switch (speed) {
> -     case SPEED_10:
> -             rate = 2500000;
> -             break;
> -     case SPEED_100:
> -             rate = 25000000;
> -             break;
> -     case SPEED_1000:
> -             rate = 125000000;
> -             break;
> -     default:
> -             return;
> +     if (bp->phy_interface == PHY_INTERFACE_MODE_USXGMII) {
> +             switch (bp->serdes_rate) {
> +             case MACB_SERDES_RATE_5Gbps:
> +                     rate = 78125000;
> +                     break;
> +             case MACB_SERDES_RATE_10Gbps:
> +                     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;
> +             }
>       }
>  
>       rate_rounded = clk_round_rate(clk, rate);
> @@ -485,6 +515,21 @@ static void gem_phylink_validate(struct phylink_config 
> *pl_config,
>  
>       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);
> +             }

If MACB_CAPS_GIGABIT_MODE_AVAILABLE is not set, are these interface
modes supported by the hardware?  If the PHY interface mode is not
supported, then the returned support mask must be cleared.

> +     /* fallthrough */
>       case PHY_INTERFACE_MODE_SGMII:
>       case PHY_INTERFACE_MODE_GMII:
>       case PHY_INTERFACE_MODE_RGMII:
> @@ -516,6 +561,91 @@ static int gem_phylink_mac_link_state(struct 
> phylink_config *pl_config,
>       return -EOPNOTSUPP;
>  }
>  
> +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 inline int gem_mac_usx_configure(struct macb *bp, int spd)
> +{
> +     u32 speed, config;
> +
> +     gem_writel(bp, NCFGR, GEM_BIT(PCSSEL) |
> +                (~GEM_BIT(SGMIIEN) & gem_readl(bp, NCFGR)));
> +     gem_writel(bp, NCR, gem_readl(bp, NCR) |
> +                GEM_BIT(ENABLE_HS_MAC));
> +     gem_writel(bp, NCFGR, gem_readl(bp, NCFGR) |
> +                MACB_BIT(FD));
> +     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) {
> +             netdev_warn(bp->dev, "USXGMII block lock failed");
> +             return -ETIMEDOUT;
> +     }
> +
> +     switch (spd) {
> +     case SPEED_10000:
> +             if (bp->serdes_rate >= MACB_SERDES_RATE_10Gbps) {
> +                     speed = HS_MAC_SPEED_10000M;
> +             } else {
> +                     netdev_warn(bp->dev, "10G speed isn't supported by HW");
> +                     netdev_warn(bp->dev, "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)));
> +     return 0;
> +}
> +
> +static inline void gem_mac_configure(struct macb *bp, int speed)
> +{
> +     if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII)
> +             gem_writel(bp, NCFGR, GEM_BIT(SGMIIEN) |
> +                        GEM_BIT(PCSSEL) |
> +                        gem_readl(bp, NCFGR));

Is this still necessary?

> +
> +     switch (speed) {
> +     case SPEED_1000:
> +             gem_writel(bp, NCFGR, GEM_BIT(GBE) |
> +                        gem_readl(bp, NCFGR));
> +             break;
> +     case SPEED_100:
> +             macb_writel(bp, NCFGR, MACB_BIT(SPD) |
> +                         macb_readl(bp, NCFGR));

What happens to the NCFGR register if we call mac_config() first for
a 1G speed, then 100M and finally 10M - what value does the NCFGR
register end up with?

I suspect it ends up with both the GBE and SPD bits set, and that is
probably not what you want.

> +             break;
> +     default:
> +             break;
> +     }
> +}
> +
>  static void gem_mac_config(struct phylink_config *pl_config, unsigned int 
> mode,
>                          const struct phylink_link_state *state)
>  {
> @@ -558,18 +688,17 @@ static void gem_mac_config(struct phylink_config 
> *pl_config, unsigned int mode,
>  
>               if (state->duplex)
>                       reg |= MACB_BIT(FD);
> +             macb_or_gem_writel(bp, NCFGR, reg);
>  
> -             switch (state->speed) {
> -             case SPEED_1000:
> -                     reg |= GEM_BIT(GBE);
> -                     break;
> -             case SPEED_100:
> -                     reg |= MACB_BIT(SPD);
> -                     break;
> -             default:
> -                     break;
> +             if (bp->phy_interface == PHY_INTERFACE_MODE_USXGMII) {
> +                     if (gem_mac_usx_configure(bp, state->speed) < 0) {
> +                             spin_unlock_irqrestore(&bp->lock, flags);
> +                             phylink_mac_change(bp->pl, false);
> +                             return;
> +                     }
> +             } else {
> +                     gem_mac_configure(bp, state->speed);
>               }
> -             macb_or_gem_writel(bp, NCFGR, reg);
>  
>               bp->speed = state->speed;
>               bp->duplex = state->duplex;
> @@ -3416,6 +3545,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;
> @@ -4404,7 +4536,18 @@ static int macb_probe(struct platform_device *pdev)
>       } else if (bp->caps & MACB_CAPS_MACB_IS_GEM_GXL) {
>               u32 interface_supported = 1;
>  
> -             if (phy_mode == PHY_INTERFACE_MODE_SGMII) {
> +             if (phy_mode == 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-gbps",
> +                                              &bp->serdes_rate)) {
> +                             netdev_err(dev,
> +                                        "GEM serdes_rate not specified");
> +                             interface_supported = 0;
> +                     }
> +             } else if (phy_mode == PHY_INTERFACE_MODE_SGMII) {
>                       if (!(bp->caps & MACB_CAPS_PCS))
>                               interface_supported = 0;
>               } else if (phy_mode == PHY_INTERFACE_MODE_GMII ||
> -- 
> 2.17.1
> 
> 

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up

Reply via email to