diff options
author | Jose Abreu <Jose.Abreu@synopsys.com> | 2018-08-08 04:04:33 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-08-09 14:16:28 -0400 |
commit | 6fc21117b791b601362fd2240fab833cbdbfdc15 (patch) | |
tree | 6bd87021c34c47b867a72f2cd4a4eab5581249d0 | |
parent | 874dfb65a484cff9b95014ed66c7cc6d2d6c4436 (diff) |
net: stmmac: Add MDIO related functions for XGMAC2
Add the MDIO related funcionalities for the new IP block XGMAC2.
Signed-off-by: Jose Abreu <joabreu@synopsys.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Joao Pinto <jpinto@synopsys.com>
Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Cc: Alexandre Torgue <alexandre.torgue@st.com>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 133 |
1 files changed, 129 insertions, 4 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index 5df1a608e566..b72ef171477e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/phy.h> | 29 | #include <linux/phy.h> |
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | 31 | ||
32 | #include "dwxgmac2.h" | ||
32 | #include "stmmac.h" | 33 | #include "stmmac.h" |
33 | 34 | ||
34 | #define MII_BUSY 0x00000001 | 35 | #define MII_BUSY 0x00000001 |
@@ -39,6 +40,115 @@ | |||
39 | #define MII_GMAC4_WRITE (1 << MII_GMAC4_GOC_SHIFT) | 40 | #define MII_GMAC4_WRITE (1 << MII_GMAC4_GOC_SHIFT) |
40 | #define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT) | 41 | #define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT) |
41 | 42 | ||
43 | /* XGMAC defines */ | ||
44 | #define MII_XGMAC_SADDR BIT(18) | ||
45 | #define MII_XGMAC_CMD_SHIFT 16 | ||
46 | #define MII_XGMAC_WRITE (1 << MII_XGMAC_CMD_SHIFT) | ||
47 | #define MII_XGMAC_READ (3 << MII_XGMAC_CMD_SHIFT) | ||
48 | #define MII_XGMAC_BUSY BIT(22) | ||
49 | #define MII_XGMAC_MAX_C22ADDR 3 | ||
50 | #define MII_XGMAC_C22P_MASK GENMASK(MII_XGMAC_MAX_C22ADDR, 0) | ||
51 | |||
52 | static int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr, | ||
53 | int phyreg, u32 *hw_addr) | ||
54 | { | ||
55 | unsigned int mii_data = priv->hw->mii.data; | ||
56 | u32 tmp; | ||
57 | |||
58 | /* HW does not support C22 addr >= 4 */ | ||
59 | if (phyaddr > MII_XGMAC_MAX_C22ADDR) | ||
60 | return -ENODEV; | ||
61 | /* Wait until any existing MII operation is complete */ | ||
62 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | ||
63 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) | ||
64 | return -EBUSY; | ||
65 | |||
66 | /* Set port as Clause 22 */ | ||
67 | tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P); | ||
68 | tmp &= ~MII_XGMAC_C22P_MASK; | ||
69 | tmp |= BIT(phyaddr); | ||
70 | writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P); | ||
71 | |||
72 | *hw_addr = (phyaddr << 16) | (phyreg & 0x1f); | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) | ||
77 | { | ||
78 | struct net_device *ndev = bus->priv; | ||
79 | struct stmmac_priv *priv = netdev_priv(ndev); | ||
80 | unsigned int mii_address = priv->hw->mii.addr; | ||
81 | unsigned int mii_data = priv->hw->mii.data; | ||
82 | u32 tmp, addr, value = MII_XGMAC_BUSY; | ||
83 | int ret; | ||
84 | |||
85 | if (phyreg & MII_ADDR_C45) { | ||
86 | return -EOPNOTSUPP; | ||
87 | } else { | ||
88 | ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr); | ||
89 | if (ret) | ||
90 | return ret; | ||
91 | } | ||
92 | |||
93 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) | ||
94 | & priv->hw->mii.clk_csr_mask; | ||
95 | value |= MII_XGMAC_SADDR | MII_XGMAC_READ; | ||
96 | |||
97 | /* Wait until any existing MII operation is complete */ | ||
98 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | ||
99 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) | ||
100 | return -EBUSY; | ||
101 | |||
102 | /* Set the MII address register to read */ | ||
103 | writel(addr, priv->ioaddr + mii_address); | ||
104 | writel(value, priv->ioaddr + mii_data); | ||
105 | |||
106 | /* Wait until any existing MII operation is complete */ | ||
107 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | ||
108 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) | ||
109 | return -EBUSY; | ||
110 | |||
111 | /* Read the data from the MII data register */ | ||
112 | return readl(priv->ioaddr + mii_data) & GENMASK(15, 0); | ||
113 | } | ||
114 | |||
115 | static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr, | ||
116 | int phyreg, u16 phydata) | ||
117 | { | ||
118 | struct net_device *ndev = bus->priv; | ||
119 | struct stmmac_priv *priv = netdev_priv(ndev); | ||
120 | unsigned int mii_address = priv->hw->mii.addr; | ||
121 | unsigned int mii_data = priv->hw->mii.data; | ||
122 | u32 addr, tmp, value = MII_XGMAC_BUSY; | ||
123 | int ret; | ||
124 | |||
125 | if (phyreg & MII_ADDR_C45) { | ||
126 | return -EOPNOTSUPP; | ||
127 | } else { | ||
128 | ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr); | ||
129 | if (ret) | ||
130 | return ret; | ||
131 | } | ||
132 | |||
133 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) | ||
134 | & priv->hw->mii.clk_csr_mask; | ||
135 | value |= phydata | MII_XGMAC_SADDR; | ||
136 | value |= MII_XGMAC_WRITE; | ||
137 | |||
138 | /* Wait until any existing MII operation is complete */ | ||
139 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, | ||
140 | !(tmp & MII_XGMAC_BUSY), 100, 10000)) | ||
141 | return -EBUSY; | ||
142 | |||
143 | /* Set the MII address register to write */ | ||
144 | writel(addr, priv->ioaddr + mii_address); | ||
145 | writel(value, priv->ioaddr + mii_data); | ||
146 | |||
147 | /* Wait until any existing MII operation is complete */ | ||
148 | return readl_poll_timeout(priv->ioaddr + mii_data, tmp, | ||
149 | !(tmp & MII_XGMAC_BUSY), 100, 10000); | ||
150 | } | ||
151 | |||
42 | /** | 152 | /** |
43 | * stmmac_mdio_read | 153 | * stmmac_mdio_read |
44 | * @bus: points to the mii_bus structure | 154 | * @bus: points to the mii_bus structure |
@@ -205,7 +315,7 @@ int stmmac_mdio_register(struct net_device *ndev) | |||
205 | struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data; | 315 | struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data; |
206 | struct device_node *mdio_node = priv->plat->mdio_node; | 316 | struct device_node *mdio_node = priv->plat->mdio_node; |
207 | struct device *dev = ndev->dev.parent; | 317 | struct device *dev = ndev->dev.parent; |
208 | int addr, found; | 318 | int addr, found, max_addr; |
209 | 319 | ||
210 | if (!mdio_bus_data) | 320 | if (!mdio_bus_data) |
211 | return 0; | 321 | return 0; |
@@ -223,8 +333,23 @@ int stmmac_mdio_register(struct net_device *ndev) | |||
223 | #endif | 333 | #endif |
224 | 334 | ||
225 | new_bus->name = "stmmac"; | 335 | new_bus->name = "stmmac"; |
226 | new_bus->read = &stmmac_mdio_read; | 336 | |
227 | new_bus->write = &stmmac_mdio_write; | 337 | if (priv->plat->has_xgmac) { |
338 | new_bus->read = &stmmac_xgmac2_mdio_read; | ||
339 | new_bus->write = &stmmac_xgmac2_mdio_write; | ||
340 | |||
341 | /* Right now only C22 phys are supported */ | ||
342 | max_addr = MII_XGMAC_MAX_C22ADDR + 1; | ||
343 | |||
344 | /* Check if DT specified an unsupported phy addr */ | ||
345 | if (priv->plat->phy_addr > MII_XGMAC_MAX_C22ADDR) | ||
346 | dev_err(dev, "Unsupported phy_addr (max=%d)\n", | ||
347 | MII_XGMAC_MAX_C22ADDR); | ||
348 | } else { | ||
349 | new_bus->read = &stmmac_mdio_read; | ||
350 | new_bus->write = &stmmac_mdio_write; | ||
351 | max_addr = PHY_MAX_ADDR; | ||
352 | } | ||
228 | 353 | ||
229 | new_bus->reset = &stmmac_mdio_reset; | 354 | new_bus->reset = &stmmac_mdio_reset; |
230 | snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x", | 355 | snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x", |
@@ -243,7 +368,7 @@ int stmmac_mdio_register(struct net_device *ndev) | |||
243 | goto bus_register_done; | 368 | goto bus_register_done; |
244 | 369 | ||
245 | found = 0; | 370 | found = 0; |
246 | for (addr = 0; addr < PHY_MAX_ADDR; addr++) { | 371 | for (addr = 0; addr < max_addr; addr++) { |
247 | struct phy_device *phydev = mdiobus_get_phy(new_bus, addr); | 372 | struct phy_device *phydev = mdiobus_get_phy(new_bus, addr); |
248 | 373 | ||
249 | if (!phydev) | 374 | if (!phydev) |