net: ethernet: mtk_eth_soc: implement Clause 45 MDIO access
authorDaniel Golle <daniel@makrotopia.org>
Tue, 4 Jan 2022 12:07:46 +0000 (12:07 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 5 Jan 2022 11:22:17 +0000 (11:22 +0000)
Implement read and write access to IEEE 802.3 Clause 45 Ethernet
phy registers while making use of new mdiobus_c45_regad and
mdiobus_c45_devad helpers.

Tested on the Ubiquiti UniFi 6 LR access point featuring
MediaTek MT7622BV WiSoC with Aquantia AQR112C.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mediatek/mtk_eth_soc.c
drivers/net/ethernet/mediatek/mtk_eth_soc.h

index 727650d..b67b432 100644 (file)
@@ -103,13 +103,35 @@ static int _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, u32 phy_reg,
        if (ret < 0)
                return ret;
 
-       mtk_w32(eth, PHY_IAC_ACCESS |
-                    PHY_IAC_START_C22 |
-                    PHY_IAC_CMD_WRITE |
-                    PHY_IAC_REG(phy_reg) |
-                    PHY_IAC_ADDR(phy_addr) |
-                    PHY_IAC_DATA(write_data),
-               MTK_PHY_IAC);
+       if (phy_reg & MII_ADDR_C45) {
+               mtk_w32(eth, PHY_IAC_ACCESS |
+                            PHY_IAC_START_C45 |
+                            PHY_IAC_CMD_C45_ADDR |
+                            PHY_IAC_REG(mdiobus_c45_devad(phy_reg)) |
+                            PHY_IAC_ADDR(phy_addr) |
+                            PHY_IAC_DATA(mdiobus_c45_regad(phy_reg)),
+                       MTK_PHY_IAC);
+
+               ret = mtk_mdio_busy_wait(eth);
+               if (ret < 0)
+                       return ret;
+
+               mtk_w32(eth, PHY_IAC_ACCESS |
+                            PHY_IAC_START_C45 |
+                            PHY_IAC_CMD_WRITE |
+                            PHY_IAC_REG(mdiobus_c45_devad(phy_reg)) |
+                            PHY_IAC_ADDR(phy_addr) |
+                            PHY_IAC_DATA(write_data),
+                       MTK_PHY_IAC);
+       } else {
+               mtk_w32(eth, PHY_IAC_ACCESS |
+                            PHY_IAC_START_C22 |
+                            PHY_IAC_CMD_WRITE |
+                            PHY_IAC_REG(phy_reg) |
+                            PHY_IAC_ADDR(phy_addr) |
+                            PHY_IAC_DATA(write_data),
+                       MTK_PHY_IAC);
+       }
 
        ret = mtk_mdio_busy_wait(eth);
        if (ret < 0)
@@ -126,12 +148,33 @@ static int _mtk_mdio_read(struct mtk_eth *eth, u32 phy_addr, u32 phy_reg)
        if (ret < 0)
                return ret;
 
-       mtk_w32(eth, PHY_IAC_ACCESS |
-                    PHY_IAC_START_C22 |
-                    PHY_IAC_CMD_C22_READ |
-                    PHY_IAC_REG(phy_reg) |
-                    PHY_IAC_ADDR(phy_addr),
-               MTK_PHY_IAC);
+       if (phy_reg & MII_ADDR_C45) {
+               mtk_w32(eth, PHY_IAC_ACCESS |
+                            PHY_IAC_START_C45 |
+                            PHY_IAC_CMD_C45_ADDR |
+                            PHY_IAC_REG(mdiobus_c45_devad(phy_reg)) |
+                            PHY_IAC_ADDR(phy_addr) |
+                            PHY_IAC_DATA(mdiobus_c45_regad(phy_reg)),
+                       MTK_PHY_IAC);
+
+               ret = mtk_mdio_busy_wait(eth);
+               if (ret < 0)
+                       return ret;
+
+               mtk_w32(eth, PHY_IAC_ACCESS |
+                            PHY_IAC_START_C45 |
+                            PHY_IAC_CMD_C45_READ |
+                            PHY_IAC_REG(mdiobus_c45_devad(phy_reg)) |
+                            PHY_IAC_ADDR(phy_addr),
+                       MTK_PHY_IAC);
+       } else {
+               mtk_w32(eth, PHY_IAC_ACCESS |
+                            PHY_IAC_START_C22 |
+                            PHY_IAC_CMD_C22_READ |
+                            PHY_IAC_REG(phy_reg) |
+                            PHY_IAC_ADDR(phy_addr),
+                       MTK_PHY_IAC);
+       }
 
        ret = mtk_mdio_busy_wait(eth);
        if (ret < 0)
@@ -504,6 +547,7 @@ static int mtk_mdio_init(struct mtk_eth *eth)
        eth->mii_bus->name = "mdio";
        eth->mii_bus->read = mtk_mdio_read;
        eth->mii_bus->write = mtk_mdio_write;
+       eth->mii_bus->probe_capabilities = MDIOBUS_C22_C45;
        eth->mii_bus->priv = eth;
        eth->mii_bus->parent = eth->dev;
 
index f2d9063..c9d42be 100644 (file)
 #define PHY_IAC_ADDR_MASK      GENMASK(24, 20)
 #define PHY_IAC_ADDR(x)                FIELD_PREP(PHY_IAC_ADDR_MASK, (x))
 #define PHY_IAC_CMD_MASK       GENMASK(19, 18)
+#define PHY_IAC_CMD_C45_ADDR   FIELD_PREP(PHY_IAC_CMD_MASK, 0)
 #define PHY_IAC_CMD_WRITE      FIELD_PREP(PHY_IAC_CMD_MASK, 1)
 #define PHY_IAC_CMD_C22_READ   FIELD_PREP(PHY_IAC_CMD_MASK, 2)
+#define PHY_IAC_CMD_C45_READ   FIELD_PREP(PHY_IAC_CMD_MASK, 3)
 #define PHY_IAC_START_MASK     GENMASK(17, 16)
+#define PHY_IAC_START_C45      FIELD_PREP(PHY_IAC_START_MASK, 0)
 #define PHY_IAC_START_C22      FIELD_PREP(PHY_IAC_START_MASK, 1)
 #define PHY_IAC_DATA_MASK      GENMASK(15, 0)
 #define PHY_IAC_DATA(x)                FIELD_PREP(PHY_IAC_DATA_MASK, (x))