net: ethernet: mtk_eth_soc: switch to external PCS driver
authorDaniel Golle <daniel@makrotopia.org>
Sun, 19 Mar 2023 12:58:02 +0000 (12:58 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 21 Mar 2023 02:48:35 +0000 (19:48 -0700)
Now that we got a PCS driver, use it and remove the now redundant
PCS code and it's header macros from the Ethernet driver.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Tested-by: Frank Wunderlich <frank-w@public-files.de>
Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/mediatek/Kconfig
drivers/net/ethernet/mediatek/Makefile
drivers/net/ethernet/mediatek/mtk_eth_soc.c
drivers/net/ethernet/mediatek/mtk_eth_soc.h
drivers/net/ethernet/mediatek/mtk_sgmii.c [deleted file]

index 97374fb..da0db41 100644 (file)
@@ -19,6 +19,8 @@ config NET_MEDIATEK_SOC
        select DIMLIB
        select PAGE_POOL
        select PAGE_POOL_STATS
+       select PCS_MTK_LYNXI
+       select REGMAP_MMIO
        help
          This driver supports the gigabit ethernet MACs in the
          MediaTek SoC family.
index 8e0c61c..03e008f 100644 (file)
@@ -4,7 +4,7 @@
 #
 
 obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
-mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o
+mtk_eth-y := mtk_eth_soc.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o
 mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o mtk_wed_mcu.o mtk_wed_wo.o
 ifdef CONFIG_DEBUG_FS
 mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o
index fc08c89..4403d3b 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/interrupt.h>
 #include <linux/pinctrl/devinfo.h>
 #include <linux/phylink.h>
+#include <linux/pcs/pcs-mtk-lynxi.h>
 #include <linux/jhash.h>
 #include <linux/bitfield.h>
 #include <net/dsa.h>
@@ -437,7 +438,7 @@ static struct phylink_pcs *mtk_mac_select_pcs(struct phylink_config *config,
                sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ?
                       0 : mac->id;
 
-               return mtk_sgmii_select_pcs(eth->sgmii, sid);
+               return eth->sgmii_pcs[sid];
        }
 
        return NULL;
@@ -4053,8 +4054,17 @@ static int mtk_unreg_dev(struct mtk_eth *eth)
        return 0;
 }
 
+static void mtk_sgmii_destroy(struct mtk_eth *eth)
+{
+       int i;
+
+       for (i = 0; i < MTK_MAX_DEVS; i++)
+               mtk_pcs_lynxi_destroy(eth->sgmii_pcs[i]);
+}
+
 static int mtk_cleanup(struct mtk_eth *eth)
 {
+       mtk_sgmii_destroy(eth);
        mtk_unreg_dev(eth);
        mtk_free_dev(eth);
        cancel_work_sync(&eth->pending_work);
@@ -4500,6 +4510,36 @@ void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev)
        rtnl_unlock();
 }
 
+static int mtk_sgmii_init(struct mtk_eth *eth)
+{
+       struct device_node *np;
+       struct regmap *regmap;
+       u32 flags;
+       int i;
+
+       for (i = 0; i < MTK_MAX_DEVS; i++) {
+               np = of_parse_phandle(eth->dev->of_node, "mediatek,sgmiisys", i);
+               if (!np)
+                       break;
+
+               regmap = syscon_node_to_regmap(np);
+               flags = 0;
+               if (of_property_read_bool(np, "mediatek,pnswap"))
+                       flags |= MTK_SGMII_FLAG_PN_SWAP;
+
+               of_node_put(np);
+
+               if (IS_ERR(regmap))
+                       return PTR_ERR(regmap);
+
+               eth->sgmii_pcs[i] = mtk_pcs_lynxi_create(eth->dev, regmap,
+                                                        eth->soc->ana_rgc3,
+                                                        flags);
+       }
+
+       return 0;
+}
+
 static int mtk_probe(struct platform_device *pdev)
 {
        struct resource *res = NULL;
@@ -4563,13 +4603,7 @@ static int mtk_probe(struct platform_device *pdev)
        }
 
        if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
-               eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii),
-                                         GFP_KERNEL);
-               if (!eth->sgmii)
-                       return -ENOMEM;
-
-               err = mtk_sgmii_init(eth->sgmii, pdev->dev.of_node,
-                                    eth->soc->ana_rgc3);
+               err = mtk_sgmii_init(eth);
 
                if (err)
                        return err;
@@ -4580,14 +4614,17 @@ static int mtk_probe(struct platform_device *pdev)
                                                            "mediatek,pctl");
                if (IS_ERR(eth->pctl)) {
                        dev_err(&pdev->dev, "no pctl regmap found\n");
-                       return PTR_ERR(eth->pctl);
+                       err = PTR_ERR(eth->pctl);
+                       goto err_destroy_sgmii;
                }
        }
 
        if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
                res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               if (!res)
