From nobody Sat May 18 14:25:18 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 653B8C77B7A for ; Thu, 1 Jun 2023 14:15:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233389AbjFAOPZ (ORCPT ); Thu, 1 Jun 2023 10:15:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36622 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234187AbjFAOPR (ORCPT ); Thu, 1 Jun 2023 10:15:17 -0400 Received: from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net [217.70.183.200]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3BE051A7; Thu, 1 Jun 2023 07:15:08 -0700 (PDT) X-GND-Sasl: maxime.chevallier@bootlin.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1685628906; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=CGAXWRYvf80zHfIhDzB2tu6kKP2+wfCv2aHqFygA5hI=; b=FXoW95C+Tqzworwca9UAfYyxbxSAmRkvLWDCrxm8wYO9MfFoZC4O9CwRasskE3dFXlNpX6 gF3ziMoisDW/3XRZpRu4670JSP3718amRQoR8Z3k3jiGvw17cUARrjWxG2LdLUdNCIkAgf 8+X3BLstbgLyhPmF/JIgBepnCdUdykAo78/2dSRErGwAKJENSzpq5F2UldShtGjOftR1II RZ+aKqUfoqpJcAI4oCM4NdYJvRaJCTd6sWh4mWuQMP8I4qs1oZeKFRULTD8is11syPVUEa Sd9Z2V//BVAkPsajLtUY5g3yei7YjXQHo8r8SprtTiyFMduTFdDKVrgzMM7D4Q== X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com Received: by mail.gandi.net (Postfix) with ESMTPSA id 57CB320008; Thu, 1 Jun 2023 14:15:02 +0000 (UTC) From: Maxime Chevallier To: Mark Brown , davem@davemloft.net Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, alexis.lothore@bootlin.com, thomas.petazzoni@bootlin.com, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Florian Fainelli , Heiner Kallweit , Russell King , Vladimir Oltean , Ioana Ciornei , linux-stm32@st-md-mailman.stormreply.com, linux-arm-kernel@lists.infradead.org, Maxime Coquelin , Jose Abreu , Alexandre Torgue , Giuseppe Cavallaro , Simon Horman Subject: [PATCH net-next v4 1/4] net: mdio: Introduce a regmap-based mdio driver Date: Thu, 1 Jun 2023 16:14:51 +0200 Message-Id: <20230601141454.67858-2-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230601141454.67858-1-maxime.chevallier@bootlin.com> References: <20230601141454.67858-1-maxime.chevallier@bootlin.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" There exists several examples today of devices that embed an ethernet PHY or PCS directly inside an SoC. In this situation, either the device is controlled through a vendor-specific register set, or sometimes exposes the standard 802.3 registers that are typically accessed over MDIO. As phylib and phylink are designed to use mdiodevices, this driver allows creating a virtual MDIO bus, that translates mdiodev register accesses to regmap accesses. The reason we use regmap is because there are at least 3 such devices known today, 2 of them are Altera TSE PCS's, memory-mapped, exposed with a 4-byte stride in stmmac's dwmac-socfpga variant, and a 2-byte stride in altera-tse. The other one (nxp,sja1110-base-tx-mdio) is exposed over SPI. Signed-off-by: Maxime Chevallier Reviewed-by: Simon Horman --- V3->V4 : - Clarify the KConfig description with the need for REGMAP - Put the correct #include in the new header, as per Vlad's review V2->V3 : - Introduce struct mdio_regmap_priv for priv elements instead of plain reuse of the config struct - Use ~O instead of ~0UL V1->V2 : - Use phy_mask to avoid unnecessary scanning, suggested by Andrew - Allow entirely disabling scanning, suggested by Vlad MAINTAINERS | 7 +++ drivers/net/mdio/Kconfig | 11 ++++ drivers/net/mdio/Makefile | 1 + drivers/net/mdio/mdio-regmap.c | 93 ++++++++++++++++++++++++++++++++ include/linux/mdio/mdio-regmap.h | 26 +++++++++ 5 files changed, 138 insertions(+) create mode 100644 drivers/net/mdio/mdio-regmap.c create mode 100644 include/linux/mdio/mdio-regmap.h diff --git a/MAINTAINERS b/MAINTAINERS index c904dba1733b..f68269b39e09 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12835,6 +12835,13 @@ F: Documentation/devicetree/bindings/net/ieee80215= 4/mcr20a.txt F: drivers/net/ieee802154/mcr20a.c F: drivers/net/ieee802154/mcr20a.h =20 +MDIO REGMAP DRIVER +M: Maxime Chevallier +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/mdio/mdio-regmap.c +F: include/linux/mdio/mdio-regmap.h + MEASUREMENT COMPUTING CIO-DAC IIO DRIVER M: William Breathitt Gray L: linux-iio@vger.kernel.org diff --git a/drivers/net/mdio/Kconfig b/drivers/net/mdio/Kconfig index 9ff2e6f22f3f..4a7a303be2f7 100644 --- a/drivers/net/mdio/Kconfig +++ b/drivers/net/mdio/Kconfig @@ -185,6 +185,17 @@ config MDIO_IPQ8064 This driver supports the MDIO interface found in the network interface units of the IPQ8064 SoC =20 +config MDIO_REGMAP + tristate + help + This driver allows using MDIO devices that are not sitting on a + regular MDIO bus, but still exposes the standard 802.3 register + layout. It's regmap-based so that it can be used on integrated, + memory-mapped PHYs, SPI PHYs and so on. A new virtual MDIO bus is + created, and its read/write operations are mapped to the underlying + regmap. Users willing to use this driver must explicitly select + REGMAP. + config MDIO_THUNDER tristate "ThunderX SOCs MDIO buses" depends on 64BIT diff --git a/drivers/net/mdio/Makefile b/drivers/net/mdio/Makefile index 7d4cb4c11e4e..1015f0db4531 100644 --- a/drivers/net/mdio/Makefile +++ b/drivers/net/mdio/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_MDIO_MOXART) +=3D mdio-moxart.o obj-$(CONFIG_MDIO_MSCC_MIIM) +=3D mdio-mscc-miim.o obj-$(CONFIG_MDIO_MVUSB) +=3D mdio-mvusb.o obj-$(CONFIG_MDIO_OCTEON) +=3D mdio-octeon.o +obj-$(CONFIG_MDIO_REGMAP) +=3D mdio-regmap.o obj-$(CONFIG_MDIO_SUN4I) +=3D mdio-sun4i.o obj-$(CONFIG_MDIO_THUNDER) +=3D mdio-thunder.o obj-$(CONFIG_MDIO_XGENE) +=3D mdio-xgene.o diff --git a/drivers/net/mdio/mdio-regmap.c b/drivers/net/mdio/mdio-regmap.c new file mode 100644 index 000000000000..8a742a8d6387 --- /dev/null +++ b/drivers/net/mdio/mdio-regmap.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Driver for MMIO-Mapped MDIO devices. Some IPs expose internal PHYs or P= CS + * within the MMIO-mapped area + * + * Copyright (C) 2023 Maxime Chevallier + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "mdio-regmap" + +struct mdio_regmap_priv { + struct regmap *regmap; + u8 valid_addr; +}; + +static int mdio_regmap_read_c22(struct mii_bus *bus, int addr, int regnum) +{ + struct mdio_regmap_priv *ctx =3D bus->priv; + unsigned int val; + int ret; + + if (ctx->valid_addr !=3D addr) + return -ENODEV; + + ret =3D regmap_read(ctx->regmap, regnum, &val); + if (ret < 0) + return ret; + + return val; +} + +static int mdio_regmap_write_c22(struct mii_bus *bus, int addr, int regnum, + u16 val) +{ + struct mdio_regmap_priv *ctx =3D bus->priv; + + if (ctx->valid_addr !=3D addr) + return -ENODEV; + + return regmap_write(ctx->regmap, regnum, val); +} + +struct mii_bus *devm_mdio_regmap_register(struct device *dev, + const struct mdio_regmap_config *config) +{ + struct mdio_regmap_priv *mr; + struct mii_bus *mii; + int rc; + + if (!config->parent) + return ERR_PTR(-EINVAL); + + mii =3D devm_mdiobus_alloc_size(config->parent, sizeof(*mr)); + if (!mii) + return ERR_PTR(-ENOMEM); + + mr =3D mii->priv; + mr->regmap =3D config->regmap; + mr->valid_addr =3D config->valid_addr; + + mii->name =3D DRV_NAME; + strscpy(mii->id, config->name, MII_BUS_ID_SIZE); + mii->parent =3D config->parent; + mii->read =3D mdio_regmap_read_c22; + mii->write =3D mdio_regmap_write_c22; + + if (config->autoscan) + mii->phy_mask =3D ~BIT(config->valid_addr); + else + mii->phy_mask =3D ~0; + + rc =3D devm_mdiobus_register(dev, mii); + if (rc) { + dev_err(config->parent, "Cannot register MDIO bus![%s] (%d)\n", mii->id,= rc); + return ERR_PTR(rc); + } + + return mii; +} +EXPORT_SYMBOL_GPL(devm_mdio_regmap_register); + +MODULE_DESCRIPTION("MDIO API over regmap"); +MODULE_AUTHOR("Maxime Chevallier "); +MODULE_LICENSE("GPL"); diff --git a/include/linux/mdio/mdio-regmap.h b/include/linux/mdio/mdio-reg= map.h new file mode 100644 index 000000000000..679d9069846b --- /dev/null +++ b/include/linux/mdio/mdio-regmap.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Driver for MMIO-Mapped MDIO devices. Some IPs expose internal PHYs or P= CS + * within the MMIO-mapped area + * + * Copyright (C) 2023 Maxime Chevallier + */ +#ifndef MDIO_REGMAP_H +#define MDIO_REGMAP_H + +#include + +struct device; +struct regmap; + +struct mdio_regmap_config { + struct device *parent; + struct regmap *regmap; + char name[MII_BUS_ID_SIZE]; + u8 valid_addr; + bool autoscan; +}; + +struct mii_bus *devm_mdio_regmap_register(struct device *dev, + const struct mdio_regmap_config *config); + +#endif --=20 2.40.1 From nobody Sat May 18 14:25:18 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 374AFC77B7A for ; Thu, 1 Jun 2023 14:15:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234186AbjFAOP2 (ORCPT ); Thu, 1 Jun 2023 10:15:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36598 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233330AbjFAOPT (ORCPT ); Thu, 1 Jun 2023 10:15:19 -0400 Received: from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net [217.70.183.200]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C43701BF; Thu, 1 Jun 2023 07:15:11 -0700 (PDT) X-GND-Sasl: maxime.chevallier@bootlin.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1685628910; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=FbF9YiR1UaImGOv/TekzB+7e07IepTmsR1e+tk9jk7k=; b=PgLJCyf/9Ceg6ezO92AoOw3M45jJiJpxeHT6se9mGNWfy3rdZ/7POe5sNa709xNJgM9D3L Vu0riRXXSojli6ajUMXnXhsUKuc3cfhuYodGJy2x+p9aekpxL0cznTXQ9+AJ+xMLfNR8t0 9hx1PEtVJ5yyFQeb2K/RchX4ub+yoepPHmF+k9wUsZBclbXskih6rX7b+fB+GWBihnepW4 VlCaEH6sjw4rJKftp0TS97MFzkjnsSdvagHUkRIITlo0d0aU6NtDg+7gkdwKry3TBvc2q1 zkL9VhNZNeL1fgJq9mcBeHMCp//pu4B/kwrqPmshuLHcYBOZN9XP50JL2IQOzg== X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com Received: by mail.gandi.net (Postfix) with ESMTPSA id 219A62000A; Thu, 1 Jun 2023 14:15:07 +0000 (UTC) From: Maxime Chevallier To: Mark Brown , davem@davemloft.net Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, alexis.lothore@bootlin.com, thomas.petazzoni@bootlin.com, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Florian Fainelli , Heiner Kallweit , Russell King , Vladimir Oltean , Ioana Ciornei , linux-stm32@st-md-mailman.stormreply.com, linux-arm-kernel@lists.infradead.org, Maxime Coquelin , Jose Abreu , Alexandre Torgue , Giuseppe Cavallaro , Simon Horman Subject: [PATCH net-next v4 2/4] net: ethernet: altera-tse: Convert to mdio-regmap and use PCS Lynx Date: Thu, 1 Jun 2023 16:14:52 +0200 Message-Id: <20230601141454.67858-3-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230601141454.67858-1-maxime.chevallier@bootlin.com> References: <20230601141454.67858-1-maxime.chevallier@bootlin.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The newly introduced regmap-based MDIO driver allows for an easy mapping of an mdiodevice onto the memory-mapped TSE PCS, which is actually a Lynx PCS. Convert Altera TSE to use this PCS instead of the pcs-altera-tse, which is nothing more than a memory-mapped Lynx PCS. Signed-off-by: Maxime Chevallier Reviewed-by: Simon Horman --- V3->V4 : - Use pcs_lynxcreate()/destroy() introduced by Russell - Fix the error path - Add back misplaced KConfig dependencies V2->V3 : No changes V1->V2 : No changes drivers/net/ethernet/altera/Kconfig | 2 + drivers/net/ethernet/altera/altera_tse_main.c | 57 ++++++++++++++++--- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/altera/Kconfig b/drivers/net/ethernet/alt= era/Kconfig index dd7fd41ccde5..93533ba03429 100644 --- a/drivers/net/ethernet/altera/Kconfig +++ b/drivers/net/ethernet/altera/Kconfig @@ -5,6 +5,8 @@ config ALTERA_TSE select PHYLIB select PHYLINK select PCS_ALTERA_TSE + select MDIO_REGMAP + select REGMAP_MMIO help This driver supports the Altera Triple-Speed (TSE) Ethernet MAC. =20 diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/et= hernet/altera/altera_tse_main.c index 190ff1bcd94e..d866c0f1b503 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -27,14 +27,16 @@ #include #include #include +#include #include #include #include #include #include -#include +#include #include #include +#include #include #include =20 @@ -1132,13 +1134,16 @@ static int request_and_map(struct platform_device *= pdev, const char *name, static int altera_tse_probe(struct platform_device *pdev) { const struct of_device_id *of_id =3D NULL; + struct regmap_config pcs_regmap_cfg; struct altera_tse_private *priv; + struct mdio_regmap_config mrc; struct resource *control_port; + struct regmap *pcs_regmap; struct resource *dma_res; struct resource *pcs_res; + struct mii_bus *pcs_bus; struct net_device *ndev; void __iomem *descmap; - int pcs_reg_width =3D 2; int ret =3D -ENODEV; =20 ndev =3D alloc_etherdev(sizeof(struct altera_tse_private)); @@ -1255,12 +1260,32 @@ static int altera_tse_probe(struct platform_device = *pdev) * address space, but if it's not the case, we fallback to the mdiophy0 * from the MAC's address space */ - ret =3D request_and_map(pdev, "pcs", &pcs_res, - &priv->pcs_base); + ret =3D request_and_map(pdev, "pcs", &pcs_res, &priv->pcs_base); if (ret) { + /* If we can't find a dedicated resource for the PCS, fallback + * to the internal PCS, that has a different address stride + */ priv->pcs_base =3D priv->mac_dev + tse_csroffs(mdio_phy0); - pcs_reg_width =3D 4; + pcs_regmap_cfg.reg_bits =3D 32; + /* Values are MDIO-like values, on 16 bits */ + pcs_regmap_cfg.val_bits =3D 16; + pcs_regmap_cfg.reg_shift =3D REGMAP_UPSHIFT(2); + } else { + pcs_regmap_cfg.reg_bits =3D 16; + pcs_regmap_cfg.val_bits =3D 16; + pcs_regmap_cfg.reg_shift =3D REGMAP_UPSHIFT(1); + } + + /* Create a regmap for the PCS so that it can be used by the PCS driver */ + pcs_regmap =3D devm_regmap_init_mmio(&pdev->dev, priv->pcs_base, + &pcs_regmap_cfg); + if (IS_ERR(pcs_regmap)) { + ret =3D PTR_ERR(pcs_regmap); + goto err_free_netdev; } + mrc.regmap =3D pcs_regmap; + mrc.parent =3D &pdev->dev; + mrc.valid_addr =3D 0x0; =20 /* Rx IRQ */ priv->rx_irq =3D platform_get_irq_byname(pdev, "rx_irq"); @@ -1384,7 +1409,18 @@ static int altera_tse_probe(struct platform_device *= pdev) (unsigned long) control_port->start, priv->rx_irq, priv->tx_irq); =20 - priv->pcs =3D alt_tse_pcs_create(ndev, priv->pcs_base, pcs_reg_width); + snprintf(mrc.name, MII_BUS_ID_SIZE, "%s-pcs-mii", ndev->name); + pcs_bus =3D devm_mdio_regmap_register(&pdev->dev, &mrc); + if (IS_ERR(pcs_bus)) { + ret =3D PTR_ERR(pcs_bus); + goto err_init_pcs; + } + + priv->pcs =3D lynx_pcs_create_mdiodev(pcs_bus, 0); + if (IS_ERR(priv->pcs)) { + ret =3D PTR_ERR(priv->pcs); + goto err_init_pcs; + } =20 priv->phylink_config.dev =3D &ndev->dev; priv->phylink_config.type =3D PHYLINK_NETDEV; @@ -1407,12 +1443,13 @@ static int altera_tse_probe(struct platform_device = *pdev) if (IS_ERR(priv->phylink)) { dev_err(&pdev->dev, "failed to create phylink\n"); ret =3D PTR_ERR(priv->phylink); - goto err_init_phy; + goto err_init_phylink; } =20 return 0; - -err_init_phy: +err_init_phylink: + lynx_pcs_destroy(priv->pcs); +err_init_pcs: unregister_netdev(ndev); err_register_netdev: netif_napi_del(&priv->napi); @@ -1433,6 +1470,8 @@ static int altera_tse_remove(struct platform_device *= pdev) altera_tse_mdio_destroy(ndev); unregister_netdev(ndev); phylink_destroy(priv->phylink); + lynx_pcs_destroy(priv->pcs); + free_netdev(ndev); =20 return 0; --=20 2.40.1 From nobody Sat May 18 14:25:18 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 71867C77B7A for ; Thu, 1 Jun 2023 14:15:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233917AbjFAOPd (ORCPT ); Thu, 1 Jun 2023 10:15:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36604 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234236AbjFAOPV (ORCPT ); Thu, 1 Jun 2023 10:15:21 -0400 Received: from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net [217.70.183.200]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 07C5AE4A; Thu, 1 Jun 2023 07:15:13 -0700 (PDT) X-GND-Sasl: maxime.chevallier@bootlin.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1685628912; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=bQmzoSyd6gH2ZK8jmNw/RyNrYrziAhYIV1+Fs40uSq0=; b=M0vZoj+EFRHsIzyoOZz3enU0oigRnJzLWcWFE2u+L+XmPjHtFiiqzITKdZ2MJix3ZjZGs/ ilbZ+iXSU6ZYLWMknlYbiqr8OPCvpgtiAIq3w+2cifjcglDRsd5Hm2hPstvF290zIMKV1Y VNZ1ZR79rJrzKXLZsado3e+RJBBPwHP38T7I6rHB8DoIh3PLYk24oJHGG0GIYWDEvXkxIE gN5mkBwwIH/f/h+UXTqODnY31KAt9HcPxScRzyybA1KK8jeYyBUAJwj8sxA3z+80j6gVYl RQJ46gRz3cnuyHXgTvvRD1du12LBKw3mifpnus/QyJ1w7xsDda5kXTlA2dr57w== X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com Received: by mail.gandi.net (Postfix) with ESMTPSA id 8A7932000F; Thu, 1 Jun 2023 14:15:10 +0000 (UTC) From: Maxime Chevallier To: Mark Brown , davem@davemloft.net Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, alexis.lothore@bootlin.com, thomas.petazzoni@bootlin.com, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Florian Fainelli , Heiner Kallweit , Russell King , Vladimir Oltean , Ioana Ciornei , linux-stm32@st-md-mailman.stormreply.com, linux-arm-kernel@lists.infradead.org, Maxime Coquelin , Jose Abreu , Alexandre Torgue , Giuseppe Cavallaro , Simon Horman Subject: [PATCH net-next v4 3/4] net: pcs: Drop the TSE PCS driver Date: Thu, 1 Jun 2023 16:14:53 +0200 Message-Id: <20230601141454.67858-4-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230601141454.67858-1-maxime.chevallier@bootlin.com> References: <20230601141454.67858-1-maxime.chevallier@bootlin.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Now that we can easily create a mdio-device that represents a memory-mapped device that exposes an MDIO-like register layout, we don't need the Altera TSE PCS anymore, since we can use the Lynx PCS instead. Reviewed-by: Simon Horman Signed-off-by: Maxime Chevallier --- V3->V4 : Add Simon's Reviewed-by V2->V3 : No changes V1->V2 : No changes MAINTAINERS | 7 -- drivers/net/pcs/Kconfig | 6 -- drivers/net/pcs/Makefile | 1 - drivers/net/pcs/pcs-altera-tse.c | 160 ------------------------------- include/linux/pcs-altera-tse.h | 17 ---- 5 files changed, 191 deletions(-) delete mode 100644 drivers/net/pcs/pcs-altera-tse.c delete mode 100644 include/linux/pcs-altera-tse.h diff --git a/MAINTAINERS b/MAINTAINERS index f68269b39e09..0982384e300f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -909,13 +909,6 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/altera/ =20 -ALTERA TSE PCS -M: Maxime Chevallier -L: netdev@vger.kernel.org -S: Supported -F: drivers/net/pcs/pcs-altera-tse.c -F: include/linux/pcs-altera-tse.h - ALTERA UART/JTAG UART SERIAL DRIVERS M: Tobias Klauser L: linux-serial@vger.kernel.org diff --git a/drivers/net/pcs/Kconfig b/drivers/net/pcs/Kconfig index 7c34fb7cbf7b..87cf308fc6d8 100644 --- a/drivers/net/pcs/Kconfig +++ b/drivers/net/pcs/Kconfig @@ -33,10 +33,4 @@ config PCS_RZN1_MIIC on RZ/N1 SoCs. This PCS converts MII to RMII/RGMII or can be set in pass-through mode for MII. =20 -config PCS_ALTERA_TSE - tristate - help - This module provides helper functions for the Altera Triple Speed - Ethernet SGMII PCS, that can be found on the Intel Socfpga family. - endmenu diff --git a/drivers/net/pcs/Makefile b/drivers/net/pcs/Makefile index 9b9afd6b1c22..ea662a7989b2 100644 --- a/drivers/net/pcs/Makefile +++ b/drivers/net/pcs/Makefile @@ -7,4 +7,3 @@ obj-$(CONFIG_PCS_XPCS) +=3D pcs_xpcs.o obj-$(CONFIG_PCS_LYNX) +=3D pcs-lynx.o obj-$(CONFIG_PCS_MTK_LYNXI) +=3D pcs-mtk-lynxi.o obj-$(CONFIG_PCS_RZN1_MIIC) +=3D pcs-rzn1-miic.o -obj-$(CONFIG_PCS_ALTERA_TSE) +=3D pcs-altera-tse.o diff --git a/drivers/net/pcs/pcs-altera-tse.c b/drivers/net/pcs/pcs-altera-= tse.c deleted file mode 100644 index d616749761f4..000000000000 --- a/drivers/net/pcs/pcs-altera-tse.c +++ /dev/null @@ -1,160 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2022 Bootlin - * - * Maxime Chevallier - */ - -#include -#include -#include -#include - -/* SGMII PCS register addresses - */ -#define SGMII_PCS_LINK_TIMER_0 0x12 -#define SGMII_PCS_LINK_TIMER_1 0x13 -#define SGMII_PCS_IF_MODE 0x14 -#define PCS_IF_MODE_SGMII_ENA BIT(0) -#define PCS_IF_MODE_USE_SGMII_AN BIT(1) -#define PCS_IF_MODE_SGMI_HALF_DUPLEX BIT(4) -#define PCS_IF_MODE_SGMI_PHY_AN BIT(5) -#define SGMII_PCS_SW_RESET_TIMEOUT 100 /* usecs */ - -struct altera_tse_pcs { - struct phylink_pcs pcs; - void __iomem *base; - int reg_width; -}; - -static struct altera_tse_pcs *phylink_pcs_to_tse_pcs(struct phylink_pcs *p= cs) -{ - return container_of(pcs, struct altera_tse_pcs, pcs); -} - -static u16 tse_pcs_read(struct altera_tse_pcs *tse_pcs, int regnum) -{ - if (tse_pcs->reg_width =3D=3D 4) - return readl(tse_pcs->base + regnum * 4); - else - return readw(tse_pcs->base + regnum * 2); -} - -static void tse_pcs_write(struct altera_tse_pcs *tse_pcs, int regnum, - u16 value) -{ - if (tse_pcs->reg_width =3D=3D 4) - writel(value, tse_pcs->base + regnum * 4); - else - writew(value, tse_pcs->base + regnum * 2); -} - -static int tse_pcs_reset(struct altera_tse_pcs *tse_pcs) -{ - u16 bmcr; - - /* Reset PCS block */ - bmcr =3D tse_pcs_read(tse_pcs, MII_BMCR); - bmcr |=3D BMCR_RESET; - tse_pcs_write(tse_pcs, MII_BMCR, bmcr); - - return read_poll_timeout(tse_pcs_read, bmcr, (bmcr & BMCR_RESET), - 10, SGMII_PCS_SW_RESET_TIMEOUT, 1, - tse_pcs, MII_BMCR); -} - -static int alt_tse_pcs_validate(struct phylink_pcs *pcs, - unsigned long *supported, - const struct phylink_link_state *state) -{ - if (state->interface =3D=3D PHY_INTERFACE_MODE_SGMII || - state->interface =3D=3D PHY_INTERFACE_MODE_1000BASEX) - return 1; - - return -EINVAL; -} - -static int alt_tse_pcs_config(struct phylink_pcs *pcs, unsigned int mode, - phy_interface_t interface, - const unsigned long *advertising, - bool permit_pause_to_mac) -{ - struct altera_tse_pcs *tse_pcs =3D phylink_pcs_to_tse_pcs(pcs); - u32 ctrl, if_mode; - - ctrl =3D tse_pcs_read(tse_pcs, MII_BMCR); - if_mode =3D tse_pcs_read(tse_pcs, SGMII_PCS_IF_MODE); - - /* Set link timer to 1.6ms, as per the MegaCore Function User Guide */ - tse_pcs_write(tse_pcs, SGMII_PCS_LINK_TIMER_0, 0x0D40); - tse_pcs_write(tse_pcs, SGMII_PCS_LINK_TIMER_1, 0x03); - - if (interface =3D=3D PHY_INTERFACE_MODE_SGMII) { - if_mode |=3D PCS_IF_MODE_USE_SGMII_AN | PCS_IF_MODE_SGMII_ENA; - } else if (interface =3D=3D PHY_INTERFACE_MODE_1000BASEX) { - if_mode &=3D ~(PCS_IF_MODE_USE_SGMII_AN | PCS_IF_MODE_SGMII_ENA); - } - - ctrl |=3D (BMCR_SPEED1000 | BMCR_FULLDPLX | BMCR_ANENABLE); - - tse_pcs_write(tse_pcs, MII_BMCR, ctrl); - tse_pcs_write(tse_pcs, SGMII_PCS_IF_MODE, if_mode); - - return tse_pcs_reset(tse_pcs); -} - -static void alt_tse_pcs_get_state(struct phylink_pcs *pcs, - struct phylink_link_state *state) -{ - struct altera_tse_pcs *tse_pcs =3D phylink_pcs_to_tse_pcs(pcs); - u16 bmsr, lpa; - - bmsr =3D tse_pcs_read(tse_pcs, MII_BMSR); - lpa =3D tse_pcs_read(tse_pcs, MII_LPA); - - phylink_mii_c22_pcs_decode_state(state, bmsr, lpa); -} - -static void alt_tse_pcs_an_restart(struct phylink_pcs *pcs) -{ - struct altera_tse_pcs *tse_pcs =3D phylink_pcs_to_tse_pcs(pcs); - u16 bmcr; - - bmcr =3D tse_pcs_read(tse_pcs, MII_BMCR); - bmcr |=3D BMCR_ANRESTART; - tse_pcs_write(tse_pcs, MII_BMCR, bmcr); - - /* This PCS seems to require a soft reset to re-sync the AN logic */ - tse_pcs_reset(tse_pcs); -} - -static const struct phylink_pcs_ops alt_tse_pcs_ops =3D { - .pcs_validate =3D alt_tse_pcs_validate, - .pcs_get_state =3D alt_tse_pcs_get_state, - .pcs_config =3D alt_tse_pcs_config, - .pcs_an_restart =3D alt_tse_pcs_an_restart, -}; - -struct phylink_pcs *alt_tse_pcs_create(struct net_device *ndev, - void __iomem *pcs_base, int reg_width) -{ - struct altera_tse_pcs *tse_pcs; - - if (reg_width !=3D 4 && reg_width !=3D 2) - return ERR_PTR(-EINVAL); - - tse_pcs =3D devm_kzalloc(&ndev->dev, sizeof(*tse_pcs), GFP_KERNEL); - if (!tse_pcs) - return ERR_PTR(-ENOMEM); - - tse_pcs->pcs.ops =3D &alt_tse_pcs_ops; - tse_pcs->base =3D pcs_base; - tse_pcs->reg_width =3D reg_width; - - return &tse_pcs->pcs; -} -EXPORT_SYMBOL_GPL(alt_tse_pcs_create); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Altera TSE PCS driver"); -MODULE_AUTHOR("Maxime Chevallier "); diff --git a/include/linux/pcs-altera-tse.h b/include/linux/pcs-altera-tse.h deleted file mode 100644 index 92ab9f08e835..000000000000 --- a/include/linux/pcs-altera-tse.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2022 Bootlin - * - * Maxime Chevallier - */ - -#ifndef __LINUX_PCS_ALTERA_TSE_H -#define __LINUX_PCS_ALTERA_TSE_H - -struct phylink_pcs; -struct net_device; - -struct phylink_pcs *alt_tse_pcs_create(struct net_device *ndev, - void __iomem *pcs_base, int reg_width); - -#endif /* __LINUX_PCS_ALTERA_TSE_H */ --=20 2.40.1 From nobody Sat May 18 14:25:18 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 5F96AC7EE23 for ; Thu, 1 Jun 2023 14:15:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234226AbjFAOPr (ORCPT ); Thu, 1 Jun 2023 10:15:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36744 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234209AbjFAOPa (ORCPT ); Thu, 1 Jun 2023 10:15:30 -0400 Received: from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net [217.70.183.200]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 18CC1E66; Thu, 1 Jun 2023 07:15:16 -0700 (PDT) X-GND-Sasl: maxime.chevallier@bootlin.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1685628915; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=OL7zcYJTWV/nEVLufRJVs96x/jiRqDhLoDIaAwogNMU=; b=U2OiZEab/X89NwF/hNerB+H1MUaok3GnK+ZDaq72hBHDwfQF9XgYWnQX4Schty8/zM1Qgw U0BBQwBJIiRZy4UN40bLrIyEWUtNxuSA1k4CtkWHSXyOkQqPycRdtXSEwIJj/j7a2G1lPr wdsN+YYNhTTeRJghz4jvQ98gSDJ0XEQmm/lHNgQB8LyIy0MVnTMQeiJCOFpkhn7R1YlgqI rfMEqA0bMfIwv+XPh8K9u0/3gY7wNWzOCcwcQlCkQTZy4V2LcuPvkUxI/wVD5nKWP5P8MP JvvrMQygpUnONvqJ3VKhDdrMpiTwZQzU2mTVZBxxcR4MbmjJo4eGszUDqBT4gQ== X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com X-GND-Sasl: maxime.chevallier@bootlin.com Received: by mail.gandi.net (Postfix) with ESMTPSA id E61D620008; Thu, 1 Jun 2023 14:15:12 +0000 (UTC) From: Maxime Chevallier To: Mark Brown , davem@davemloft.net Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, alexis.lothore@bootlin.com, thomas.petazzoni@bootlin.com, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Florian Fainelli , Heiner Kallweit , Russell King , Vladimir Oltean , Ioana Ciornei , linux-stm32@st-md-mailman.stormreply.com, linux-arm-kernel@lists.infradead.org, Maxime Coquelin , Jose Abreu , Alexandre Torgue , Giuseppe Cavallaro , Simon Horman Subject: [PATCH net-next v4 4/4] net: stmmac: dwmac-sogfpga: use the lynx pcs driver Date: Thu, 1 Jun 2023 16:14:54 +0200 Message-Id: <20230601141454.67858-5-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20230601141454.67858-1-maxime.chevallier@bootlin.com> References: <20230601141454.67858-1-maxime.chevallier@bootlin.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" dwmac_socfpga re-implements support for the TSE PCS, which is identical to the already existing TSE PCS, which in turn is the same as the Lynx PCS. Drop the existing TSE re-implemenation and use the Lynx PCS instead, relying on the regmap-mdio driver to translate MDIO accesses into mmio accesses. Add a lynx_pcs reference in the stmmac's internal structure, and use .mac_select_pcs() to return the relevant PCS to be used. Signed-off-by: Maxime Chevallier Reviewed-by: Simon Horman --- V3->V4 : - Use pcs_lynx_create/destroy() - Add a missing cleanup step for this PCS - rename the new PCS field from phylink_pcs to lynx_pcs, as we need to know which kind of PCS it is to call the proper cleanup helper - Add missing Kconfig dependencies V2->V3 : No changes V1->V2 : No changes drivers/net/ethernet/stmicro/stmmac/Kconfig | 3 + drivers/net/ethernet/stmicro/stmmac/Makefile | 2 +- .../ethernet/stmicro/stmmac/altr_tse_pcs.c | 257 ------------------ .../ethernet/stmicro/stmmac/altr_tse_pcs.h | 29 -- drivers/net/ethernet/stmicro/stmmac/common.h | 2 + .../ethernet/stmicro/stmmac/dwmac-socfpga.c | 91 +++++-- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 12 +- .../net/ethernet/stmicro/stmmac/stmmac_mdio.c | 3 + 8 files changed, 83 insertions(+), 316 deletions(-) delete mode 100644 drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c delete mode 100644 drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethe= rnet/stmicro/stmmac/Kconfig index 5f5a997f21f3..5583f0b055ec 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -158,6 +158,9 @@ config DWMAC_SOCFPGA default ARCH_INTEL_SOCFPGA depends on OF && (ARCH_INTEL_SOCFPGA || COMPILE_TEST) select MFD_SYSCON + select MDIO_REGMAP + select REGMAP_MMIO + select PCS_LYNX help Support for ethernet controller on Altera SOCFPGA =20 diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/eth= ernet/stmicro/stmmac/Makefile index 8738fdbb4b2d..7dd3d388068b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -35,7 +35,7 @@ obj-$(CONFIG_DWMAC_IMX8) +=3D dwmac-imx.o obj-$(CONFIG_DWMAC_TEGRA) +=3D dwmac-tegra.o obj-$(CONFIG_DWMAC_VISCONTI) +=3D dwmac-visconti.o stmmac-platform-objs:=3D stmmac_platform.o -dwmac-altr-socfpga-objs :=3D altr_tse_pcs.o dwmac-socfpga.o +dwmac-altr-socfpga-objs :=3D dwmac-socfpga.o =20 obj-$(CONFIG_STMMAC_PCI) +=3D stmmac-pci.o obj-$(CONFIG_DWMAC_INTEL) +=3D dwmac-intel.o diff --git a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c b/drivers/n= et/ethernet/stmicro/stmmac/altr_tse_pcs.c deleted file mode 100644 index 00f6d347eaf7..000000000000 --- a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c +++ /dev/null @@ -1,257 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* Copyright Altera Corporation (C) 2016. All rights reserved. - * - * Author: Tien Hock Loh - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "stmmac.h" -#include "stmmac_platform.h" -#include "altr_tse_pcs.h" - -#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0 -#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII BIT(1) -#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII BIT(2) -#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2 -#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK GENMASK(1, 0) - -#define TSE_PCS_CONTROL_AN_EN_MASK BIT(12) -#define TSE_PCS_CONTROL_REG 0x00 -#define TSE_PCS_CONTROL_RESTART_AN_MASK BIT(9) -#define TSE_PCS_CTRL_AUTONEG_SGMII 0x1140 -#define TSE_PCS_IF_MODE_REG 0x28 -#define TSE_PCS_LINK_TIMER_0_REG 0x24 -#define TSE_PCS_LINK_TIMER_1_REG 0x26 -#define TSE_PCS_SIZE 0x40 -#define TSE_PCS_STATUS_AN_COMPLETED_MASK BIT(5) -#define TSE_PCS_STATUS_LINK_MASK 0x0004 -#define TSE_PCS_STATUS_REG 0x02 -#define TSE_PCS_SGMII_SPEED_1000 BIT(3) -#define TSE_PCS_SGMII_SPEED_100 BIT(2) -#define TSE_PCS_SGMII_SPEED_10 0x0 -#define TSE_PCS_SW_RST_MASK 0x8000 -#define TSE_PCS_PARTNER_ABILITY_REG 0x0A -#define TSE_PCS_PARTNER_DUPLEX_FULL 0x1000 -#define TSE_PCS_PARTNER_DUPLEX_HALF 0x0000 -#define TSE_PCS_PARTNER_DUPLEX_MASK 0x1000 -#define TSE_PCS_PARTNER_SPEED_MASK GENMASK(11, 10) -#define TSE_PCS_PARTNER_SPEED_1000 BIT(11) -#define TSE_PCS_PARTNER_SPEED_100 BIT(10) -#define TSE_PCS_PARTNER_SPEED_10 0x0000 -#define TSE_PCS_PARTNER_SPEED_1000 BIT(11) -#define TSE_PCS_PARTNER_SPEED_100 BIT(10) -#define TSE_PCS_PARTNER_SPEED_10 0x0000 -#define TSE_PCS_SGMII_SPEED_MASK GENMASK(3, 2) -#define TSE_PCS_SGMII_LINK_TIMER_0 0x0D40 -#define TSE_PCS_SGMII_LINK_TIMER_1 0x0003 -#define TSE_PCS_SW_RESET_TIMEOUT 100 -#define TSE_PCS_USE_SGMII_AN_MASK BIT(1) -#define TSE_PCS_USE_SGMII_ENA BIT(0) -#define TSE_PCS_IF_USE_SGMII 0x03 - -#define AUTONEGO_LINK_TIMER 20 - -static int tse_pcs_reset(void __iomem *base, struct tse_pcs *pcs) -{ - int counter =3D 0; - u16 val; - - val =3D readw(base + TSE_PCS_CONTROL_REG); - val |=3D TSE_PCS_SW_RST_MASK; - writew(val, base + TSE_PCS_CONTROL_REG); - - while (counter < TSE_PCS_SW_RESET_TIMEOUT) { - val =3D readw(base + TSE_PCS_CONTROL_REG); - val &=3D TSE_PCS_SW_RST_MASK; - if (val =3D=3D 0) - break; - counter++; - udelay(1); - } - if (counter >=3D TSE_PCS_SW_RESET_TIMEOUT) { - dev_err(pcs->dev, "PCS could not get out of sw reset\n"); - return -ETIMEDOUT; - } - - return 0; -} - -int tse_pcs_init(void __iomem *base, struct tse_pcs *pcs) -{ - int ret =3D 0; - - writew(TSE_PCS_IF_USE_SGMII, base + TSE_PCS_IF_MODE_REG); - - writew(TSE_PCS_CTRL_AUTONEG_SGMII, base + TSE_PCS_CONTROL_REG); - - writew(TSE_PCS_SGMII_LINK_TIMER_0, base + TSE_PCS_LINK_TIMER_0_REG); - writew(TSE_PCS_SGMII_LINK_TIMER_1, base + TSE_PCS_LINK_TIMER_1_REG); - - ret =3D tse_pcs_reset(base, pcs); - if (ret =3D=3D 0) - writew(SGMII_ADAPTER_ENABLE, - pcs->sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); - - return ret; -} - -static void pcs_link_timer_callback(struct tse_pcs *pcs) -{ - u16 val =3D 0; - void __iomem *tse_pcs_base =3D pcs->tse_pcs_base; - void __iomem *sgmii_adapter_base =3D pcs->sgmii_adapter_base; - - val =3D readw(tse_pcs_base + TSE_PCS_STATUS_REG); - val &=3D TSE_PCS_STATUS_LINK_MASK; - - if (val !=3D 0) { - dev_dbg(pcs->dev, "Adapter: Link is established\n"); - writew(SGMII_ADAPTER_ENABLE, - sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); - } else { - mod_timer(&pcs->aneg_link_timer, jiffies + - msecs_to_jiffies(AUTONEGO_LINK_TIMER)); - } -} - -static void auto_nego_timer_callback(struct tse_pcs *pcs) -{ - u16 val =3D 0; - u16 speed =3D 0; - u16 duplex =3D 0; - void __iomem *tse_pcs_base =3D pcs->tse_pcs_base; - void __iomem *sgmii_adapter_base =3D pcs->sgmii_adapter_base; - - val =3D readw(tse_pcs_base + TSE_PCS_STATUS_REG); - val &=3D TSE_PCS_STATUS_AN_COMPLETED_MASK; - - if (val !=3D 0) { - dev_dbg(pcs->dev, "Adapter: Auto Negotiation is completed\n"); - val =3D readw(tse_pcs_base + TSE_PCS_PARTNER_ABILITY_REG); - speed =3D val & TSE_PCS_PARTNER_SPEED_MASK; - duplex =3D val & TSE_PCS_PARTNER_DUPLEX_MASK; - - if (speed =3D=3D TSE_PCS_PARTNER_SPEED_10 && - duplex =3D=3D TSE_PCS_PARTNER_DUPLEX_FULL) - dev_dbg(pcs->dev, - "Adapter: Link Partner is Up - 10/Full\n"); - else if (speed =3D=3D TSE_PCS_PARTNER_SPEED_100 && - duplex =3D=3D TSE_PCS_PARTNER_DUPLEX_FULL) - dev_dbg(pcs->dev, - "Adapter: Link Partner is Up - 100/Full\n"); - else if (speed =3D=3D TSE_PCS_PARTNER_SPEED_1000 && - duplex =3D=3D TSE_PCS_PARTNER_DUPLEX_FULL) - dev_dbg(pcs->dev, - "Adapter: Link Partner is Up - 1000/Full\n"); - else if (speed =3D=3D TSE_PCS_PARTNER_SPEED_10 && - duplex =3D=3D TSE_PCS_PARTNER_DUPLEX_HALF) - dev_err(pcs->dev, - "Adapter does not support Half Duplex\n"); - else if (speed =3D=3D TSE_PCS_PARTNER_SPEED_100 && - duplex =3D=3D TSE_PCS_PARTNER_DUPLEX_HALF) - dev_err(pcs->dev, - "Adapter does not support Half Duplex\n"); - else if (speed =3D=3D TSE_PCS_PARTNER_SPEED_1000 && - duplex =3D=3D TSE_PCS_PARTNER_DUPLEX_HALF) - dev_err(pcs->dev, - "Adapter does not support Half Duplex\n"); - else - dev_err(pcs->dev, - "Adapter: Invalid Partner Speed and Duplex\n"); - - if (duplex =3D=3D TSE_PCS_PARTNER_DUPLEX_FULL && - (speed =3D=3D TSE_PCS_PARTNER_SPEED_10 || - speed =3D=3D TSE_PCS_PARTNER_SPEED_100 || - speed =3D=3D TSE_PCS_PARTNER_SPEED_1000)) - writew(SGMII_ADAPTER_ENABLE, - sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); - } else { - val =3D readw(tse_pcs_base + TSE_PCS_CONTROL_REG); - val |=3D TSE_PCS_CONTROL_RESTART_AN_MASK; - writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG); - - tse_pcs_reset(tse_pcs_base, pcs); - mod_timer(&pcs->aneg_link_timer, jiffies + - msecs_to_jiffies(AUTONEGO_LINK_TIMER)); - } -} - -static void aneg_link_timer_callback(struct timer_list *t) -{ - struct tse_pcs *pcs =3D from_timer(pcs, t, aneg_link_timer); - - if (pcs->autoneg =3D=3D AUTONEG_ENABLE) - auto_nego_timer_callback(pcs); - else if (pcs->autoneg =3D=3D AUTONEG_DISABLE) - pcs_link_timer_callback(pcs); -} - -void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev, - unsigned int speed) -{ - void __iomem *tse_pcs_base =3D pcs->tse_pcs_base; - u32 val; - - pcs->autoneg =3D phy_dev->autoneg; - - if (phy_dev->autoneg =3D=3D AUTONEG_ENABLE) { - val =3D readw(tse_pcs_base + TSE_PCS_CONTROL_REG); - val |=3D TSE_PCS_CONTROL_AN_EN_MASK; - writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG); - - val =3D readw(tse_pcs_base + TSE_PCS_IF_MODE_REG); - val |=3D TSE_PCS_USE_SGMII_AN_MASK; - writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG); - - val =3D readw(tse_pcs_base + TSE_PCS_CONTROL_REG); - val |=3D TSE_PCS_CONTROL_RESTART_AN_MASK; - - tse_pcs_reset(tse_pcs_base, pcs); - - timer_setup(&pcs->aneg_link_timer, aneg_link_timer_callback, - 0); - mod_timer(&pcs->aneg_link_timer, jiffies + - msecs_to_jiffies(AUTONEGO_LINK_TIMER)); - } else if (phy_dev->autoneg =3D=3D AUTONEG_DISABLE) { - val =3D readw(tse_pcs_base + TSE_PCS_CONTROL_REG); - val &=3D ~TSE_PCS_CONTROL_AN_EN_MASK; - writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG); - - val =3D readw(tse_pcs_base + TSE_PCS_IF_MODE_REG); - val &=3D ~TSE_PCS_USE_SGMII_AN_MASK; - writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG); - - val =3D readw(tse_pcs_base + TSE_PCS_IF_MODE_REG); - val &=3D ~TSE_PCS_SGMII_SPEED_MASK; - - switch (speed) { - case 1000: - val |=3D TSE_PCS_SGMII_SPEED_1000; - break; - case 100: - val |=3D TSE_PCS_SGMII_SPEED_100; - break; - case 10: - val |=3D TSE_PCS_SGMII_SPEED_10; - break; - default: - return; - } - writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG); - - tse_pcs_reset(tse_pcs_base, pcs); - - timer_setup(&pcs->aneg_link_timer, aneg_link_timer_callback, - 0); - mod_timer(&pcs->aneg_link_timer, jiffies + - msecs_to_jiffies(AUTONEGO_LINK_TIMER)); - } -} diff --git a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h b/drivers/n= et/ethernet/stmicro/stmmac/altr_tse_pcs.h deleted file mode 100644 index 694ac25ef426..000000000000 --- a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright Altera Corporation (C) 2016. All rights reserved. - * - * Author: Tien Hock Loh - */ - -#ifndef __TSE_PCS_H__ -#define __TSE_PCS_H__ - -#include -#include - -#define SGMII_ADAPTER_CTRL_REG 0x00 -#define SGMII_ADAPTER_ENABLE 0x0000 -#define SGMII_ADAPTER_DISABLE 0x0001 - -struct tse_pcs { - struct device *dev; - void __iomem *tse_pcs_base; - void __iomem *sgmii_adapter_base; - struct timer_list aneg_link_timer; - int autoneg; -}; - -int tse_pcs_init(void __iomem *base, struct tse_pcs *pcs); -void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev, - unsigned int speed); - -#endif /* __TSE_PCS_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/eth= ernet/stmicro/stmmac/common.h index 4ad692c4116c..52c5ec553276 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #if IS_ENABLED(CONFIG_VLAN_8021Q) #define STMMAC_VLAN_TAG_USED @@ -519,6 +520,7 @@ struct mac_device_info { const struct stmmac_tc_ops *tc; const struct stmmac_mmc_ops *mmc; struct dw_xpcs *xpcs; + struct phylink_pcs *lynx_pcs; /* Lynx external PCS */ struct mii_regs mii; /* MII register Addresses */ struct mac_link link; void __iomem *pcsr; /* vpointer to device CSRs */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/= net/ethernet/stmicro/stmmac/dwmac-socfpga.c index 6ee050300b31..e399fccbafe5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -10,14 +10,13 @@ #include #include #include +#include #include #include =20 #include "stmmac.h" #include "stmmac_platform.h" =20 -#include "altr_tse_pcs.h" - #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2 @@ -37,6 +36,10 @@ #define EMAC_SPLITTER_CTRL_SPEED_100 0x3 #define EMAC_SPLITTER_CTRL_SPEED_1000 0x0 =20 +#define SGMII_ADAPTER_CTRL_REG 0x00 +#define SGMII_ADAPTER_ENABLE 0x0000 +#define SGMII_ADAPTER_DISABLE 0x0001 + struct socfpga_dwmac; struct socfpga_dwmac_ops { int (*set_phy_mode)(struct socfpga_dwmac *dwmac_priv); @@ -50,16 +53,18 @@ struct socfpga_dwmac { struct reset_control *stmmac_rst; struct reset_control *stmmac_ocp_rst; void __iomem *splitter_base; + void __iomem *tse_pcs_base; + void __iomem *sgmii_adapter_base; bool f2h_ptp_ref_clk; - struct tse_pcs pcs; const struct socfpga_dwmac_ops *ops; + struct mdio_device *pcs_mdiodev; }; =20 static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed) { struct socfpga_dwmac *dwmac =3D (struct socfpga_dwmac *)priv; void __iomem *splitter_base =3D dwmac->splitter_base; - void __iomem *sgmii_adapter_base =3D dwmac->pcs.sgmii_adapter_base; + void __iomem *sgmii_adapter_base =3D dwmac->sgmii_adapter_base; struct device *dev =3D dwmac->dev; struct net_device *ndev =3D dev_get_drvdata(dev); struct phy_device *phy_dev =3D ndev->phydev; @@ -89,11 +94,9 @@ static void socfpga_dwmac_fix_mac_speed(void *priv, unsi= gned int speed) writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG); } =20 - if (phy_dev && sgmii_adapter_base) { + if (phy_dev && sgmii_adapter_base) writew(SGMII_ADAPTER_ENABLE, sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); - tse_pcs_fix_mac_speed(&dwmac->pcs, phy_dev, speed); - } } =20 static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct de= vice *dev) @@ -183,11 +186,11 @@ static int socfpga_dwmac_parse_data(struct socfpga_dw= mac *dwmac, struct device * goto err_node_put; } =20 - dwmac->pcs.sgmii_adapter_base =3D + dwmac->sgmii_adapter_base =3D devm_ioremap_resource(dev, &res_sgmii_adapter); =20 - if (IS_ERR(dwmac->pcs.sgmii_adapter_base)) { - ret =3D PTR_ERR(dwmac->pcs.sgmii_adapter_base); + if (IS_ERR(dwmac->sgmii_adapter_base)) { + ret =3D PTR_ERR(dwmac->sgmii_adapter_base); goto err_node_put; } } @@ -205,11 +208,11 @@ static int socfpga_dwmac_parse_data(struct socfpga_dw= mac *dwmac, struct device * goto err_node_put; } =20 - dwmac->pcs.tse_pcs_base =3D + dwmac->tse_pcs_base =3D devm_ioremap_resource(dev, &res_tse_pcs); =20 - if (IS_ERR(dwmac->pcs.tse_pcs_base)) { - ret =3D PTR_ERR(dwmac->pcs.tse_pcs_base); + if (IS_ERR(dwmac->tse_pcs_base)) { + ret =3D PTR_ERR(dwmac->tse_pcs_base); goto err_node_put; } } @@ -235,6 +238,13 @@ static int socfpga_get_plat_phymode(struct socfpga_dwm= ac *dwmac) return priv->plat->interface; } =20 +static void socfpga_sgmii_config(struct socfpga_dwmac *dwmac, bool enable) +{ + u16 val =3D enable ? SGMII_ADAPTER_ENABLE : SGMII_ADAPTER_DISABLE; + + writew(val, dwmac->sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); +} + static int socfpga_set_phy_mode_common(int phymode, u32 *val) { switch (phymode) { @@ -310,12 +320,8 @@ static int socfpga_gen5_set_phy_mode(struct socfpga_dw= mac *dwmac) */ reset_control_deassert(dwmac->stmmac_ocp_rst); reset_control_deassert(dwmac->stmmac_rst); - if (phymode =3D=3D PHY_INTERFACE_MODE_SGMII) { - if (tse_pcs_init(dwmac->pcs.tse_pcs_base, &dwmac->pcs) !=3D 0) { - dev_err(dwmac->dev, "Unable to initialize TSE PCS"); - return -EINVAL; - } - } + if (phymode =3D=3D PHY_INTERFACE_MODE_SGMII) + socfpga_sgmii_config(dwmac, true); =20 return 0; } @@ -367,12 +373,8 @@ static int socfpga_gen10_set_phy_mode(struct socfpga_d= wmac *dwmac) */ reset_control_deassert(dwmac->stmmac_ocp_rst); reset_control_deassert(dwmac->stmmac_rst); - if (phymode =3D=3D PHY_INTERFACE_MODE_SGMII) { - if (tse_pcs_init(dwmac->pcs.tse_pcs_base, &dwmac->pcs) !=3D 0) { - dev_err(dwmac->dev, "Unable to initialize TSE PCS"); - return -EINVAL; - } - } + if (phymode =3D=3D PHY_INTERFACE_MODE_SGMII) + socfpga_sgmii_config(dwmac, true); return 0; } =20 @@ -386,6 +388,7 @@ static int socfpga_dwmac_probe(struct platform_device *= pdev) struct net_device *ndev; struct stmmac_priv *stpriv; const struct socfpga_dwmac_ops *ops; + struct regmap_config pcs_regmap_cfg; =20 ops =3D device_get_match_data(&pdev->dev); if (!ops) { @@ -443,6 +446,44 @@ static int socfpga_dwmac_probe(struct platform_device = *pdev) if (ret) goto err_dvr_remove; =20 + memset(&pcs_regmap_cfg, 0, sizeof(pcs_regmap_cfg)); + pcs_regmap_cfg.reg_bits =3D 16; + pcs_regmap_cfg.val_bits =3D 16; + pcs_regmap_cfg.reg_shift =3D REGMAP_UPSHIFT(1); + + /* Create a regmap for the PCS so that it can be used by the PCS driver, + * if we have such a PCS + */ + if (dwmac->tse_pcs_base) { + struct mdio_regmap_config mrc; + struct regmap *pcs_regmap; + struct mii_bus *pcs_bus; + + pcs_regmap =3D devm_regmap_init_mmio(&pdev->dev, dwmac->tse_pcs_base, + &pcs_regmap_cfg); + if (IS_ERR(pcs_regmap)) { + ret =3D PTR_ERR(pcs_regmap); + goto err_dvr_remove; + } + + mrc.regmap =3D pcs_regmap; + mrc.parent =3D &pdev->dev; + mrc.valid_addr =3D 0x0; + + snprintf(mrc.name, MII_BUS_ID_SIZE, "%s-pcs-mii", ndev->name); + pcs_bus =3D devm_mdio_regmap_register(&pdev->dev, &mrc); + if (IS_ERR(pcs_bus)) { + ret =3D PTR_ERR(pcs_bus); + goto err_dvr_remove; + } + + stpriv->hw->lynx_pcs =3D lynx_pcs_create_mdiodev(pcs_bus, 0); + if (IS_ERR(stpriv->hw->lynx_pcs)) { + ret =3D PTR_ERR(stpriv->hw->lynx_pcs); + goto err_dvr_remove; + } + } + return 0; =20 err_dvr_remove: diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/ne= t/ethernet/stmicro/stmmac/stmmac_main.c index 0fca81507a77..cff76e215f7d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -937,10 +937,13 @@ static struct phylink_pcs *stmmac_mac_select_pcs(stru= ct phylink_config *config, { struct stmmac_priv *priv =3D netdev_priv(to_net_dev(config->dev)); =20 - if (!priv->hw->xpcs) - return NULL; + if (priv->hw->xpcs) + return &priv->hw->xpcs->pcs; + + if (priv->hw->lynx_pcs) + return priv->hw->lynx_pcs; =20 - return &priv->hw->xpcs->pcs; + return NULL; } =20 static void stmmac_mac_config(struct phylink_config *config, unsigned int = mode, @@ -3813,7 +3816,8 @@ static int __stmmac_open(struct net_device *dev, if (priv->hw->pcs !=3D STMMAC_PCS_TBI && priv->hw->pcs !=3D STMMAC_PCS_RTBI && (!priv->hw->xpcs || - xpcs_get_an_mode(priv->hw->xpcs, mode) !=3D DW_AN_C73)) { + xpcs_get_an_mode(priv->hw->xpcs, mode) !=3D DW_AN_C73) && + !priv->hw->lynx_pcs) { ret =3D stmmac_init_phy(dev); if (ret) { netdev_err(priv->dev, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/ne= t/ethernet/stmicro/stmmac/stmmac_mdio.c index 3db1cb0fd160..c784a6731f08 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -665,6 +665,9 @@ int stmmac_mdio_unregister(struct net_device *ndev) if (priv->hw->xpcs) xpcs_destroy(priv->hw->xpcs); =20 + if (priv->hw->lynx_pcs) + lynx_pcs_destroy(priv->hw->lynx_pcs); + mdiobus_unregister(priv->mii); priv->mii->priv =3D NULL; mdiobus_free(priv->mii); --=20 2.40.1