There are some common operations shared between the dwmac hwifs, the only difference is where they are located within the device. These are already present in the form of dwmac_rane() and dwmac_ctrl_ane(). Rather than use these (which don't quite fit with phylink PCS, provide phylink PCS specific versions. Also provide an implementation to parse the RSGMII status register. Signed-off-by: Russell King (Oracle) <rmk+kernel@xxxxxxxxxxxxxxx> --- drivers/net/ethernet/stmicro/stmmac/Makefile | 2 +- .../net/ethernet/stmicro/stmmac/stmmac_pcs.c | 47 +++++++++++++++++ .../net/ethernet/stmicro/stmmac/stmmac_pcs.h | 50 +++++++++++++++++++ 3 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index c2f0e91f6bf8..9e15f7615ff4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \ mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o \ dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \ stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \ - stmmac_xdp.o stmmac_est.o \ + stmmac_xdp.o stmmac_est.o stmmac_pcs.o \ $(stmmac-y) stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c new file mode 100644 index 000000000000..292c039c9778 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include "stmmac.h" +#include "stmmac_pcs.h" + +static void __dwmac_ctrl_ane(struct stmmac_pcs *spcs, bool ane, bool srgmi_ral, + bool loopback) + +{ + u32 val; + + val = readl(spcs->pcs_base + GMAC_AN_CTRL(0)); + + /* Enable and restart the Auto-Negotiation */ + if (ane) + val |= GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_RAN; + else + val &= ~GMAC_AN_CTRL_ANE; + + /* In case of MAC-2-MAC connection, block is configured to operate + * according to MAC conf register. + */ + if (srgmi_ral) + val |= GMAC_AN_CTRL_SGMRAL; + + if (loopback) + val |= GMAC_AN_CTRL_ELE; + else + val &= ~GMAC_AN_CTRL_ELE; + + writel(val, spcs->pcs_base + GMAC_AN_CTRL(0)); +} + +int dwmac_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, + phy_interface_t interface, + const unsigned long *advertising, + bool permit_pause_to_mac) +{ + struct stmmac_pcs *spcs = phylink_pcs_to_stmmac_pcs(pcs); + + /* The RGMII interface does not have the GMAC_AN_CTRL register */ + if (phy_interface_mode_is_rgmii(spcs->priv->plat->mac_interface)) + return 0; + + __dwmac_ctrl_ane(spcs, true, spcs->priv->hw->ps, false); + + return 0; +} diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h index 4a684c97dfae..f0d6442711ff 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h @@ -46,6 +46,19 @@ #define GMAC_ANE_RFE_SHIFT 12 #define GMAC_ANE_ACK BIT(14) +/* MAC specific status - for RGMII and SGMII. These appear as + * GMAC_RGSMIIIS[15:0] and GMAC_PHYIF_CONTROL_STATUS[31:16] + */ +#define GMAC_RS_STAT_LNKMOD BIT(0) +#define GMAC_RS_STAT_SPEED GENMASK(2, 1) +#define GMAC_RS_STAT_LNKSTS BIT(3) +#define GMAC_RS_STAT_JABTO BIT(4) +#define GMAC_RS_STAT_FALSECARDET BIT(5) + +#define GMAC_RS_STAT_SPEED_125 2 +#define GMAC_RS_STAT_SPEED_25 1 +#define GMAC_RS_STAT_SPEED_2_5 0 + /** * dwmac_pcs_isr - TBI, RTBI, or SGMII PHY ISR * @ioaddr: IO registers pointer @@ -109,4 +122,41 @@ static inline void dwmac_ctrl_ane(void __iomem *ioaddr, u32 reg, bool ane, writel(value, ioaddr + GMAC_AN_CTRL(reg)); } + +static inline bool dwmac_rs_decode_stat(struct phylink_link_state *state, + uint16_t rs_stat) +{ + unsigned int speed; + + state->link = !!(rs_stat & GMAC_RS_STAT_LNKSTS); + if (!state->link) + return false; + + speed = FIELD_GET(GMAC_RS_STAT_SPEED, rs_stat); + switch (speed) { + case GMAC_RS_STAT_SPEED_125: + state->speed = SPEED_1000; + break; + case GMAC_RS_STAT_SPEED_25: + state->speed = SPEED_100; + break; + case GMAC_RS_STAT_SPEED_2_5: + state->speed = SPEED_10; + break; + default: + state->link = false; + return false; + } + + state->duplex = rs_stat & GMAC_RS_STAT_LNKMOD ? + DUPLEX_FULL : DUPLEX_HALF; + + return true; +} + +int dwmac_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, + phy_interface_t interface, + const unsigned long *advertising, + bool permit_pause_to_mac); + #endif /* __STMMAC_PCS_H__ */ -- 2.30.2