This patch add support for PCS (for SGMII interface) and 2.5Gbps MAC in Cadence ethernet controller driver.
Signed-off-by: Parshuram Thombare <pthom...@cadence.com> --- drivers/net/ethernet/cadence/macb.h | 20 ++++ drivers/net/ethernet/cadence/macb_main.c | 154 +++++++++++++++++++++++------- 2 files changed, 140 insertions(+), 34 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 9bbaad9..bed4ded 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -79,6 +79,7 @@ #define MACB_RBQPH 0x04D4 /* GEM register offsets. */ +#define GEM_NCR 0x0000 /* Network Control */ #define GEM_NCFGR 0x0004 /* Network Config */ #define GEM_USRIO 0x000c /* User IO */ #define GEM_DMACFG 0x0010 /* DMA Configuration */ @@ -273,6 +274,10 @@ #define MACB_IRXFCS_OFFSET 19 #define MACB_IRXFCS_SIZE 1 +/* GEM specific NCR bitfields. */ +#define GEM_TWO_PT_FIVE_GIG_OFFSET 29 +#define GEM_TWO_PT_FIVE_GIG_SIZE 1 + /* GEM specific NCFGR bitfields. */ #define GEM_GBE_OFFSET 10 /* Gigabit mode enable */ #define GEM_GBE_SIZE 1 @@ -463,6 +468,8 @@ #define GEM_IRQCOR_SIZE 1 #define GEM_DBWDEF_OFFSET 25 #define GEM_DBWDEF_SIZE 3 +#define GEM_NO_PCS_OFFSET 0 +#define GEM_NO_PCS_SIZE 1 /* Bitfields in DCFG2. */ #define GEM_RX_PKT_BUFF_OFFSET 20 @@ -648,6 +655,19 @@ #define MACB_CAPS_GIGABIT_MODE_AVAILABLE 0x20000000 #define MACB_CAPS_SG_DISABLED 0x40000000 #define MACB_CAPS_MACB_IS_GEM 0x80000000 +#define MACB_CAPS_PCS 0x01000000 +#define MACB_CAPS_TWO_PT_FIVE_GIG_SPEED 0x02000000 + +#define MACB_GEM7010_IDNUM 0x009 +#define MACB_GEM7014_IDNUM 0x107 +#define MACB_GEM7014A_IDNUM 0x207 +#define MACB_GEM7016_IDNUM 0x10a +#define MACB_GEM7017_IDNUM 0x00a +#define MACB_GEM7017A_IDNUM 0x20a +#define MACB_GEM7020_IDNUM 0x003 +#define MACB_GEM7021_IDNUM 0x00c +#define MACB_GEM7021A_IDNUM 0x20c +#define MACB_GEM7022_IDNUM 0x00b /* LSO settings */ #define MACB_LSO_UFO_ENABLE 0x01 diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index f2915f2..4f4f8e5 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -361,26 +361,50 @@ static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum, * macb_set_tx_clk() - Set a clock to a new frequency * @clk Pointer to the clock to change * @rate New frequency in Hz + * @interafce Phy interface * @dev Pointer to the struct net_device */ -static void macb_set_tx_clk(struct clk *clk, int speed, struct net_device *dev) +static void macb_set_tx_clk(struct clk *clk, int speed, + phy_interface_t interface, struct net_device *dev) { long ferr, rate, rate_rounded; if (!clk) return; - switch (speed) { - case SPEED_10: + if (interface == PHY_INTERFACE_MODE_GMII || + interface == PHY_INTERFACE_MODE_MII) { + switch (speed) { + case SPEED_10: rate = 2500000; break; - case SPEED_100: + case SPEED_100: rate = 25000000; break; - case SPEED_1000: + case SPEED_1000: rate = 125000000; break; - default: + default: + return; + } + } else if (interface == PHY_INTERFACE_MODE_SGMII) { + switch (speed) { + case SPEED_10: + rate = 1250000; + break; + case SPEED_100: + rate = 12500000; + break; + case SPEED_1000: + rate = 125000000; + break; + case SPEED_2500: + rate = 312500000; + break; + default: + return; + } + } else { return; } @@ -410,30 +434,49 @@ static void macb_handle_link_change(struct net_device *dev) spin_lock_irqsave(&bp->lock, flags); - if (phydev->link) { - if ((bp->speed != phydev->speed) || - (bp->duplex != phydev->duplex)) { - u32 reg; - - reg = macb_readl(bp, NCFGR); - reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); - if (macb_is_gem(bp)) - reg &= ~GEM_BIT(GBE); + if (phydev->link && (bp->speed != phydev->speed || + bp->duplex != phydev->duplex)) { + u32 reg; - if (phydev->duplex) - reg |= MACB_BIT(FD); + reg = macb_readl(bp, NCFGR); + reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); + if (macb_is_gem(bp)) + reg &= ~GEM_BIT(GBE); + if (phydev->duplex) + reg |= MACB_BIT(FD); + macb_or_gem_writel(bp, NCFGR, reg); + + 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) { + reg = gem_readl(bp, NCR) & + ~GEM_BIT(TWO_PT_FIVE_GIG); + gem_writel(bp, NCR, reg); + } + gem_writel(bp, NCFGR, GEM_BIT(GBE) | + gem_readl(bp, NCFGR)); + if (bp->caps & MACB_CAPS_TWO_PT_FIVE_GIG_SPEED && + phydev->speed == SPEED_2500) + gem_writel(bp, NCR, gem_readl(bp, NCR) | + GEM_BIT(TWO_PT_FIVE_GIG)); + } else if (phydev->speed == SPEED_1000) { + gem_writel(bp, NCFGR, GEM_BIT(GBE) | + gem_readl(bp, NCFGR)); + } else { + if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) { + reg = gem_readl(bp, NCFGR); + reg &= ~(GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL)); + gem_writel(bp, NCFGR, reg); + } if (phydev->speed == SPEED_100) - reg |= MACB_BIT(SPD); - if (phydev->speed == SPEED_1000 && - bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) - reg |= GEM_BIT(GBE); - - macb_or_gem_writel(bp, NCFGR, reg); - - bp->speed = phydev->speed; - bp->duplex = phydev->duplex; - status_change = 1; + macb_writel(bp, NCFGR, MACB_BIT(SPD) | + macb_readl(bp, NCFGR)); } + + bp->speed = phydev->speed; + bp->duplex = phydev->duplex; + status_change = 1; } if (phydev->link != bp->link) { @@ -453,7 +496,8 @@ static void macb_handle_link_change(struct net_device *dev) /* Update the TX clock rate if and only if the link is * up and there has been a link change. */ - macb_set_tx_clk(bp->tx_clk, phydev->speed, dev); + macb_set_tx_clk(bp->tx_clk, phydev->speed, + bp->phy_interface, dev); netif_carrier_on(dev); netdev_info(dev, "link up (%d/%s)\n", @@ -543,10 +587,16 @@ static int macb_mii_probe(struct net_device *dev) } /* mask with MAC supported features */ - if (macb_is_gem(bp) && bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) - phy_set_max_speed(phydev, SPEED_1000); - else - phy_set_max_speed(phydev, SPEED_100); + 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); + } else { + linkmode_copy(phydev->supported, PHY_BASIC_FEATURES); + } + + linkmode_copy(phydev->advertising, phydev->supported); if (bp->caps & MACB_CAPS_NO_GIGABIT_HALF) phy_remove_link_mode(phydev, @@ -2217,8 +2267,6 @@ static void macb_init_hw(struct macb *bp) macb_set_hwaddr(bp); config = macb_mdc_clk_div(bp); - if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) - config |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL); config |= MACB_BF(RBOF, NET_IP_ALIGN); /* Make eth data aligned */ config |= MACB_BIT(PAE); /* PAuse Enable */ config |= MACB_BIT(DRFCS); /* Discard Rx FCS */ @@ -3255,6 +3303,23 @@ static void macb_configure_caps(struct macb *bp, dcfg = gem_readl(bp, DCFG1); if (GEM_BFEXT(IRQCOR, dcfg) == 0) bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE; + if (GEM_BFEXT(NO_PCS, dcfg) == 0) + bp->caps |= MACB_CAPS_PCS; + switch (MACB_BFEXT(IDNUM, macb_readl(bp, MID))) { + case MACB_GEM7016_IDNUM: + case MACB_GEM7017_IDNUM: + case MACB_GEM7017A_IDNUM: + case MACB_GEM7020_IDNUM: + case MACB_GEM7021_IDNUM: + case MACB_GEM7021A_IDNUM: + case MACB_GEM7022_IDNUM: + if (bp->caps & MACB_CAPS_PCS) + bp->caps |= MACB_CAPS_TWO_PT_FIVE_GIG_SPEED; + break; + + default: + break; + } dcfg = gem_readl(bp, DCFG2); if ((dcfg & (GEM_BIT(RX_PKT_BUFF) | GEM_BIT(TX_PKT_BUFF))) == 0) bp->caps |= MACB_CAPS_FIFO_MODE; @@ -4110,7 +4175,28 @@ static int macb_probe(struct platform_device *pdev) else bp->phy_interface = PHY_INTERFACE_MODE_MII; } else { + switch (err) { + case PHY_INTERFACE_MODE_SGMII: + if (bp->caps & MACB_CAPS_PCS) { + bp->phy_interface = PHY_INTERFACE_MODE_SGMII; + break; + } + /* Fallthrough */ + + default: + if (macb_is_gem(bp)) + err = PHY_INTERFACE_MODE_GMII; + else + err = PHY_INTERFACE_MODE_MII; + /* Fallthrough */ + + case PHY_INTERFACE_MODE_GMII: + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_RMII: bp->phy_interface = err; + break; + } } /* IP specific init */ -- 1.7.1