-                       return -EINVAL;
+               if (!res) {
+                       err = -EINVAL;
+                       goto err_destroy_sgmii;
+               }
        }
 
        if (eth->soc->offload_version) {
@@ -4746,6 +4783,8 @@ err_deinit_hw:
        mtk_hw_deinit(eth);
 err_wed_exit:
        mtk_wed_exit();
+err_destroy_sgmii:
+       mtk_sgmii_destroy(eth);
 
        return err;
 }
index 666a7a4..23c7abe 100644 (file)
 #define ETHSYS_DMA_AG_MAP_QDMA BIT(1)
 #define ETHSYS_DMA_AG_MAP_PPE  BIT(2)
 
-/* SGMII subsystem config registers */
-/* BMCR (low 16) BMSR (high 16) */
-#define SGMSYS_PCS_CONTROL_1   0x0
-#define SGMII_BMCR             GENMASK(15, 0)
-#define SGMII_BMSR             GENMASK(31, 16)
-#define SGMII_AN_RESTART       BIT(9)
-#define SGMII_ISOLATE          BIT(10)
-#define SGMII_AN_ENABLE                BIT(12)
-#define SGMII_LINK_STATYS      BIT(18)
-#define SGMII_AN_ABILITY       BIT(19)
-#define SGMII_AN_COMPLETE      BIT(21)
-#define SGMII_PCS_FAULT                BIT(23)
-#define SGMII_AN_EXPANSION_CLR BIT(30)
-
-#define SGMSYS_PCS_ADVERTISE   0x8
-#define SGMII_ADVERTISE                GENMASK(15, 0)
-#define SGMII_LPA              GENMASK(31, 16)
-
-/* Register to programmable link timer, the unit in 2 * 8ns */
-#define SGMSYS_PCS_LINK_TIMER  0x18
-#define SGMII_LINK_TIMER_MASK  GENMASK(19, 0)
-#define SGMII_LINK_TIMER_DEFAULT       (0x186a0 & SGMII_LINK_TIMER_MASK)
-
-/* Register to control remote fault */
-#define SGMSYS_SGMII_MODE              0x20
-#define SGMII_IF_MODE_SGMII            BIT(0)
-#define SGMII_SPEED_DUPLEX_AN          BIT(1)
-#define SGMII_SPEED_MASK               GENMASK(3, 2)
-#define SGMII_SPEED_10                 FIELD_PREP(SGMII_SPEED_MASK, 0)
-#define SGMII_SPEED_100                        FIELD_PREP(SGMII_SPEED_MASK, 1)
-#define SGMII_SPEED_1000               FIELD_PREP(SGMII_SPEED_MASK, 2)
-#define SGMII_DUPLEX_HALF              BIT(4)
-#define SGMII_IF_MODE_BIT5             BIT(5)
-#define SGMII_REMOTE_FAULT_DIS         BIT(8)
-#define SGMII_CODE_SYNC_SET_VAL                BIT(9)
-#define SGMII_CODE_SYNC_SET_EN         BIT(10)
-#define SGMII_SEND_AN_ERROR_EN         BIT(11)
-#define SGMII_IF_MODE_MASK             GENMASK(5, 1)
-
-/* Register to reset SGMII design */
-#define SGMII_RESERVED_0       0x34
-#define SGMII_SW_RESET         BIT(0)
-
-/* Register to set SGMII speed, ANA RG_ Control Signals III*/
-#define SGMSYS_ANA_RG_CS3      0x2028
-#define RG_PHY_SPEED_MASK      (BIT(2) | BIT(3))
-#define RG_PHY_SPEED_1_25G     0x0
-#define RG_PHY_SPEED_3_125G    BIT(2)
-
-/* Register to power up QPHY */
-#define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8
-#define        SGMII_PHYA_PWD          BIT(4)
-
-/* Register to QPHY wrapper control */
-#define SGMSYS_QPHY_WRAP_CTRL  0xec
-#define SGMII_PN_SWAP_MASK     GENMASK(1, 0)
-#define SGMII_PN_SWAP_TX_RX    (BIT(0) | BIT(1))
-#define MTK_SGMII_FLAG_PN_SWAP BIT(0)
-
 /* Infrasys subsystem config registers */
 #define INFRA_MISC2            0x70c
 #define CO_QPHY_SEL            BIT(0)
