summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2023-06-05 09:56:36 +0100
committerDavid S. Miller <davem@davemloft.net>2023-06-05 09:56:36 +0100
commitf91e32dea63930ef9dfd3382d757865d9455cfb1 (patch)
tree9d7b1faed940ea977f8722d196af8e26b67e97d4
parentf69de8aa4752adae750892c71711a5b806ec0dff (diff)
parent5d1f3fe7d2d54d04b44aa5b9b62b305fdcf653ec (diff)
Merge branch 'regmap-TSE-PCS'
Maxime Chevallier says: ==================== net: add a regmap-based mdio driver and drop TSE PCS This is the V4 of a series that follows-up on the work [1] aiming to drop the altera TSE PCS driver, as it turns out to be a version of the Lynx PCS exposed as a memory-mapped block, instead of living on an MDIO bus. One step of this removal involved creating a regmap-based mdio driver that translates MDIO accesses into the actual underlying bus that exposes the register. The register layout must of course match the standard MDIO layout, but we can now account for differences in stride with recent work on the regmap subsystem [2]. Sorry for repeating this, but I didn't hear anything on this matter in previous iterations, Mark, Net maintainers, this series depends on the patch e12ff2876493 that was recently merged into the regmap tree [3]. For this series to be usable in net-next, this patch must be applied beforehand. Should Mark create a tag that would then be merged into net-next ? Or should we just wait for the next release to merge this into net-next ? This series introduces a new MDIO driver, and uses it to convert Altera TSE from the actual TSE PCS driver to Lynx PCS. Since it turns out dwmac_socfpga also uses a TSE PCS block, port that driver to Lynx as well. Changes in V4 : - Use new pcs_lynx_create/destroy helpers added by Russell - Rework the cleanup sequence to avoid leaking data - Rework a bit KConfig to properly select dependencies - Fix a few hiccups with misplaced hunks in 2 commits Changes in V3 : - Use a dedicated struct for the mii bus's priv data, to avoid duplicating the whole struct mdio_regmap_config, from which 2 fields only are necessary after init, as suggested by Russell - Use ~0 instead of ~0UL for the no-scan bitmask, following Simon's review. Changes in V2 : - Use phy_mask to avoid unnecessarily scanning the whole mdio bus - Go one step further and completely disable scanning if users set the .autoscan flag to false, in case the mdiodevice isn't an actual PHY (a PCS for example). ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--MAINTAINERS14
-rw-r--r--drivers/net/ethernet/altera/Kconfig2
-rw-r--r--drivers/net/ethernet/altera/altera_tse_main.c57
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c257
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h29
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c91
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c12
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c3
-rw-r--r--drivers/net/mdio/Kconfig11
-rw-r--r--drivers/net/mdio/Makefile1
-rw-r--r--drivers/net/mdio/mdio-regmap.c93
-rw-r--r--drivers/net/pcs/Kconfig6
-rw-r--r--drivers/net/pcs/Makefile1
-rw-r--r--drivers/net/pcs/pcs-altera-tse.c160
-rw-r--r--include/linux/mdio/mdio-regmap.h26
-rw-r--r--include/linux/pcs-altera-tse.h17
19 files changed, 271 insertions, 516 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 288d9a5edb9d..081eb65ef865 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -909,13 +909,6 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/altera/
-ALTERA TSE PCS
-M: Maxime Chevallier <maxime.chevallier@bootlin.com>
-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 <tklauser@distanz.ch>
L: linux-serial@vger.kernel.org
@@ -12844,6 +12837,13 @@ F: Documentation/devicetree/bindings/net/ieee802154/mcr20a.txt
F: drivers/net/ieee802154/mcr20a.c
F: drivers/net/ieee802154/mcr20a.h
+MDIO REGMAP DRIVER
+M: Maxime Chevallier <maxime.chevallier@bootlin.com>
+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 <william.gray@linaro.org>
L: linux-iio@vger.kernel.org
diff --git a/drivers/net/ethernet/altera/Kconfig b/drivers/net/ethernet/altera/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.
diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/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 <linux/kernel.h>
#include <linux/module.h>
#include <linux/mii.h>
+#include <linux/mdio/mdio-regmap.h>
#include <linux/netdevice.h>
#include <linux/of_device.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/of_platform.h>
-#include <linux/pcs-altera-tse.h>
+#include <linux/pcs-lynx.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/skbuff.h>
#include <asm/cacheflush.h>
@@ -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 = 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 = 2;
int ret = -ENODEV;
ndev = 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 = request_and_map(pdev, "pcs", &pcs_res,
- &priv->pcs_base);
+ ret = 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 = priv->mac_dev + tse_csroffs(mdio_phy0);
- pcs_reg_width = 4;
+ pcs_regmap_cfg.reg_bits = 32;
+ /* Values are MDIO-like values, on 16 bits */
+ pcs_regmap_cfg.val_bits = 16;
+ pcs_regmap_cfg.reg_shift = REGMAP_UPSHIFT(2);
+ } else {
+ pcs_regmap_cfg.reg_bits = 16;
+ pcs_regmap_cfg.val_bits = 16;
+ pcs_regmap_cfg.reg_shift = REGMAP_UPSHIFT(1);
+ }
+
+ /* Create a regmap for the PCS so that it can be used by the PCS driver */
+ pcs_regmap = devm_regmap_init_mmio(&pdev->dev, priv->pcs_base,
+ &pcs_regmap_cfg);
+ if (IS_ERR(pcs_regmap)) {
+ ret = PTR_ERR(pcs_regmap);
+ goto err_free_netdev;
}
+ mrc.regmap = pcs_regmap;
+ mrc.parent = &pdev->dev;
+ mrc.valid_addr = 0x0;
/* Rx IRQ */
priv->rx_irq = 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);
- priv->pcs = 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 = devm_mdio_regmap_register(&pdev->dev, &mrc);
+ if (IS_ERR(pcs_bus)) {
+ ret = PTR_ERR(pcs_bus);
+ goto err_init_pcs;
+ }
+
+ priv->pcs = lynx_pcs_create_mdiodev(pcs_bus, 0);
+ if (IS_ERR(priv->pcs)) {
+ ret = PTR_ERR(priv->pcs);
+ goto err_init_pcs;
+ }
priv->phylink_config.dev = &ndev->dev;
priv->phylink_config.type = 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 = PTR_ERR(priv->phylink);
- goto err_init_phy;
+ goto err_init_phylink;
}
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);
return 0;
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/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
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/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) += dwmac-imx.o
obj-$(CONFIG_DWMAC_TEGRA) += dwmac-tegra.o
obj-$(CONFIG_DWMAC_VISCONTI) += dwmac-visconti.o
stmmac-platform-objs:= stmmac_platform.o
-dwmac-altr-socfpga-objs := altr_tse_pcs.o dwmac-socfpga.o
+dwmac-altr-socfpga-objs := dwmac-socfpga.o
obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o
obj-$(CONFIG_DWMAC_INTEL) += dwmac-intel.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c b/drivers/net/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 <thloh@altera.com>
- */
-
-#include <linux/mfd/syscon.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_net.h>
-#include <linux/phy.h>
-#include <linux/regmap.h>
-#include <linux/reset.h>
-#include <linux/stmmac.h>
-
-#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 = 0;
- u16 val;
-
- val = readw(base + TSE_PCS_CONTROL_REG);
- val |= TSE_PCS_SW_RST_MASK;
- writew(val, base + TSE_PCS_CONTROL_REG);
-
- while (counter < TSE_PCS_SW_RESET_TIMEOUT) {
- val = readw(base + TSE_PCS_CONTROL_REG);
- val &= TSE_PCS_SW_RST_MASK;
- if (val == 0)
- break;
- counter++;
- udelay(1);
- }
- if (counter >= 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 = 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 = tse_pcs_reset(base, pcs);
- if (ret == 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 = 0;
- void __iomem *tse_pcs_base = pcs->tse_pcs_base;
- void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
-
- val = readw(tse_pcs_base + TSE_PCS_STATUS_REG);
- val &= TSE_PCS_STATUS_LINK_MASK;
-
- if (val != 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 = 0;
- u16 speed = 0;
- u16 duplex = 0;
- void __iomem *tse_pcs_base = pcs->tse_pcs_base;
- void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
-
- val = readw(tse_pcs_base + TSE_PCS_STATUS_REG);
- val &= TSE_PCS_STATUS_AN_COMPLETED_MASK;
-
- if (val != 0) {
- dev_dbg(pcs->dev, "Adapter: Auto Negotiation is completed\n");
- val = readw(tse_pcs_base + TSE_PCS_PARTNER_ABILITY_REG);
- speed = val & TSE_PCS_PARTNER_SPEED_MASK;
- duplex = val & TSE_PCS_PARTNER_DUPLEX_MASK;
-
- if (speed == TSE_PCS_PARTNER_SPEED_10 &&
- duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
- dev_dbg(pcs->dev,
- "Adapter: Link Partner is Up - 10/Full\n");
- else if (speed == TSE_PCS_PARTNER_SPEED_100 &&
- duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
- dev_dbg(pcs->dev,
- "Adapter: Link Partner is Up - 100/Full\n");
- else if (speed == TSE_PCS_PARTNER_SPEED_1000 &&
- duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
- dev_dbg(pcs->dev,
- "Adapter: Link Partner is Up - 1000/Full\n");
- else if (speed == TSE_PCS_PARTNER_SPEED_10 &&
- duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
- dev_err(pcs->dev,
- "Adapter does not support Half Duplex\n");
- else if (speed == TSE_PCS_PARTNER_SPEED_100 &&
- duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
- dev_err(pcs->dev,
- "Adapter does not support Half Duplex\n");
- else if (speed == TSE_PCS_PARTNER_SPEED_1000 &&
- duplex == 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 == TSE_PCS_PARTNER_DUPLEX_FULL &&
- (speed == TSE_PCS_PARTNER_SPEED_10 ||
- speed == TSE_PCS_PARTNER_SPEED_100 ||
- speed == TSE_PCS_PARTNER_SPEED_1000))
- writew(SGMII_ADAPTER_ENABLE,
- sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
- } else {
- val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
- val |= 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 = from_timer(pcs, t, aneg_link_timer);
-
- if (pcs->autoneg == AUTONEG_ENABLE)
- auto_nego_timer_callback(pcs);
- else if (pcs->autoneg == 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 = pcs->tse_pcs_base;
- u32 val;
-
- pcs->autoneg = phy_dev->autoneg;
-
- if (phy_dev->autoneg == AUTONEG_ENABLE) {
- val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
- val |= TSE_PCS_CONTROL_AN_EN_MASK;
- writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
-
- val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
- val |= TSE_PCS_USE_SGMII_AN_MASK;
- writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
-
- val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
- val |= 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 == AUTONEG_DISABLE) {
- val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
- val &= ~TSE_PCS_CONTROL_AN_EN_MASK;
- writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
-
- val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
- val &= ~TSE_PCS_USE_SGMII_AN_MASK;
- writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
-
- val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
- val &= ~TSE_PCS_SGMII_SPEED_MASK;
-
- switch (speed) {
- case 1000:
- val |= TSE_PCS_SGMII_SPEED_1000;
- break;
- case 100:
- val |= TSE_PCS_SGMII_SPEED_100;
- break;
- case 10:
- val |= 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/net/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 <thloh@altera.com>
- */
-
-#ifndef __TSE_PCS_H__
-#define __TSE_PCS_H__
-
-#include <linux/phy.h>
-#include <linux/timer.h>
-
-#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/ethernet/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 <linux/stmmac.h>
#include <linux/phy.h>
#include <linux/pcs/pcs-xpcs.h>
+#include <linux/pcs-lynx.h>
#include <linux/module.h>
#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 <linux/of_net.h>
#include <linux/phy.h>
#include <linux/regmap.h>
+#include <linux/mdio/mdio-regmap.h>
#include <linux/reset.h>
#include <linux/stmmac.h>
#include "stmmac.h"
#include "stmmac_platform.h"
-#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
+#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;
};
static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed)
{
struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv;
void __iomem *splitter_base = dwmac->splitter_base;
- void __iomem *sgmii_adapter_base = dwmac->pcs.sgmii_adapter_base;
+ void __iomem *sgmii_adapter_base = dwmac->sgmii_adapter_base;
struct device *dev = dwmac->dev;
struct net_device *ndev = dev_get_drvdata(dev);
struct phy_device *phy_dev = ndev->phydev;
@@ -89,11 +94,9 @@ static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed)
writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG);
}
- 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);
- }
}
static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev)
@@ -183,11 +186,11 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *
goto err_node_put;
}
- dwmac->pcs.sgmii_adapter_base =
+ dwmac->sgmii_adapter_base =
devm_ioremap_resource(dev, &res_sgmii_adapter);
- if (IS_ERR(dwmac->pcs.sgmii_adapter_base)) {
- ret = PTR_ERR(dwmac->pcs.sgmii_adapter_base);
+ if (IS_ERR(dwmac->sgmii_adapter_base)) {
+ ret = PTR_ERR(dwmac->sgmii_adapter_base);
goto err_node_put;
}
}
@@ -205,11 +208,11 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *
goto err_node_put;
}
- dwmac->pcs.tse_pcs_base =
+ dwmac->tse_pcs_base =
devm_ioremap_resource(dev, &res_tse_pcs);
- if (IS_ERR(dwmac->pcs.tse_pcs_base)) {
- ret = PTR_ERR(dwmac->pcs.tse_pcs_base);
+ if (IS_ERR(dwmac->tse_pcs_base)) {
+ ret = PTR_ERR(dwmac->tse_pcs_base);
goto err_node_put;
}
}
@@ -235,6 +238,13 @@ static int socfpga_get_plat_phymode(struct socfpga_dwmac *dwmac)
return priv->plat->interface;
}
+static void socfpga_sgmii_config(struct socfpga_dwmac *dwmac, bool enable)
+{
+ u16 val = 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_dwmac *dwmac)
*/
reset_control_deassert(dwmac->stmmac_ocp_rst);
reset_control_deassert(dwmac->stmmac_rst);
- if (phymode == PHY_INTERFACE_MODE_SGMII) {
- if (tse_pcs_init(dwmac->pcs.tse_pcs_base, &dwmac->pcs) != 0) {
- dev_err(dwmac->dev, "Unable to initialize TSE PCS");
- return -EINVAL;
- }
- }
+ if (phymode == PHY_INTERFACE_MODE_SGMII)
+ socfpga_sgmii_config(dwmac, true);
return 0;
}
@@ -367,12 +373,8 @@ static int socfpga_gen10_set_phy_mode(struct socfpga_dwmac *dwmac)
*/
reset_control_deassert(dwmac->stmmac_ocp_rst);
reset_control_deassert(dwmac->stmmac_rst);
- if (phymode == PHY_INTERFACE_MODE_SGMII) {
- if (tse_pcs_init(dwmac->pcs.tse_pcs_base, &dwmac->pcs) != 0) {
- dev_err(dwmac->dev, "Unable to initialize TSE PCS");
- return -EINVAL;
- }
- }
+ if (phymode == PHY_INTERFACE_MODE_SGMII)
+ socfpga_sgmii_config(dwmac, true);
return 0;
}
@@ -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;
ops = 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;
+ memset(&pcs_regmap_cfg, 0, sizeof(pcs_regmap_cfg));
+ pcs_regmap_cfg.reg_bits = 16;
+ pcs_regmap_cfg.val_bits = 16;
+ pcs_regmap_cfg.reg_shift = 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 = devm_regmap_init_mmio(&pdev->dev, dwmac->tse_pcs_base,
+ &pcs_regmap_cfg);
+ if (IS_ERR(pcs_regmap)) {
+ ret = PTR_ERR(pcs_regmap);
+ goto err_dvr_remove;
+ }
+
+ mrc.regmap = pcs_regmap;
+ mrc.parent = &pdev->dev;
+ mrc.valid_addr = 0x0;
+
+ snprintf(mrc.name, MII_BUS_ID_SIZE, "%s-pcs-mii", ndev->name);
+ pcs_bus = devm_mdio_regmap_register(&pdev->dev, &mrc);
+ if (IS_ERR(pcs_bus)) {
+ ret = PTR_ERR(pcs_bus);
+ goto err_dvr_remove;
+ }
+
+ stpriv->hw->lynx_pcs = lynx_pcs_create_mdiodev(pcs_bus, 0);
+ if (IS_ERR(stpriv->hw->lynx_pcs)) {
+ ret = PTR_ERR(stpriv->hw->lynx_pcs);
+ goto err_dvr_remove;
+ }
+ }
+
return 0;
err_dvr_remove:
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 52cab9de05f2..fa07b0d50b46 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(struct phylink_config *config,
{
struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
- 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;
- return &priv->hw->xpcs->pcs;
+ return NULL;
}
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 != STMMAC_PCS_TBI &&
priv->hw->pcs != STMMAC_PCS_RTBI &&
(!priv->hw->xpcs ||
- xpcs_get_an_mode(priv->hw->xpcs, mode) != DW_AN_C73)) {
+ xpcs_get_an_mode(priv->hw->xpcs, mode) != DW_AN_C73) &&
+ !priv->hw->lynx_pcs) {
ret = stmmac_init_phy(dev);
if (ret) {
netdev_err(priv->dev,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/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);
+ if (priv->hw->lynx_pcs)
+ lynx_pcs_destroy(priv->hw->lynx_pcs);
+
mdiobus_unregister(priv->mii);
priv->mii->priv = NULL;
mdiobus_free(priv->mii);
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
+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) += mdio-moxart.o
obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.o
obj-$(CONFIG_MDIO_MVUSB) += mdio-mvusb.o
obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
+obj-$(CONFIG_MDIO_REGMAP) += mdio-regmap.o
obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o
obj-$(CONFIG_MDIO_THUNDER) += mdio-thunder.o
obj-$(CONFIG_MDIO_XGENE) += 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 PCS
+ * within the MMIO-mapped area
+ *
+ * Copyright (C) 2023 Maxime Chevallier <maxime.chevallier@bootlin.com>
+ */
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/mdio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_mdio.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mdio/mdio-regmap.h>
+
+#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 = bus->priv;
+ unsigned int val;
+ int ret;
+
+ if (ctx->valid_addr != addr)
+ return -ENODEV;
+
+ ret = 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 = bus->priv;
+
+ if (ctx->valid_addr != 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 = devm_mdiobus_alloc_size(config->parent, sizeof(*mr));
+ if (!mii)
+ return ERR_PTR(-ENOMEM);
+
+ mr = mii->priv;
+ mr->regmap = config->regmap;
+ mr->valid_addr = config->valid_addr;
+
+ mii->name = DRV_NAME;
+ strscpy(mii->id, config->name, MII_BUS_ID_SIZE);
+ mii->parent = config->parent;
+ mii->read = mdio_regmap_read_c22;
+ mii->write = mdio_regmap_write_c22;
+
+ if (config->autoscan)
+ mii->phy_mask = ~BIT(config->valid_addr);
+ else
+ mii->phy_mask = ~0;
+
+ rc = 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 <maxime.chevallier@bootlin.com>");
+MODULE_LICENSE("GPL");
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.
-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) += pcs_xpcs.o
obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o
obj-$(CONFIG_PCS_MTK_LYNXI) += pcs-mtk-lynxi.o
obj-$(CONFIG_PCS_RZN1_MIIC) += pcs-rzn1-miic.o
-obj-$(CONFIG_PCS_ALTERA_TSE) += 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 <maxime.chevallier@bootlin.com>
- */
-
-#include <linux/netdevice.h>
-#include <linux/phy.h>
-#include <linux/phylink.h>
-#include <linux/pcs-altera-tse.h>
-
-/* 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 *pcs)
-{
- 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 == 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 == 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 = tse_pcs_read(tse_pcs, MII_BMCR);
- bmcr |= 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 == PHY_INTERFACE_MODE_SGMII ||
- state->interface == 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 = phylink_pcs_to_tse_pcs(pcs);
- u32 ctrl, if_mode;
-
- ctrl = tse_pcs_read(tse_pcs, MII_BMCR);
- if_mode = 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 == PHY_INTERFACE_MODE_SGMII) {
- if_mode |= PCS_IF_MODE_USE_SGMII_AN | PCS_IF_MODE_SGMII_ENA;
- } else if (interface == PHY_INTERFACE_MODE_1000BASEX) {
- if_mode &= ~(PCS_IF_MODE_USE_SGMII_AN | PCS_IF_MODE_SGMII_ENA);
- }
-
- ctrl |= (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 = phylink_pcs_to_tse_pcs(pcs);
- u16 bmsr, lpa;
-
- bmsr = tse_pcs_read(tse_pcs, MII_BMSR);
- lpa = 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 = phylink_pcs_to_tse_pcs(pcs);
- u16 bmcr;
-
- bmcr = tse_pcs_read(tse_pcs, MII_BMCR);
- bmcr |= 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 = {
- .pcs_validate = alt_tse_pcs_validate,
- .pcs_get_state = alt_tse_pcs_get_state,
- .pcs_config = alt_tse_pcs_config,
- .pcs_an_restart = 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 != 4 && reg_width != 2)
- return ERR_PTR(-EINVAL);
-
- tse_pcs = devm_kzalloc(&ndev->dev, sizeof(*tse_pcs), GFP_KERNEL);
- if (!tse_pcs)
- return ERR_PTR(-ENOMEM);
-
- tse_pcs->pcs.ops = &alt_tse_pcs_ops;
- tse_pcs->base = pcs_base;
- tse_pcs->reg_width = 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 <maxime.chevallier@bootlin.com>");
diff --git a/include/linux/mdio/mdio-regmap.h b/include/linux/mdio/mdio-regmap.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 PCS
+ * within the MMIO-mapped area
+ *
+ * Copyright (C) 2023 Maxime Chevallier <maxime.chevallier@bootlin.com>
+ */
+#ifndef MDIO_REGMAP_H
+#define MDIO_REGMAP_H
+
+#include <linux/phy.h>
+
+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
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 <maxime.chevallier@bootlin.com>
- */
-
-#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 */