From: Florian Fainelli <florian.fainelli@broadcom.com>
To: netdev@vger.kernel.org
Cc: Florian Fainelli <florian.fainelli@broadcom.com>,
Carlos Soto <carlos.soto@broadcom.com>,
Justin Chen <justin.chen@broadcom.com>,
Doug Berger <opendmb@gmail.com>,
Nicolai Buchwitz <nb@tipi-net.de>,
Broadcom internal kernel review list
<bcm-kernel-feedback-list@broadcom.com>,
Andrew Lunn <andrew@lunn.ch>,
Heiner Kallweit <hkallweit1@gmail.com>,
Russell King <linux@armlinux.org.uk>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
linux-kernel@vger.kernel.org (open list),
Mlody12 mlody12 <kudzo51@gmail.com>
Subject: [PATCH net-next 3/3] net: mdio: mdio-bcm-unimac: Add Clause 45 support
Date: Fri, 13 Nov 2026 13:15:54 -0800 [thread overview]
Message-ID: <20261113211554.2058181-4-florian.fainelli@broadcom.com> (raw)
In-Reply-To: <20261113211554.2058181-1-florian.fainelli@broadcom.com>
Add Clause 45 read/write support to the UniMAC MDIO bus controller driver
by implementing the read_c45/write_c45 bus callbacks. Each access performs
the two-step C45 sequence (ADDR cycle followed by a READ/WRITE cycle) under
the bus lock and switches MDIO_CFG between C22 and C45 mode as needed;
MDIO_CFG is only written when the mode actually changes.
Also skip the BMSR workaround read in unimac_mdio_reset() for children
compatible with "ethernet-phy-ieee802.3-c45", since such PHYs are not
expected to respond to C22 accesses.
Note that providing read_c45/write_c45 also makes the MDIO core scan for
C45 PHYs at registration time, on addresses that are not masked and do not
already have a C22 device.
Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
Co-developed-by: Carlos Soto <carlos.soto@broadcom.com>
Signed-off-by: Carlos Soto <carlos.soto@broadcom.com>
Co-developed-by: Justin Chen <justin.chen@broadcom.com>
Signed-off-by: Justin Chen <justin.chen@broadcom.com>
---
drivers/net/mdio/mdio-bcm-unimac.c | 105 +++++++++++++++++++++++++++--
1 file changed, 98 insertions(+), 7 deletions(-)
diff --git a/drivers/net/mdio/mdio-bcm-unimac.c b/drivers/net/mdio/mdio-bcm-unimac.c
index 15a9880c3573..25f54ee754f9 100644
--- a/drivers/net/mdio/mdio-bcm-unimac.c
+++ b/drivers/net/mdio/mdio-bcm-unimac.c
@@ -24,10 +24,16 @@
#define MDIO_OP_SHIFT 26
#define MDIO_RD_C22 (2 << MDIO_OP_SHIFT)
#define MDIO_WR_C22 (1 << MDIO_OP_SHIFT)
+#define MDIO_ADDR_C45 (0 << MDIO_OP_SHIFT)
+#define MDIO_WR_C45 (1 << MDIO_OP_SHIFT)
+#define MDIO_RD_C45 (3 << MDIO_OP_SHIFT)
#define MDIO_PMD_SHIFT 21
#define MDIO_PMD_MASK 0x1F
#define MDIO_REG_SHIFT 16
#define MDIO_REG_MASK 0x1F
+#define MDIO_DEVAD_SHIFT 16
+#define MDIO_DEVAD_MASK GENMASK(20, 16)
+#define MDIO_C45_REG_MASK GENMASK(15, 0)
#define MDIO_CFG 0x04
#define MDIO_C22 (1 << 0)
@@ -96,7 +102,43 @@ static int unimac_mdio_poll(void *wait_func_data)
MDIO_CMD);
}
-static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+static u32 unimac_mdio_c45_devad(int devad)
+{
+ return ((u32)devad << MDIO_DEVAD_SHIFT) & MDIO_DEVAD_MASK;
+}
+
+static int unimac_mdio_addr_c45(struct unimac_mdio_priv *priv,
+ int phy_id, int devad, int reg)
+{
+ u32 cmd;
+
+ /* Prepare the addr c45 operation */
+ cmd = MDIO_ADDR_C45 | (phy_id << MDIO_PMD_SHIFT) |
+ unimac_mdio_c45_devad(devad) | (reg & MDIO_C45_REG_MASK);
+ unimac_mdio_writel(priv, cmd, MDIO_CMD);
+
+ /* Start MDIO transaction */
+ unimac_mdio_start(priv);
+
+ return priv->wait_func(priv->wait_func_data);
+}
+
+static void unimac_mdio_set_clause(struct unimac_mdio_priv *priv, bool is_c45)
+{
+ u32 cfg = unimac_mdio_readl(priv, MDIO_CFG);
+ u32 new_cfg = cfg;
+
+ if (is_c45)
+ new_cfg &= ~MDIO_C22;
+ else
+ new_cfg |= MDIO_C22;
+
+ if (new_cfg != cfg)
+ unimac_mdio_writel(priv, new_cfg, MDIO_CFG);
+}
+
+static int unimac_mdio_do_read(struct mii_bus *bus, int phy_id, int devad,
+ int reg, bool is_c45)
{
struct unimac_mdio_priv *priv = bus->priv;
int ret;
@@ -107,8 +149,19 @@ static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
return ret;
/* Prepare the read operation */
- cmd = MDIO_RD_C22 | (phy_id << MDIO_PMD_SHIFT) |
- (reg << MDIO_REG_SHIFT);
+ unimac_mdio_set_clause(priv, is_c45);
+ if (is_c45) {
+ ret = unimac_mdio_addr_c45(priv, phy_id, devad, reg);
+ if (ret)
+ goto out;
+
+ cmd = MDIO_RD_C45 | (phy_id << MDIO_PMD_SHIFT) |
+ unimac_mdio_c45_devad(devad) |
+ (reg & MDIO_C45_REG_MASK);
+ } else {
+ cmd = MDIO_RD_C22 | (phy_id << MDIO_PMD_SHIFT) |
+ (reg << MDIO_REG_SHIFT);
+ }
unimac_mdio_writel(priv, cmd, MDIO_CMD);
/* Start MDIO transaction */
@@ -136,8 +189,8 @@ static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
return ret;
}
-static int unimac_mdio_write(struct mii_bus *bus, int phy_id,
- int reg, u16 val)
+static int unimac_mdio_do_write(struct mii_bus *bus, int phy_id, int devad,
+ int reg, u16 val, bool is_c45)
{
struct unimac_mdio_priv *priv = bus->priv;
u32 cmd;
@@ -148,18 +201,50 @@ static int unimac_mdio_write(struct mii_bus *bus, int phy_id,
return ret;
/* Prepare the write operation */
- cmd = MDIO_WR_C22 | (phy_id << MDIO_PMD_SHIFT) |
- (reg << MDIO_REG_SHIFT) | (0xffff & val);
+ unimac_mdio_set_clause(priv, is_c45);
+ if (is_c45) {
+ ret = unimac_mdio_addr_c45(priv, phy_id, devad, reg);
+ if (ret)
+ goto out;
+
+ cmd = MDIO_WR_C45 | (phy_id << MDIO_PMD_SHIFT) |
+ unimac_mdio_c45_devad(devad) | (0xffff & val);
+ } else {
+ cmd = MDIO_WR_C22 | (phy_id << MDIO_PMD_SHIFT) |
+ (reg << MDIO_REG_SHIFT) | (0xffff & val);
+ }
unimac_mdio_writel(priv, cmd, MDIO_CMD);
unimac_mdio_start(priv);
ret = priv->wait_func(priv->wait_func_data);
+out:
clk_disable_unprepare(priv->clk);
return ret;
}
+static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+ return unimac_mdio_do_read(bus, phy_id, 0, reg, false);
+}
+
+static int unimac_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
+{
+ return unimac_mdio_do_write(bus, phy_id, 0, reg, val, false);
+}
+
+static int unimac_mdio_read_c45(struct mii_bus *bus, int addr, int dev, int reg)
+{
+ return unimac_mdio_do_read(bus, addr, dev, reg, true);
+}
+
+static int unimac_mdio_write_c45(struct mii_bus *bus, int addr, int dev,
+ int reg, u16 val)
+{
+ return unimac_mdio_do_write(bus, addr, dev, reg, val, true);
+}
+
/* Workaround for integrated BCM7xxx Gigabit PHYs which have a problem with
* their internal MDIO management controller making them fail to successfully
* be read from or written to for the first transaction. We insert a dummy
@@ -190,6 +275,10 @@ static int unimac_mdio_reset(struct mii_bus *bus)
if (addr < 0)
continue;
+ if (of_device_is_compatible(child,
+ "ethernet-phy-ieee802.3-c45"))
+ continue;
+
read_mask |= 1 << addr;
}
}
@@ -301,6 +390,8 @@ static int unimac_mdio_probe(struct platform_device *pdev)
bus->parent = &pdev->dev;
bus->read = unimac_mdio_read;
bus->write = unimac_mdio_write;
+ bus->read_c45 = unimac_mdio_read_c45;
+ bus->write_c45 = unimac_mdio_write_c45;
bus->reset = unimac_mdio_reset;
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id);
--
2.34.1
prev parent reply other threads:[~2026-11-13 21:16 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-13 21:15 [PATCH net-next 0/3] net: mdio: Clause 45 support for Florian Fainelli
2026-11-13 21:15 ` [PATCH net-next 1/3] net: mdio: mdio-bcm-unimac: Define MDIO_OP_SHIFT Florian Fainelli
2026-11-13 21:15 ` [PATCH net-next 2/3] net: mdio: mdio-bcm-unimac: Poll for completion at 1us granularity Florian Fainelli
2026-11-13 21:15 ` Florian Fainelli [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261113211554.2058181-4-florian.fainelli@broadcom.com \
--to=florian.fainelli@broadcom.com \
--cc=andrew@lunn.ch \
--cc=bcm-kernel-feedback-list@broadcom.com \
--cc=carlos.soto@broadcom.com \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=hkallweit1@gmail.com \
--cc=justin.chen@broadcom.com \
--cc=kuba@kernel.org \
--cc=kudzo51@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=nb@tipi-net.de \
--cc=netdev@vger.kernel.org \
--cc=opendmb@gmail.com \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®