From a3ed309ae79917e4f990b4afa5a451db90c7d3d5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 23 Dec 2016 01:09:44 +0000 Subject: net: mvgmac: support different hw versions Signed-off-by: Russell King --- drivers/net/ethernet/marvell/mvgmac.c | 118 ++++++++++++++++++++++++++++++---- drivers/net/ethernet/marvell/mvgmac.h | 9 +++ drivers/net/ethernet/marvell/mvneta.c | 1 + 3 files changed, 115 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvgmac.c b/drivers/net/ethernet/marvell/mvgmac.c index aee6dff9f569..04da6d475ff1 100644 --- a/drivers/net/ethernet/marvell/mvgmac.c +++ b/drivers/net/ethernet/marvell/mvgmac.c @@ -20,6 +20,8 @@ #include "mvgmac.h" enum { + /* N = Neta, 21 = PPV2.1, 22 = PPV2.2 */ + /* N: 0-14 21: 0,2-15 22: 0-14 */ GMAC_CTRL0_REG = 0x00, GMAC_CTRL0_PORT_ENABLE = BIT(0), GMAC_CTRL0_PORT_1000BASE_X = BIT(1), @@ -27,12 +29,21 @@ enum { GMAC_CTRL0_MAX_RX_SIZE_MASK = 0x1fff << GMAC_CTRL0_MAX_RX_SIZE_SHIFT, GMAC_CTRL0_MIB_CNTR_ENABLE = BIT(15), + /* N: 21: 1,5,6 22: */ + GMAC_CTRL1_REG = 0x04, + GMAC_CTRL1_PERIODIC_XON_ENABLE = BIT(1), + GMAC_CTRL1_GMII_LB_ENABLE = BIT(5), + GMAC_CTRL1_PCS_LB_ENABLE = BIT(6), + + /* ALL: 0,3,4,6 */ GMAC_CTRL2_REG = 0x08, GMAC_CTRL2_INBAND_AN_SGMII = BIT(0), GMAC_CTRL2_PCS_ENABLE = BIT(3), GMAC_CTRL2_PORT_RGMII = BIT(4), GMAC_CTRL2_PORT_RESET = BIT(6), + /* N:0-9,11-13 21:0,1,5-7,9,12,13 22:0-7,9-15 */ + /* 22 bit 2 - EN_PCS_AN */ GMAC_ANEG_REG = 0x0c, GMAC_ANEG_FORCE_LINK_DOWN = BIT(0), GMAC_ANEG_FORCE_LINK_PASS = BIT(1), @@ -44,9 +55,12 @@ enum { GMAC_ANEG_AN_SPEED_ENABLE = BIT(7), GMAC_ANEG_CONFIG_FLOW_CTRL = BIT(8), GMAC_ANEG_ADVERT_SYM_FLOW_CTRL = BIT(9), + GMAC_ANEG_ADVERT_ASYM_FLOW_CTRL = BIT(10), GMAC_ANEG_AN_FLOW_CTRL_ENABLE = BIT(11), GMAC_ANEG_FULL_DUPLEX = BIT(12), GMAC_ANEG_AN_DUPLEX_ENABLE = BIT(13), + /* pp22: bit 14 - phy mode */ + /* pp22: bit 15 - choose sample tx config */ GMAC_STATUS_REG = 0x10, MVGMAC_LINK_UP = BIT(0), @@ -60,8 +74,21 @@ enum { MVGMAC_AN_COMPLETE = BIT(11), MVGMAC_SYNC_OK = BIT(14), + /* N: 21:6-13 22: */ + GMAC_FIFO_CFG1_REG = 0x1c, + GMAC_FIFO_CFG1_TX_MIN_TH_SHIFT = 6, + GMAC_FIFO_CFG1_TX_MIN_TH_MASK = 0x7f << + GMAC_FIFO_CFG1_TX_MIN_TH_SHIFT, + + /* N:1 21: 22:0,3-7 */ GMAC_CTRL4_REG = 0x90, + GMAC_CTRL4_EXT_PIN_GMII_SEL = BIT(0), GMAC_CTRL4_SHORT_PREAMBLE_ENABLE = BIT(1), + GMAC_CTRL4_FC_RX_ENABLE = BIT(3), + GMAC_CTRL4_FC_TX_ENABLE = BIT(4), + GMAC_CTRL4_DP_CLK_SEL = BIT(5), + GMAC_CTRL4_SYNC_BYPASS = BIT(6), + GMAC_CTRL4_QSGMII_BYPASS = BIT(7), GMAC_LPI_CTRL0_REG = 0xc0, GMAC_LPI_CTRL0_TS = 0xff << 8, @@ -115,6 +142,49 @@ void mvgmac_port_disable(struct mvgmac *gmac) } EXPORT_SYMBOL_GPL(mvgmac_port_disable); +int mvgmac_configure(struct mvgmac *gmac, phy_interface_t phy_mode) +{ + u32 ctrl4; + + switch (phy_mode) { + case PHY_INTERFACE_MODE_QSGMII: + ctrl4 = 0; + break; + + case PHY_INTERFACE_MODE_SGMII: + ctrl4 = GMAC_CTRL4_QSGMII_BYPASS; + break; + + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + ctrl4 = GMAC_CTRL4_QSGMII_BYPASS | + GMAC_CTRL4_EXT_PIN_GMII_SEL; + break; + + default: + return -EINVAL; + } + + if (gmac->version == MVGMAC_PP21) { + /* Min. TX threshold must be less than minimum packet length */ + mvgmac_modify(gmac->base + GMAC_FIFO_CFG1_REG, + GMAC_FIFO_CFG1_TX_MIN_TH_MASK, + FIELD_PREP(GMAC_FIFO_CFG1_TX_MIN_TH_MASK, + 64 - 4 - 2)); + } else if (gmac->version == MVGMAC_PP22) { + mvgmac_modify(gmac->base + GMAC_CTRL4_REG, + GMAC_CTRL4_DP_CLK_SEL | GMAC_CTRL4_SYNC_BYPASS | + GMAC_CTRL4_QSGMII_BYPASS | + GMAC_CTRL4_EXT_PIN_GMII_SEL, + GMAC_CTRL4_SYNC_BYPASS | ctrl4); + } + + return 0; +} +EXPORT_SYMBOL_GPL(mvgmac_configure); + void mvgmac_link_unforce(struct mvgmac *gmac) { mvgmac_clear(gmac->base + GMAC_ANEG_REG, @@ -140,16 +210,21 @@ EXPORT_SYMBOL_GPL(mvgmac_link_down); void mvgmac_link_up(struct mvgmac *gmac, int mode, int speed, int duplex, bool tx_pause, bool rx_pause) { - u32 an_mask, an_val; + u32 an_mask, an_val, ctrl4; - an_mask = GMAC_ANEG_CONFIG_FLOW_CTRL; - an_val = FIELD_PREP(GMAC_ANEG_CONFIG_FLOW_CTRL, tx_pause || rx_pause); + if (gmac->version == MVGMAC_NETA) { + an_mask = GMAC_ANEG_CONFIG_FLOW_CTRL; + an_val = FIELD_PREP(GMAC_ANEG_CONFIG_FLOW_CTRL, + tx_pause || rx_pause); + } else { + an_mask = 0; + an_val = 0; + } if (!phylink_autoneg_inband(mode)) { an_mask |= GMAC_ANEG_FORCE_LINK_DOWN | GMAC_ANEG_FORCE_LINK_PASS | - GMAC_ANEG_MII_SPEED | - GMAC_ANEG_GMII_SPEED | + GMAC_ANEG_MII_SPEED | GMAC_ANEG_GMII_SPEED | GMAC_ANEG_FULL_DUPLEX; an_val |= GMAC_ANEG_FORCE_LINK_PASS; @@ -162,7 +237,15 @@ void mvgmac_link_up(struct mvgmac *gmac, int mode, int speed, int duplex, an_val |= GMAC_ANEG_FULL_DUPLEX; } - mvgmac_modify(gmac->base + GMAC_ANEG_REG, an_mask, an_val); + if (an_mask) + mvgmac_modify(gmac->base + GMAC_ANEG_REG, an_mask, an_val); + + if (gmac->version == MVGMAC_PP22) { + ctrl4 = readl_relaxed(gmac->base + GMAC_CTRL4_REG); + ctrl4 = insert(ctrl4, GMAC_CTRL4_FC_TX_ENABLE, tx_pause); + ctrl4 = insert(ctrl4, GMAC_CTRL4_FC_RX_ENABLE, rx_pause); + writel_relaxed(ctrl4, gmac->base + GMAC_CTRL4_REG); + } } EXPORT_SYMBOL_GPL(mvgmac_link_up); @@ -252,6 +335,11 @@ int mvgmac_pcs_config(struct phylink_pcs *pcs, unsigned int mode, mask |= GMAC_ANEG_ADVERT_SYM_FLOW_CTRL; if (phylink_test(advertising, Pause)) val |= GMAC_ANEG_ADVERT_SYM_FLOW_CTRL; + if (gmac->version == MVGMAC_PP22) { + mask |= GMAC_ANEG_ADVERT_ASYM_FLOW_CTRL; + if (phylink_test(advertising, Asym_Pause)) + val |= GMAC_ANEG_ADVERT_ASYM_FLOW_CTRL; + } } } else { /* Phy or fixed speed - disable in-band AN modes */ @@ -265,7 +353,8 @@ int mvgmac_pcs_config(struct phylink_pcs *pcs, unsigned int mode, writel_relaxed(an, gmac->base + GMAC_ANEG_REG); /* We are only interested in the advertisement bits changing */ - return !!(changed & GMAC_ANEG_ADVERT_SYM_FLOW_CTRL); + return !!(changed & (GMAC_ANEG_ADVERT_SYM_FLOW_CTRL | + GMAC_ANEG_ADVERT_ASYM_FLOW_CTRL)); } EXPORT_SYMBOL_GPL(mvgmac_pcs_config); @@ -279,7 +368,7 @@ void mvgmac_config_mac(struct mvgmac *gmac, unsigned int mode, new_ctrl0 = gmac_ctrl0 & ~GMAC_CTRL0_PORT_1000BASE_X; new_ctrl2 = gmac_ctrl2 & ~(GMAC_CTRL2_INBAND_AN_SGMII | GMAC_CTRL2_PORT_RESET); - new_ctrl4 = gmac_ctrl4 & ~GMAC_CTRL4_SHORT_PREAMBLE_ENABLE; + new_ctrl4 = gmac_ctrl4; /* Even though it might look weird, when we're configured in * SGMII or QSGMII mode, the RGMII bit needs to be set. @@ -303,11 +392,14 @@ void mvgmac_config_mac(struct mvgmac *gmac, unsigned int mode, new_ctrl0 |= GMAC_CTRL0_PORT_1000BASE_X; } - /* When at 2.5G, the link partner can send frames with shortened - * preambles. - */ - if (state->interface == PHY_INTERFACE_MODE_2500BASEX) - new_ctrl4 |= GMAC_CTRL4_SHORT_PREAMBLE_ENABLE; + if (gmac->version == MVGMAC_NETA) { + /* When at 2.5G, the link partner can send frames with + * shortened preambles. + */ + new_ctrl4 &= ~GMAC_CTRL4_SHORT_PREAMBLE_ENABLE; + if (state->interface == PHY_INTERFACE_MODE_2500BASEX) + new_ctrl4 |= GMAC_CTRL4_SHORT_PREAMBLE_ENABLE; + } if (new_ctrl0 != gmac_ctrl0) writel_relaxed(new_ctrl0, gmac->base + GMAC_CTRL0_REG); diff --git a/drivers/net/ethernet/marvell/mvgmac.h b/drivers/net/ethernet/marvell/mvgmac.h index dea376505eb3..36ed203094be 100644 --- a/drivers/net/ethernet/marvell/mvgmac.h +++ b/drivers/net/ethernet/marvell/mvgmac.h @@ -12,8 +12,16 @@ */ #define MARVELL_HEADER_SIZE 2 +enum { + /* GMAC version */ + MVGMAC_NETA, + MVGMAC_PP21, + MVGMAC_PP22, +}; + struct mvgmac { void __iomem *base; + unsigned int version; struct phylink_pcs pcs; }; @@ -25,6 +33,7 @@ static inline struct mvgmac *pcs_to_mvgmac(struct phylink_pcs *pcs) void mvgmac_set_max_rx_size(struct mvgmac *gmac, size_t max_rx_size); void mvgmac_port_enable(struct mvgmac *gmac); void mvgmac_port_disable(struct mvgmac *gmac); +int mvgmac_configure(struct mvgmac *gmac, phy_interface_t phy_mode); void mvgmac_link_unforce(struct mvgmac *gmac); void mvgmac_link_force_down(struct mvgmac *gmac); void mvgmac_link_down(struct mvgmac *gmac, int mode); diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 38063d5ad220..19eef504b6e0 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -5170,6 +5170,7 @@ static int mvneta_probe(struct platform_device *pdev) clk_prepare_enable(pp->clk_bus); pp->gmac.base = pp->base + MVNETA_GMAC_BASE; + pp->gmac.version = MVGMAC_NETA; pp->gmac.pcs.ops = &mvneta_phylink_pcs_ops; pp->tx_lpi_timer = 16; -- cgit