@@ -1105,31 +1046,6 @@ struct mtk_soc_data {
 /* currently no SoC has more than 2 macs */
 #define MTK_MAX_DEVS                   2
 
-/* struct mtk_pcs -    This structure holds each sgmii regmap and associated
- *                     data
- * @regmap:            The register map pointing at the range used to setup
- *                     SGMII modes
- * @ana_rgc3:          The offset refers to register ANA_RGC3 related to regmap
- * @interface:         Currently configured interface mode
- * @pcs:               Phylink PCS structure
- * @flags:             Flags indicating hardware properties
- */
-struct mtk_pcs {
-       struct regmap   *regmap;
-       u32             ana_rgc3;
-       phy_interface_t interface;
-       struct phylink_pcs pcs;
-       u32             flags;
-};
-
-/* struct mtk_sgmii -  This is the structure holding sgmii regmap and its
- *                     characteristics
- * @pcs                Array of individual PCS structures
- */
-struct mtk_sgmii {
-       struct mtk_pcs  pcs[MTK_MAX_DEVS];
-};
-
 /* struct mtk_eth -    This is the main datasructure for holding the state
  *                     of the driver
  * @dev:               The device pointer
@@ -1149,6 +1065,7 @@ struct mtk_sgmii {
  *                     MII modes
  * @infra:              The register map pointing at the range used to setup
  *                      SGMII and GePHY path
+ * @sgmii_pcs:         Pointers to mtk-pcs-lynxi phylink_pcs instances
  * @pctl:              The register map pointing at the range used to setup
  *                     GMAC port drive/slew values
  * @dma_refcnt:                track how many netdevs are using the DMA engine
@@ -1189,8 +1106,8 @@ struct mtk_eth {
        u32                             msg_enable;
        unsigned long                   sysclk;
        struct regmap                   *ethsys;
-       struct regmap                   *infra;
-       struct mtk_sgmii                *sgmii;
+       struct regmap                   *infra;
+       struct phylink_pcs              *sgmii_pcs[MTK_MAX_DEVS];
        struct regmap                   *pctl;
        bool                            hwlro;
        refcount_t                      dma_refcnt;
@@ -1352,10 +1269,6 @@ void mtk_stats_update_mac(struct mtk_mac *mac);
 void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg);
 u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
 
-struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id);
-int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np,
-                  u32 ana_rgc3);
-
 int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id);
 int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id);
 int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id);
diff --git a/drivers/net/ethernet/mediatek/mtk_sgmii.c b/drivers/net/ethernet/mediatek/mtk_sgmii.c
deleted file mode 100644 (file)
index 61bd998..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2018-2019 MediaTek Inc.
-
-/* A library for MediaTek SGMII circuit
- *
- * Author: Sean Wang <sean.wang@mediatek.com>
- *
- */
-
-#include <linux/mfd/syscon.h>
-#include <linux/of.h>
-#include <linux/phylink.h>
-#include <linux/regmap.h>
-
-#include "mtk_eth_soc.h"
-
-static struct mtk_pcs *pcs_to_mtk_pcs(struct phylink_pcs *pcs)
-{
-       return container_of(pcs, struct mtk_pcs, pcs);
-}
-
-static void mtk_pcs_get_state(struct phylink_pcs *pcs,
-                             struct phylink_link_state *state)
-{
-       struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs);
-       unsigned int bm, adv;
-
-       /* Read the BMSR and LPA */
-       regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm);
-       regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv);
-
-       phylink_mii_c22_pcs_decode_state(state, FIELD_GET(SGMII_BMSR, bm),
-                                        FIELD_GET(SGMII_LPA, adv));
-}
-
-static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
-                         phy_interface_t interface,
-                         const unsigned long *advertising,
-                         bool permit_pause_to_mac)
-{
-       bool mode_changed = false, changed, use_an;
-       struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs);
-       unsigned int rgc3, sgm_mode, bmcr;
-       int advertise, link_timer;
-
-       advertise = phylink_mii_c22_pcs_encode_advertisement(interface,
-                                                            advertising);
-       if (advertise < 0)
-               return advertise;
-
-       /* Clearing IF_MODE_BIT0 switches the PCS to BASE-X mode, and
-        * we assume that fixes it's speed at bitrate = line rate (in
-        * other words, 1000Mbps or 2500Mbps).
-        */
-       if (interface == PHY_INTERFACE_MODE_SGMII) {
-               sgm_mode = SGMII_IF_MODE_SGMII;
-               if (phylink_autoneg_inband(mode)) {
-                       sgm_mode |= SGMII_REMOTE_FAULT_DIS |
-                                   SGMII_SPEED_DUPLEX_AN;
-                       use_an = true;
-               } else {
-                       use_an = false;
-               }
-       } else if (phylink_autoneg_inband(mode)) {
-               /* 1000base-X or 2500base-X autoneg */
-               sgm_mode = SGMII_REMOTE_FAULT_DIS;
-               use_an = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
-                                          advertising);
-       } else {
-               /* 1000base-X or 2500base-X without autoneg */
-               sgm_mode = 0;
-               use_an = false;
-       }
-
-       if (use_an) {
-               bmcr = SGMII_AN_ENABLE;
-       } else {
-               bmcr = 0;
-       }
-
-       if (mpcs->interface != interface) {
-               link_timer = phylink_get_link_timer_ns(interface);
-               if (link_timer < 0)
-                       return link_timer;
-
-               /* PHYA power down */
-               regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL,
-                                  SGMII_PHYA_PWD, SGMII_PHYA_PWD);
-
-               /* Reset SGMII PCS state */
-               regmap_update_bits(mpcs->regmap, SGMII_RESERVED_0,
-                                  SGMII_SW_RESET, SGMII_SW_RESET);
-
-               if (mpcs->flags & MTK_SGMII_FLAG_PN_SWAP)
-                       regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
-                                          SGMII_PN_SWAP_MASK,
-                                          SGMII_PN_SWAP_TX_RX);
-
-               if (interface == PHY_INTERFACE_MODE_2500BASEX)
-                       rgc3 = RG_PHY_SPEED_3_125G;
-               else
-                       rgc3 = 0;
-
-               /* Configure the underlying interface speed */
-               regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3,
-                                  RG_PHY_SPEED_3_125G, rgc3);
-
-               /* Setup the link timer */
-               regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, link_timer / 2 / 8);
-
-               mpcs->interface = interface;
-               mode_changed = true;
-       }
-
-       /* Update the advertisement, noting whether it has changed */
-       regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE,
-                                SGMII_ADVERTISE, advertise, &changed);
-
-       /* Update the sgmsys mode register */
-       regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE,
-                          SGMII_REMOTE_FAULT_DIS | SGMII_SPEED_DUPLEX_AN |
-                          SGMII_IF_MODE_SGMII, sgm_mode);
-
-       /* Update the BMCR */
-       regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1,
-                          SGMII_AN_ENABLE, bmcr);
-
-       /* Release PHYA power down state
-        * Only removing bit SGMII_PHYA_PWD isn't enough.
-        * There are cases when the SGMII_PHYA_PWD register contains 0x9 which
-        * prevents SGMII from working. The SGMII still shows link but no traffic
-        * can flow. Writing 0x0 to the PHYA_PWD register fix the issue. 0x0 was
-        * taken from a good working state of the SGMII interface.
-        * Unknown how much the QPHY needs but it is racy without a sleep.
-        * Tested on mt7622 & mt7986.
-        */
-       usleep_range(50, 100);
-       regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0);
-
-       return changed || mode_changed;
-}
-
-static void mtk_pcs_restart_an(struct phylink_pcs *pcs)
-{
-       struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs);
-
-       regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1,
-                          SGMII_AN_RESTART, SGMII_AN_RESTART);
-}
-
-static void mtk_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
-                           phy_interface_t interface, int speed, int duplex)
-{
-       struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs);
-       unsigned int sgm_mode;
-
-       if (!phylink_autoneg_inband(mode)) {
-               /* Force the speed and duplex setting */
-               if (speed == SPEED_10)
-                       sgm_mode = SGMII_SPEED_10;
-               else if (speed == SPEED_100)
-                       sgm_mode = SGMII_SPEED_100;
-               else
-                       sgm_mode = SGMII_SPEED_1000;
-
-               if (duplex != DUPLEX_FULL)
-                       sgm_mode |= SGMII_DUPLEX_HALF;
-
-               regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE,
-                                  SGMII_DUPLEX_HALF | SGMII_SPEED_MASK,
-                                  sgm_mode);
-       }
-}
-
-static const struct phylink_pcs_ops mtk_pcs_ops = {
-       .pcs_get_state = mtk_pcs_get_state,
-       .pcs_config = mtk_pcs_config,
-       .pcs_an_restart = mtk_pcs_restart_an,
-       .pcs_link_up = mtk_pcs_link_up,
-};
-
-int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3)
-{
-       struct device_node *np;
-       int i;
-
-       for (i = 0; i < MTK_MAX_DEVS; i++) {
-               np = of_parse_phandle(r, "mediatek,sgmiisys", i);
-               if (!np)
-                       break;
-
-               ss->pcs[i].ana_rgc3 = ana_rgc3;
-               ss->pcs[i].regmap = syscon_node_to_regmap(np);
-
-               ss->pcs[i].flags = 0;
-               if (of_property_read_bool(np, "mediatek,pnswap"))
-                       ss->pcs[i].flags |= MTK_SGMII_FLAG_PN_SWAP;
-
-               of_node_put(np);
-               if (IS_ERR(ss->pcs[i].regmap))
-                       return PTR_ERR(ss->pcs[i].regmap);
-
-               ss->pcs[i].pcs.ops = &mtk_pcs_ops;
-               ss->pcs[i].pcs.poll = true;
-               ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
-       }
-
-       return 0;
-}
-
-struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id)
-{
-       if (!ss->pcs[id].regmap)
-               return NULL;
-
-       return &ss->pcs[id].pcs;
-}