From 8098317b4fdffa8b82a7e89a8fb76b142c22497b 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 | 108 ++++++++++++++++++++++++++++++---- drivers/net/ethernet/marvell/mvgmac.h | 9 +++ drivers/net/ethernet/marvell/mvneta.c | 1 + 3 files changed, 108 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvgmac.c b/drivers/net/ethernet/marvell/mvgmac.c index 6c0b7c5c0b24..e776d4e85d3f 100644 --- a/drivers/net/ethernet/marvell/mvgmac.c +++ b/drivers/net/ethernet/marvell/mvgmac.c @@ -19,6 +19,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), @@ -26,12 +28,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), @@ -43,9 +54,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), @@ -59,8 +73,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, @@ -111,6 +138,47 @@ void mvgmac_disable(struct mvgmac *gmac) } EXPORT_SYMBOL_GPL(mvgmac_disable); +int mvgmac_configure(struct mvgmac *gmac, phy_interface_t phy_mode) +{ + bool ext_pin_gmii; + u32 val; + + switch (phy_mode) { + case PHY_INTERFACE_MODE_QSGMII: + case PHY_INTERFACE_MODE_SGMII: + ext_pin_gmii = false; + break; + + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + ext_pin_gmii = true; + break; + + default: + return -EINVAL; + } + + if (gmac->version == MVGMAC_PP21) { + /* Min. TX threshold must be less than minimum packet length */ + val = readl_relaxed(gmac->base + GMAC_FIFO_CFG1_REG); + val = insert(val, GMAC_FIFO_CFG1_TX_MIN_TH_MASK, 64 - 4 - 2); + writel_relaxed(val, gmac->base + GMAC_FIFO_CFG1_REG); + } else if (gmac->version == MVGMAC_PP22) { + val = readl_relaxed(gmac->base + GMAC_CTRL4_REG); + val &= ~GMAC_CTRL4_DP_CLK_SEL; + val |= GMAC_CTRL4_SYNC_BYPASS; + val = insert(val, GMAC_CTRL4_QSGMII_BYPASS, + phy_mode != PHY_INTERFACE_MODE_QSGMII); + val = insert(val, GMAC_CTRL4_EXT_PIN_GMII_SEL, ext_pin_gmii); + writel_relaxed(val, gmac->base + GMAC_CTRL4_REG); + } + + return 0; +} +EXPORT_SYMBOL_GPL(mvgmac_configure); + void mvgmac_link_unforce(struct mvgmac *gmac) { u32 val; @@ -142,7 +210,7 @@ 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 val; + u32 val, ctrl4; val = readl_relaxed(gmac->base + GMAC_ANEG_REG); val &= ~GMAC_ANEG_CONFIG_FLOW_CTRL; @@ -163,8 +231,19 @@ void mvgmac_link_up(struct mvgmac *gmac, int mode, int speed, int duplex, val |= GMAC_ANEG_FULL_DUPLEX; } - if (tx_pause || rx_pause) - val |= GMAC_ANEG_CONFIG_FLOW_CTRL; + switch (gmac->version) { + case MVGMAC_NETA: + val = insert(val, GMAC_ANEG_CONFIG_FLOW_CTRL, + tx_pause || rx_pause); + break; + + case 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); + break; + } writel_relaxed(val, gmac->base + GMAC_ANEG_REG); } @@ -252,6 +331,11 @@ int mvgmac_pcs_config(struct mvgmac *gmac, 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 +349,8 @@ int mvgmac_pcs_config(struct mvgmac *gmac, 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 +364,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 +388,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 ceccc6777237..f4111fba7258 100644 --- a/drivers/net/ethernet/marvell/mvgmac.h +++ b/drivers/net/ethernet/marvell/mvgmac.h @@ -14,13 +14,22 @@ struct phylink_link_state; */ #define MARVELL_HEADER_SIZE 2 +enum { + /* GMAC version */ + MVGMAC_NETA, + MVGMAC_PP21, + MVGMAC_PP22, +}; + struct mvgmac { void __iomem *base; + unsigned int version; }; void mvgmac_set_max_rx_size(struct mvgmac *gmac, size_t max_rx_size); void mvgmac_enable(struct mvgmac *gmac); void mvgmac_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 5331f5a72ab5..b2225166f288 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -5074,6 +5074,7 @@ static int mvneta_probe(struct platform_device *pdev) } pp->gmac.base = pp->base + MVNETA_GMAC_BASE; + pp->gmac.version = MVGMAC_NETA; pp->tx_lpi_timer = 16; /* Alloc per-cpu port structure */ -- cgit