diff options
author | René van Dorst <opensource@vdorst.com> | 2019-08-25 20:43:40 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-08-28 06:19:27 +0300 |
commit | 7e538372694b3e449783eed3981d59d2597c2882 (patch) | |
tree | 9bf928677a0dd882a474f87f35f04380402949ec /drivers/net/ethernet/mediatek/mtk_eth_soc.c | |
parent | b8fc9f30821ec0ca018b3716fbed55ab6910a8f1 (diff) | |
download | linux-7e538372694b3e449783eed3981d59d2597c2882.tar.xz |
net: ethernet: mediatek: Re-add support SGMII
* Re-add SGMII support but now with PHYLINK API support
So the SGMII changes are more clear
* Move SGMII block setup from mtk_gmac_sgmii_path_setup() to
mtk_mac_config()
* Merge mtk_setup_hw_path() into mtk_mac_config()
* Remove mediatek,physpeed property, fixed-link supports now any speed so
speed = <2500>; is now valid with PHYLINK
* Demagic SGMII register values
* Use phylink state to setup fixed-link mode
Signed-off-by: René van Dorst <opensource@vdorst.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/mediatek/mtk_eth_soc.c')
-rw-r--r-- | drivers/net/ethernet/mediatek/mtk_eth_soc.c | 151 |
1 files changed, 133 insertions, 18 deletions
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 7d2566dd4ce0..b41884e12434 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -193,8 +193,8 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, struct mtk_mac *mac = container_of(config, struct mtk_mac, phylink_config); struct mtk_eth *eth = mac->hw; - u32 mcr_cur, mcr_new; - int val, ge_mode = 0; + u32 mcr_cur, mcr_new, sid; + int val, ge_mode, err; /* MT76x8 has no hardware settings between for the MAC */ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) && @@ -208,29 +208,42 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, MTK_GMAC1_TRGMII)) goto err_phy; /* fall through */ - case PHY_INTERFACE_MODE_GMII: case PHY_INTERFACE_MODE_RGMII_TXID: case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII: - break; case PHY_INTERFACE_MODE_MII: - ge_mode = 1; - break; case PHY_INTERFACE_MODE_REVMII: - ge_mode = 2; - break; case PHY_INTERFACE_MODE_RMII: - if (mac->id) - goto err_phy; - ge_mode = 3; + if (MTK_HAS_CAPS(eth->soc->caps, MTK_RGMII)) { + err = mtk_gmac_rgmii_path_setup(eth, mac->id); + if (err) + goto init_err; + } + break; + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + case PHY_INTERFACE_MODE_SGMII: + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { + err = mtk_gmac_sgmii_path_setup(eth, mac->id); + if (err) + goto init_err; + } + break; + case PHY_INTERFACE_MODE_GMII: + if (MTK_HAS_CAPS(eth->soc->caps, MTK_GEPHY)) { + err = mtk_gmac_gephy_path_setup(eth, mac->id); + if (err) + goto init_err; + } break; default: goto err_phy; } /* Setup clock for 1st gmac */ - if (!mac->id && + if (!mac->id && state->interface != PHY_INTERFACE_MODE_SGMII && + !phy_interface_mode_is_8023z(state->interface) && MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GMAC1_TRGMII)) { if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_TRGMII_MT7621_CLK)) { @@ -245,6 +258,23 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, } } + ge_mode = 0; + switch (state->interface) { + case PHY_INTERFACE_MODE_MII: + ge_mode = 1; + break; + case PHY_INTERFACE_MODE_REVMII: + ge_mode = 2; + break; + case PHY_INTERFACE_MODE_RMII: + if (mac->id) + goto err_phy; + ge_mode = 3; + break; + default: + break; + } + /* put the gmac into the right mode */ regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); val &= ~SYSCFG0_GE_MODE(SYSCFG0_GE_MASK, mac->id); @@ -254,6 +284,40 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, mac->interface = state->interface; } + /* SGMII */ + if (state->interface == PHY_INTERFACE_MODE_SGMII || + phy_interface_mode_is_8023z(state->interface)) { + /* The path GMAC to SGMII will be enabled once the SGMIISYS is + * being setup done. + */ + regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); + + regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, + SYSCFG0_SGMII_MASK, + ~(u32)SYSCFG0_SGMII_MASK); + + /* Decide how GMAC and SGMIISYS be mapped */ + sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? + 0 : mac->id; + + /* Setup SGMIISYS with the determined property */ + if (state->interface != PHY_INTERFACE_MODE_SGMII) + err = mtk_sgmii_setup_mode_force(eth->sgmii, sid, + state); + else if (phylink_autoneg_inband(mode)) + err = mtk_sgmii_setup_mode_an(eth->sgmii, sid); + + if (err) + goto init_err; + + regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, + SYSCFG0_SGMII_MASK, val); + } else if (phylink_autoneg_inband(mode)) { + dev_err(eth->dev, + "In-band mode not supported in non SGMII mode!\n"); + return; + } + /* Setup gmac */ mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); mcr_new = mcr_cur; @@ -264,6 +328,7 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, MAC_MCR_BACKOFF_EN | MAC_MCR_BACKPR_EN | MAC_MCR_FORCE_LINK; switch (state->speed) { + case SPEED_2500: case SPEED_1000: mcr_new |= MAC_MCR_SPEED_1000; break; @@ -288,6 +353,11 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, err_phy: dev_err(eth->dev, "%s: GMAC%d mode %s not supported!\n", __func__, mac->id, phy_modes(state->interface)); + return; + +init_err: + dev_err(eth->dev, "%s: GMAC%d mode %s err: %d!\n", __func__, + mac->id, phy_modes(state->interface), err); } static int mtk_mac_link_state(struct phylink_config *config, @@ -326,7 +396,10 @@ static int mtk_mac_link_state(struct phylink_config *config, static void mtk_mac_an_restart(struct phylink_config *config) { - /* Do nothing */ + struct mtk_mac *mac = container_of(config, struct mtk_mac, + phylink_config); + + mtk_sgmii_restart_an(mac->hw, mac->id); } static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode, @@ -366,7 +439,10 @@ static void mtk_validate(struct phylink_config *config, !(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_RGMII) && phy_interface_mode_is_rgmii(state->interface)) && !(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_TRGMII) && - !mac->id && state->interface == PHY_INTERFACE_MODE_TRGMII)) { + !mac->id && state->interface == PHY_INTERFACE_MODE_TRGMII) && + !(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_SGMII) && + (state->interface == PHY_INTERFACE_MODE_SGMII || + phy_interface_mode_is_8023z(state->interface)))) { linkmode_zero(supported); return; } @@ -374,19 +450,53 @@ static void mtk_validate(struct phylink_config *config, phylink_set_port_modes(mask); phylink_set(mask, Autoneg); - if (state->interface == PHY_INTERFACE_MODE_TRGMII) { + switch (state->interface) { + case PHY_INTERFACE_MODE_TRGMII: phylink_set(mask, 1000baseT_Full); - } else { + break; + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + phylink_set(mask, 1000baseX_Full); + phylink_set(mask, 2500baseX_Full); + break; + case PHY_INTERFACE_MODE_GMII: + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + phylink_set(mask, 1000baseT_Half); + /* fall through */ + case PHY_INTERFACE_MODE_SGMII: + phylink_set(mask, 1000baseT_Full); + phylink_set(mask, 1000baseX_Full); + /* fall through */ + case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_RMII: + case PHY_INTERFACE_MODE_REVMII: + case PHY_INTERFACE_MODE_NA: + default: phylink_set(mask, 10baseT_Half); phylink_set(mask, 10baseT_Full); phylink_set(mask, 100baseT_Half); phylink_set(mask, 100baseT_Full); + break; + } - if (state->interface != PHY_INTERFACE_MODE_MII) { - phylink_set(mask, 1000baseT_Half); + if (state->interface == PHY_INTERFACE_MODE_NA) { + if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_SGMII)) { + phylink_set(mask, 1000baseT_Full); + phylink_set(mask, 1000baseX_Full); + phylink_set(mask, 2500baseX_Full); + } + if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_RGMII)) { phylink_set(mask, 1000baseT_Full); + phylink_set(mask, 1000baseT_Half); phylink_set(mask, 1000baseX_Full); } + if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GEPHY)) { + phylink_set(mask, 1000baseT_Full); + phylink_set(mask, 1000baseT_Half); + } } phylink_set(mask, Pause); @@ -394,6 +504,11 @@ static void mtk_validate(struct phylink_config *config, linkmode_and(supported, supported, mask); linkmode_and(state->advertising, state->advertising, mask); + + /* We can only operate at 2500BaseX or 1000BaseX. If requested + * to advertise both, only report advertising at 2500BaseX. + */ + phylink_helper_basex_speed(state); } static const struct phylink_mac_ops mtk_phylink_ops = { |