From nobody Sat Sep 21 04:26:19 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 392EAC7EE36 for ; Wed, 1 Mar 2023 19:56:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229934AbjCAT4k (ORCPT ); Wed, 1 Mar 2023 14:56:40 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60978 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229918AbjCAT42 (ORCPT ); Wed, 1 Mar 2023 14:56:28 -0500 Received: from fudo.makrotopia.org (fudo.makrotopia.org [IPv6:2a07:2ec0:3002::71]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 210394ECDB; Wed, 1 Mar 2023 11:56:00 -0800 (PST) Received: from local by fudo.makrotopia.org with esmtpsa (TLS1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.96) (envelope-from ) id 1pXSYO-0007ND-1P; Wed, 01 Mar 2023 20:55:56 +0100 Date: Wed, 1 Mar 2023 19:55:52 +0000 From: Daniel Golle To: devicetree@vger.kernel.org, Rob Herring , Krzysztof Kozlowski , netdev@vger.kernel.org, linux-mediatek@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Russell King , Heiner Kallweit , Lorenzo Bianconi , Mark Lee , John Crispin , Felix Fietkau , AngeloGioacchino Del Regno , Matthias Brugger , DENG Qingfang , Landen Chao , Sean Wang , Paolo Abeni , Jakub Kicinski , Eric Dumazet , "David S. Miller" , Vladimir Oltean , Florian Fainelli , Andrew Lunn Cc: Jianhui Zhao , =?iso-8859-1?Q?Bj=F8rn?= Mork Subject: [RFC PATCH v11 12/12] net: dsa: mt7530: use external PCS driver Message-ID: <70bfd5f9b657c465d12236ffb8867ef5417856b3.1677699407.git.daniel@makrotopia.org> References: MIME-Version: 1.0 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable In-Reply-To: Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Implement regmap access wrappers, for now only to be used by the pcs-mtk driver. Make use of external PCS driver and drop the reduntant implementation in mt7530.c. As a nice side effect the SGMII registers can now also more easily be inspected for debugging via /sys/kernel/debug/regmap. Reviewed-by: Russell King (Oracle) Tested-by: Bj=C3=B8rn Mork Signed-off-by: Daniel Golle --- drivers/net/dsa/Kconfig | 1 + drivers/net/dsa/mt7530.c | 277 ++++++++++----------------------------- drivers/net/dsa/mt7530.h | 47 +------ 3 files changed, 71 insertions(+), 254 deletions(-) diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index f6f3b43dfb06e..6b45fa8b69078 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -38,6 +38,7 @@ config NET_DSA_MT7530 tristate "MediaTek MT7530 and MT7531 Ethernet switch support" select NET_DSA_TAG_MTK select MEDIATEK_GE_PHY + select PCS_MTK_LYNXI help This enables support for the MediaTek MT7530 and MT7531 Ethernet switch chips. Multi-chip module MT7530 in MT7621AT, MT7621DAT, diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 3a15015bc409e..582ba30374c8c 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -2567,128 +2568,11 @@ static int mt7531_rgmii_setup(struct mt7530_priv *= priv, u32 port, return 0; } =20 -static void mt7531_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, - phy_interface_t interface, int speed, int duplex) -{ - struct mt7530_priv *priv =3D pcs_to_mt753x_pcs(pcs)->priv; - int port =3D pcs_to_mt753x_pcs(pcs)->port; - unsigned int val; - - /* For adjusting speed and duplex of SGMII force mode. */ - if (interface !=3D PHY_INTERFACE_MODE_SGMII || - phylink_autoneg_inband(mode)) - return; - - /* SGMII force mode setting */ - val =3D mt7530_read(priv, MT7531_SGMII_MODE(port)); - val &=3D ~MT7531_SGMII_IF_MODE_MASK; - - switch (speed) { - case SPEED_10: - val |=3D MT7531_SGMII_FORCE_SPEED_10; - break; - case SPEED_100: - val |=3D MT7531_SGMII_FORCE_SPEED_100; - break; - case SPEED_1000: - val |=3D MT7531_SGMII_FORCE_SPEED_1000; - break; - } - - /* MT7531 SGMII 1G force mode can only work in full duplex mode, - * no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not. - * - * The speed check is unnecessary as the MAC capabilities apply - * this restriction. --rmk - */ - if ((speed =3D=3D SPEED_10 || speed =3D=3D SPEED_100) && - duplex !=3D DUPLEX_FULL) - val |=3D MT7531_SGMII_FORCE_HALF_DUPLEX; - - mt7530_write(priv, MT7531_SGMII_MODE(port), val); -} - static bool mt753x_is_mac_port(u32 port) { return (port =3D=3D 5 || port =3D=3D 6); } =20 -static int mt7531_sgmii_setup_mode_force(struct mt7530_priv *priv, u32 por= t, - phy_interface_t interface) -{ - u32 val; - - if (!mt753x_is_mac_port(port)) - return -EINVAL; - - mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port), - MT7531_SGMII_PHYA_PWD); - - val =3D mt7530_read(priv, MT7531_PHYA_CTRL_SIGNAL3(port)); - val &=3D ~MT7531_RG_TPHY_SPEED_MASK; - /* Setup 2.5 times faster clock for 2.5Gbps data speeds with 10B/8B - * encoding. - */ - val |=3D (interface =3D=3D PHY_INTERFACE_MODE_2500BASEX) ? - MT7531_RG_TPHY_SPEED_3_125G : MT7531_RG_TPHY_SPEED_1_25G; - mt7530_write(priv, MT7531_PHYA_CTRL_SIGNAL3(port), val); - - mt7530_clear(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE); - - /* MT7531 SGMII 1G and 2.5G force mode can only work in full duplex - * mode, no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not. - */ - mt7530_rmw(priv, MT7531_SGMII_MODE(port), - MT7531_SGMII_IF_MODE_MASK | MT7531_SGMII_REMOTE_FAULT_DIS, - MT7531_SGMII_FORCE_SPEED_1000); - - mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0); - - return 0; -} - -static int mt7531_sgmii_setup_mode_an(struct mt7530_priv *priv, int port, - phy_interface_t interface) -{ - if (!mt753x_is_mac_port(port)) - return -EINVAL; - - mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port), - MT7531_SGMII_PHYA_PWD); - - mt7530_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port), - MT7531_RG_TPHY_SPEED_MASK, MT7531_RG_TPHY_SPEED_1_25G); - - mt7530_set(priv, MT7531_SGMII_MODE(port), - MT7531_SGMII_REMOTE_FAULT_DIS | - MT7531_SGMII_SPEED_DUPLEX_AN); - - mt7530_rmw(priv, MT7531_PCS_SPEED_ABILITY(port), - MT7531_SGMII_TX_CONFIG_MASK, 1); - - mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE); - - mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_RESTART); - - mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0); - - return 0; -} - -static void mt7531_pcs_an_restart(struct phylink_pcs *pcs) -{ - struct mt7530_priv *priv =3D pcs_to_mt753x_pcs(pcs)->priv; - int port =3D pcs_to_mt753x_pcs(pcs)->port; - u32 val; - - /* Only restart AN when AN is enabled */ - val =3D mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); - if (val & MT7531_SGMII_AN_ENABLE) { - val |=3D MT7531_SGMII_AN_RESTART; - mt7530_write(priv, MT7531_PCS_CONTROL_1(port), val); - } -} - static int mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode, phy_interface_t interface) @@ -2711,11 +2595,11 @@ mt7531_mac_config(struct dsa_switch *ds, int port, = unsigned int mode, phydev =3D dp->slave->phydev; return mt7531_rgmii_setup(priv, port, interface, phydev); case PHY_INTERFACE_MODE_SGMII: - return mt7531_sgmii_setup_mode_an(priv, port, interface); case PHY_INTERFACE_MODE_NA: case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_2500BASEX: - return mt7531_sgmii_setup_mode_force(priv, port, interface); + /* handled in SGMII PCS driver */ + return 0; default: return -EINVAL; } @@ -2740,11 +2624,11 @@ mt753x_phylink_mac_select_pcs(struct dsa_switch *ds= , int port, =20 switch (interface) { case PHY_INTERFACE_MODE_TRGMII: + return &priv->pcs[port].pcs; case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_2500BASEX: - return &priv->pcs[port].pcs; - + return priv->ports[port].sgmii_pcs; default: return NULL; } @@ -2982,86 +2866,6 @@ static void mt7530_pcs_get_state(struct phylink_pcs = *pcs, state->pause |=3D MLO_PAUSE_TX; } =20 -static int -mt7531_sgmii_pcs_get_state_an(struct mt7530_priv *priv, int port, - struct phylink_link_state *state) -{ - u32 status, val; - u16 config_reg; - - status =3D mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); - state->link =3D !!(status & MT7531_SGMII_LINK_STATUS); - state->an_complete =3D !!(status & MT7531_SGMII_AN_COMPLETE); - if (state->interface =3D=3D PHY_INTERFACE_MODE_SGMII && - (status & MT7531_SGMII_AN_ENABLE)) { - val =3D mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port)); - config_reg =3D val >> 16; - - switch (config_reg & LPA_SGMII_SPD_MASK) { - case LPA_SGMII_1000: - state->speed =3D SPEED_1000; - break; - case LPA_SGMII_100: - state->speed =3D SPEED_100; - break; - case LPA_SGMII_10: - state->speed =3D SPEED_10; - break; - default: - dev_err(priv->dev, "invalid sgmii PHY speed\n"); - state->link =3D false; - return -EINVAL; - } - - if (config_reg & LPA_SGMII_FULL_DUPLEX) - state->duplex =3D DUPLEX_FULL; - else - state->duplex =3D DUPLEX_HALF; - } - - return 0; -} - -static void -mt7531_sgmii_pcs_get_state_inband(struct mt7530_priv *priv, int port, - struct phylink_link_state *state) -{ - unsigned int val; - - val =3D mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); - state->link =3D !!(val & MT7531_SGMII_LINK_STATUS); - if (!state->link) - return; - - state->an_complete =3D state->link; - - if (state->interface =3D=3D PHY_INTERFACE_MODE_2500BASEX) - state->speed =3D SPEED_2500; - else - state->speed =3D SPEED_1000; - - state->duplex =3D DUPLEX_FULL; - state->pause =3D MLO_PAUSE_NONE; -} - -static void mt7531_pcs_get_state(struct phylink_pcs *pcs, - struct phylink_link_state *state) -{ - struct mt7530_priv *priv =3D pcs_to_mt753x_pcs(pcs)->priv; - int port =3D pcs_to_mt753x_pcs(pcs)->port; - - if (state->interface =3D=3D PHY_INTERFACE_MODE_SGMII) { - mt7531_sgmii_pcs_get_state_an(priv, port, state); - return; - } else if ((state->interface =3D=3D PHY_INTERFACE_MODE_1000BASEX) || - (state->interface =3D=3D PHY_INTERFACE_MODE_2500BASEX)) { - mt7531_sgmii_pcs_get_state_inband(priv, port, state); - return; - } - - state->link =3D false; -} - static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode, phy_interface_t interface, const unsigned long *advertising, @@ -3081,18 +2885,57 @@ static const struct phylink_pcs_ops mt7530_pcs_ops = =3D { .pcs_an_restart =3D mt7530_pcs_an_restart, }; =20 -static const struct phylink_pcs_ops mt7531_pcs_ops =3D { - .pcs_validate =3D mt753x_pcs_validate, - .pcs_get_state =3D mt7531_pcs_get_state, - .pcs_config =3D mt753x_pcs_config, - .pcs_an_restart =3D mt7531_pcs_an_restart, - .pcs_link_up =3D mt7531_pcs_link_up, +static int mt7530_regmap_read(void *context, unsigned int reg, unsigned in= t *val) +{ + struct mt7530_priv *priv =3D context; + + *val =3D mt7530_read(priv, reg); + return 0; +}; + +static int mt7530_regmap_write(void *context, unsigned int reg, unsigned i= nt val) +{ + struct mt7530_priv *priv =3D context; + + mt7530_write(priv, reg, val); + return 0; +}; + +static int mt7530_regmap_update_bits(void *context, unsigned int reg, + unsigned int mask, unsigned int val) +{ + struct mt7530_priv *priv =3D context; + + mt7530_rmw(priv, reg, mask, val); + return 0; +}; + +static const struct regmap_bus mt7531_regmap_bus =3D { + .reg_write =3D mt7530_regmap_write, + .reg_read =3D mt7530_regmap_read, + .reg_update_bits =3D mt7530_regmap_update_bits, +}; + +#define MT7531_PCS_REGMAP_CONFIG(_name, _reg_base) \ + { \ + .name =3D _name, \ + .reg_bits =3D 16, \ + .val_bits =3D 32, \ + .reg_stride =3D 4, \ + .reg_base =3D _reg_base, \ + .max_register =3D 0x17c, \ + } + +static const struct regmap_config mt7531_pcs_config[] =3D { + MT7531_PCS_REGMAP_CONFIG("port5", MT7531_SGMII_REG_BASE(5)), + MT7531_PCS_REGMAP_CONFIG("port6", MT7531_SGMII_REG_BASE(6)), }; =20 static int mt753x_setup(struct dsa_switch *ds) { struct mt7530_priv *priv =3D ds->priv; + struct regmap *regmap; int i, ret; =20 /* Initialise the PCS devices */ @@ -3100,8 +2943,6 @@ mt753x_setup(struct dsa_switch *ds) priv->pcs[i].pcs.ops =3D priv->info->pcs_ops; priv->pcs[i].priv =3D priv; priv->pcs[i].port =3D i; - if (mt753x_is_mac_port(i)) - priv->pcs[i].pcs.poll =3D 1; } =20 ret =3D priv->info->sw_setup(ds); @@ -3116,6 +2957,16 @@ mt753x_setup(struct dsa_switch *ds) if (ret && priv->irq) mt7530_free_irq_common(priv); =20 + if (priv->id =3D=3D ID_MT7531) + for (i =3D 0; i < 2; i++) { + regmap =3D devm_regmap_init(ds->dev, + &mt7531_regmap_bus, priv, + &mt7531_pcs_config[i]); + priv->ports[5 + i].sgmii_pcs =3D + mtk_pcs_lynxi_create(ds->dev, regmap, + MT7531_PHYA_CTRL_SIGNAL3, 0); + } + return ret; } =20 @@ -3211,7 +3062,7 @@ static const struct mt753x_info mt753x_table[] =3D { }, [ID_MT7531] =3D { .id =3D ID_MT7531, - .pcs_ops =3D &mt7531_pcs_ops, + .pcs_ops =3D &mt7530_pcs_ops, .sw_setup =3D mt7531_setup, .phy_read_c22 =3D mt7531_ind_c22_phy_read, .phy_write_c22 =3D mt7531_ind_c22_phy_write, @@ -3321,7 +3172,7 @@ static void mt7530_remove(struct mdio_device *mdiodev) { struct mt7530_priv *priv =3D dev_get_drvdata(&mdiodev->dev); - int ret =3D 0; + int ret =3D 0, i; =20 if (!priv) return; @@ -3340,6 +3191,10 @@ mt7530_remove(struct mdio_device *mdiodev) mt7530_free_irq(priv); =20 dsa_unregister_switch(priv->ds); + + for (i =3D 0; i < 2; ++i) + mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs); + mutex_destroy(&priv->reg_mutex); } =20 diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index 6b2fc6290ea84..c5d29f3fc1d80 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -364,47 +364,8 @@ enum mt7530_vlan_port_acc_frm { CCR_TX_OCT_CNT_BAD) =20 /* MT7531 SGMII register group */ -#define MT7531_SGMII_REG_BASE 0x5000 -#define MT7531_SGMII_REG(p, r) (MT7531_SGMII_REG_BASE + \ - ((p) - 5) * 0x1000 + (r)) - -/* Register forSGMII PCS_CONTROL_1 */ -#define MT7531_PCS_CONTROL_1(p) MT7531_SGMII_REG(p, 0x00) -#define MT7531_SGMII_LINK_STATUS BIT(18) -#define MT7531_SGMII_AN_ENABLE BIT(12) -#define MT7531_SGMII_AN_RESTART BIT(9) -#define MT7531_SGMII_AN_COMPLETE BIT(21) - -/* Register for SGMII PCS_SPPED_ABILITY */ -#define MT7531_PCS_SPEED_ABILITY(p) MT7531_SGMII_REG(p, 0x08) -#define MT7531_SGMII_TX_CONFIG_MASK GENMASK(15, 0) -#define MT7531_SGMII_TX_CONFIG BIT(0) - -/* Register for SGMII_MODE */ -#define MT7531_SGMII_MODE(p) MT7531_SGMII_REG(p, 0x20) -#define MT7531_SGMII_REMOTE_FAULT_DIS BIT(8) -#define MT7531_SGMII_IF_MODE_MASK GENMASK(5, 1) -#define MT7531_SGMII_FORCE_DUPLEX BIT(4) -#define MT7531_SGMII_FORCE_SPEED_MASK GENMASK(3, 2) -#define MT7531_SGMII_FORCE_SPEED_1000 BIT(3) -#define MT7531_SGMII_FORCE_SPEED_100 BIT(2) -#define MT7531_SGMII_FORCE_SPEED_10 0 -#define MT7531_SGMII_SPEED_DUPLEX_AN BIT(1) - -enum mt7531_sgmii_force_duplex { - MT7531_SGMII_FORCE_FULL_DUPLEX =3D 0, - MT7531_SGMII_FORCE_HALF_DUPLEX =3D 0x10, -}; - -/* Fields of QPHY_PWR_STATE_CTRL */ -#define MT7531_QPHY_PWR_STATE_CTRL(p) MT7531_SGMII_REG(p, 0xe8) -#define MT7531_SGMII_PHYA_PWD BIT(4) - -/* Values of SGMII SPEED */ -#define MT7531_PHYA_CTRL_SIGNAL3(p) MT7531_SGMII_REG(p, 0x128) -#define MT7531_RG_TPHY_SPEED_MASK (BIT(2) | BIT(3)) -#define MT7531_RG_TPHY_SPEED_1_25G 0x0 -#define MT7531_RG_TPHY_SPEED_3_125G BIT(2) +#define MT7531_SGMII_REG_BASE(p) (0x5000 + ((p) - 5) * 0x1000) +#define MT7531_PHYA_CTRL_SIGNAL3 0x128 =20 /* Register for system reset */ #define MT7530_SYS_CTRL 0x7000 @@ -703,13 +664,13 @@ struct mt7530_fdb { * @pm: The matrix used to show all connections with the port. * @pvid: The VLAN specified is to be considered a PVID at ingress. Any * untagged frames will be assigned to the related VLAN. - * @vlan_filtering: The flags indicating whether the port that can recogni= ze - * VLAN-tagged frames. + * @sgmii_pcs: Pointer to PCS instance for SerDes ports */ struct mt7530_port { bool enable; u32 pm; u16 pvid; + struct phylink_pcs *sgmii_pcs; }; =20 /* Port 5 interface select definitions */ --=20 2.39.2