net: ethernet: stmmac: update MDIO support for GMAC4
authorAlexandre TORGUE <alexandre.torgue@st.com>
Thu, 28 Apr 2016 13:56:45 +0000 (15:56 +0200)
committerDavid S. Miller <davem@davemloft.net>
Fri, 29 Apr 2016 19:14:24 +0000 (15:14 -0400)
On new GMAC4 IP, MAC_MDIO_address register has been updated, and bitmaps
changed. This patch takes into account those changes.

Signed-off-by: Alexandre TORGUE <alexandre.torgue@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c

index 06704ca6f9ca3ec00aea1a4302fd0757a888fb45..3f83c369f56c46f306d84916586e872c05b6067e 100644 (file)
 #define MII_BUSY 0x00000001
 #define MII_WRITE 0x00000002
 
+/* GMAC4 defines */
+#define MII_GMAC4_GOC_SHIFT            2
+#define MII_GMAC4_WRITE                        (1 << MII_GMAC4_GOC_SHIFT)
+#define MII_GMAC4_READ                 (3 << MII_GMAC4_GOC_SHIFT)
+
+#define MII_PHY_ADDR_GMAC4_SHIFT       21
+#define MII_PHY_ADDR_GMAC4_MASK                GENMASK(25, 21)
+#define MII_PHY_REG_GMAC4_SHIFT                16
+#define MII_PHY_REG_GMAC4_MASK         GENMASK(20, 16)
+#define MII_CSR_CLK_GMAC4_SHIFT                8
+#define MII_CSR_CLK_GMAC4_MASK         GENMASK(11, 8)
+
 static int stmmac_mdio_busy_wait(void __iomem *ioaddr, unsigned int mii_addr)
 {
        unsigned long curr;
@@ -123,6 +135,80 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
        return stmmac_mdio_busy_wait(priv->ioaddr, mii_address);
 }
 
+/**
+ * stmmac_mdio_read_gmac4
+ * @bus: points to the mii_bus structure
+ * @phyaddr: MII addr reg bits 25-21
+ * @phyreg: MII addr reg bits 20-16
+ * Description: it reads data from the MII register of GMAC4 from within
+ * the phy device.
+ */
+static int stmmac_mdio_read_gmac4(struct mii_bus *bus, int phyaddr, int phyreg)
+{
+       struct net_device *ndev = bus->priv;
+       struct stmmac_priv *priv = netdev_priv(ndev);
+       unsigned int mii_address = priv->hw->mii.addr;
+       unsigned int mii_data = priv->hw->mii.data;
+       int data;
+       u32 value = (((phyaddr << MII_PHY_ADDR_GMAC4_SHIFT) &
+                    (MII_PHY_ADDR_GMAC4_MASK)) |
+                    ((phyreg << MII_PHY_REG_GMAC4_SHIFT) &
+                    (MII_PHY_REG_GMAC4_MASK))) | MII_GMAC4_READ;
+
+       value |= MII_BUSY | ((priv->clk_csr & MII_CSR_CLK_GMAC4_MASK)
+                << MII_CSR_CLK_GMAC4_SHIFT);
+
+       if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
+               return -EBUSY;
+
+       writel(value, priv->ioaddr + mii_address);
+
+       if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
+               return -EBUSY;
+
+       /* Read the data from the MII data register */
+       data = (int)readl(priv->ioaddr + mii_data);
+
+       return data;
+}
+
+/**
+ * stmmac_mdio_write_gmac4
+ * @bus: points to the mii_bus structure
+ * @phyaddr: MII addr reg bits 25-21
+ * @phyreg: MII addr reg bits 20-16
+ * @phydata: phy data
+ * Description: it writes the data into the MII register of GMAC4 from within
+ * the device.
+ */
+static int stmmac_mdio_write_gmac4(struct mii_bus *bus, int phyaddr, int phyreg,
+                                  u16 phydata)
+{
+       struct net_device *ndev = bus->priv;
+       struct stmmac_priv *priv = netdev_priv(ndev);
+       unsigned int mii_address = priv->hw->mii.addr;
+       unsigned int mii_data = priv->hw->mii.data;
+
+       u32 value = (((phyaddr << MII_PHY_ADDR_GMAC4_SHIFT) &
+                    (MII_PHY_ADDR_GMAC4_MASK)) |
+                    ((phyreg << MII_PHY_REG_GMAC4_SHIFT) &
+                    (MII_PHY_REG_GMAC4_MASK))) | MII_GMAC4_WRITE;
+
+       value |= MII_BUSY | ((priv->clk_csr & MII_CSR_CLK_GMAC4_MASK)
+                << MII_CSR_CLK_GMAC4_SHIFT);
+
+       /* Wait until any existing MII operation is complete */
+       if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
+               return -EBUSY;
+
+       /* Set the MII address register to write */
+       writel(phydata, priv->ioaddr + mii_data);
+       writel(value, priv->ioaddr + mii_address);
+
+       /* Wait until any existing MII operation is complete */
+       return stmmac_mdio_busy_wait(priv->ioaddr, mii_address);
+}
+
 /**
  * stmmac_mdio_reset
  * @bus: points to the mii_bus structure
@@ -180,9 +266,11 @@ int stmmac_mdio_reset(struct mii_bus *bus)
 
        /* This is a workaround for problems with the STE101P PHY.
         * It doesn't complete its reset until at least one clock cycle
-        * on MDC, so perform a dummy mdio read.
+        * on MDC, so perform a dummy mdio read. To be upadted for GMAC4
+        * if needed.
         */
-       writel(0, priv->ioaddr + mii_address);
+       if (!priv->plat->has_gmac4)
+               writel(0, priv->ioaddr + mii_address);
 #endif
        return 0;
 }
@@ -217,8 +305,14 @@ int stmmac_mdio_register(struct net_device *ndev)
 #endif
 
        new_bus->name = "stmmac";
-       new_bus->read = &stmmac_mdio_read;
-       new_bus->write = &stmmac_mdio_write;
+       if (priv->plat->has_gmac4) {
+               new_bus->read = &stmmac_mdio_read_gmac4;
+               new_bus->write = &stmmac_mdio_write_gmac4;
+       } else {
+               new_bus->read = &stmmac_mdio_read;
+               new_bus->write = &stmmac_mdio_write;
+       }
+
        new_bus->reset = &stmmac_mdio_reset;
        snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x",
                 new_bus->name, priv->plat->bus_id);