1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*******************************************************************************
3*4882a593Smuzhiyun STMMAC Ethernet Driver -- MDIO bus implementation
4*4882a593Smuzhiyun Provides Bus interface for MII registers
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun Copyright (C) 2007-2009 STMicroelectronics Ltd
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun Author: Carl Shaw <carl.shaw@st.com>
10*4882a593Smuzhiyun Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
11*4882a593Smuzhiyun *******************************************************************************/
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
14*4882a593Smuzhiyun #include <linux/io.h>
15*4882a593Smuzhiyun #include <linux/iopoll.h>
16*4882a593Smuzhiyun #include <linux/mii.h>
17*4882a593Smuzhiyun #include <linux/of_mdio.h>
18*4882a593Smuzhiyun #include <linux/pm_runtime.h>
19*4882a593Smuzhiyun #include <linux/phy.h>
20*4882a593Smuzhiyun #include <linux/property.h>
21*4882a593Smuzhiyun #include <linux/slab.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include "dwxgmac2.h"
24*4882a593Smuzhiyun #include "stmmac.h"
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #define MII_BUSY 0x00000001
27*4882a593Smuzhiyun #define MII_WRITE 0x00000002
28*4882a593Smuzhiyun #define MII_DATA_MASK GENMASK(15, 0)
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun /* GMAC4 defines */
31*4882a593Smuzhiyun #define MII_GMAC4_GOC_SHIFT 2
32*4882a593Smuzhiyun #define MII_GMAC4_REG_ADDR_SHIFT 16
33*4882a593Smuzhiyun #define MII_GMAC4_WRITE (1 << MII_GMAC4_GOC_SHIFT)
34*4882a593Smuzhiyun #define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT)
35*4882a593Smuzhiyun #define MII_GMAC4_C45E BIT(1)
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun /* XGMAC defines */
38*4882a593Smuzhiyun #define MII_XGMAC_SADDR BIT(18)
39*4882a593Smuzhiyun #define MII_XGMAC_CMD_SHIFT 16
40*4882a593Smuzhiyun #define MII_XGMAC_WRITE (1 << MII_XGMAC_CMD_SHIFT)
41*4882a593Smuzhiyun #define MII_XGMAC_READ (3 << MII_XGMAC_CMD_SHIFT)
42*4882a593Smuzhiyun #define MII_XGMAC_BUSY BIT(22)
43*4882a593Smuzhiyun #define MII_XGMAC_MAX_C22ADDR 3
44*4882a593Smuzhiyun #define MII_XGMAC_C22P_MASK GENMASK(MII_XGMAC_MAX_C22ADDR, 0)
45*4882a593Smuzhiyun #define MII_XGMAC_PA_SHIFT 16
46*4882a593Smuzhiyun #define MII_XGMAC_DA_SHIFT 21
47*4882a593Smuzhiyun
stmmac_xgmac2_c45_format(struct stmmac_priv * priv,int phyaddr,int phyreg,u32 * hw_addr)48*4882a593Smuzhiyun static int stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr,
49*4882a593Smuzhiyun int phyreg, u32 *hw_addr)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun u32 tmp;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun /* Set port as Clause 45 */
54*4882a593Smuzhiyun tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
55*4882a593Smuzhiyun tmp &= ~BIT(phyaddr);
56*4882a593Smuzhiyun writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P);
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun *hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0xffff);
59*4882a593Smuzhiyun *hw_addr |= (phyreg >> MII_DEVADDR_C45_SHIFT) << MII_XGMAC_DA_SHIFT;
60*4882a593Smuzhiyun return 0;
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun
stmmac_xgmac2_c22_format(struct stmmac_priv * priv,int phyaddr,int phyreg,u32 * hw_addr)63*4882a593Smuzhiyun static int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr,
64*4882a593Smuzhiyun int phyreg, u32 *hw_addr)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun u32 tmp;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun /* HW does not support C22 addr >= 4 */
69*4882a593Smuzhiyun if (phyaddr > MII_XGMAC_MAX_C22ADDR)
70*4882a593Smuzhiyun return -ENODEV;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /* Set port as Clause 22 */
73*4882a593Smuzhiyun tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
74*4882a593Smuzhiyun tmp &= ~MII_XGMAC_C22P_MASK;
75*4882a593Smuzhiyun tmp |= BIT(phyaddr);
76*4882a593Smuzhiyun writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P);
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun *hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0x1f);
79*4882a593Smuzhiyun return 0;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
stmmac_xgmac2_mdio_read(struct mii_bus * bus,int phyaddr,int phyreg)82*4882a593Smuzhiyun static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun struct net_device *ndev = bus->priv;
85*4882a593Smuzhiyun struct stmmac_priv *priv = netdev_priv(ndev);
86*4882a593Smuzhiyun unsigned int mii_address = priv->hw->mii.addr;
87*4882a593Smuzhiyun unsigned int mii_data = priv->hw->mii.data;
88*4882a593Smuzhiyun u32 tmp, addr, value = MII_XGMAC_BUSY;
89*4882a593Smuzhiyun int ret;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun ret = pm_runtime_get_sync(priv->device);
92*4882a593Smuzhiyun if (ret < 0) {
93*4882a593Smuzhiyun pm_runtime_put_noidle(priv->device);
94*4882a593Smuzhiyun return ret;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun /* Wait until any existing MII operation is complete */
98*4882a593Smuzhiyun if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
99*4882a593Smuzhiyun !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
100*4882a593Smuzhiyun ret = -EBUSY;
101*4882a593Smuzhiyun goto err_disable_clks;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun if (phyreg & MII_ADDR_C45) {
105*4882a593Smuzhiyun phyreg &= ~MII_ADDR_C45;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
108*4882a593Smuzhiyun if (ret)
109*4882a593Smuzhiyun goto err_disable_clks;
110*4882a593Smuzhiyun } else {
111*4882a593Smuzhiyun ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
112*4882a593Smuzhiyun if (ret)
113*4882a593Smuzhiyun goto err_disable_clks;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun value |= MII_XGMAC_SADDR;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
119*4882a593Smuzhiyun & priv->hw->mii.clk_csr_mask;
120*4882a593Smuzhiyun value |= MII_XGMAC_READ;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun /* Wait until any existing MII operation is complete */
123*4882a593Smuzhiyun if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
124*4882a593Smuzhiyun !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
125*4882a593Smuzhiyun ret = -EBUSY;
126*4882a593Smuzhiyun goto err_disable_clks;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun /* Set the MII address register to read */
130*4882a593Smuzhiyun writel(addr, priv->ioaddr + mii_address);
131*4882a593Smuzhiyun writel(value, priv->ioaddr + mii_data);
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun /* Wait until any existing MII operation is complete */
134*4882a593Smuzhiyun if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
135*4882a593Smuzhiyun !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
136*4882a593Smuzhiyun ret = -EBUSY;
137*4882a593Smuzhiyun goto err_disable_clks;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun /* Read the data from the MII data register */
141*4882a593Smuzhiyun ret = (int)readl(priv->ioaddr + mii_data) & GENMASK(15, 0);
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun err_disable_clks:
144*4882a593Smuzhiyun pm_runtime_put(priv->device);
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun return ret;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
stmmac_xgmac2_mdio_write(struct mii_bus * bus,int phyaddr,int phyreg,u16 phydata)149*4882a593Smuzhiyun static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr,
150*4882a593Smuzhiyun int phyreg, u16 phydata)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun struct net_device *ndev = bus->priv;
153*4882a593Smuzhiyun struct stmmac_priv *priv = netdev_priv(ndev);
154*4882a593Smuzhiyun unsigned int mii_address = priv->hw->mii.addr;
155*4882a593Smuzhiyun unsigned int mii_data = priv->hw->mii.data;
156*4882a593Smuzhiyun u32 addr, tmp, value = MII_XGMAC_BUSY;
157*4882a593Smuzhiyun int ret;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun ret = pm_runtime_get_sync(priv->device);
160*4882a593Smuzhiyun if (ret < 0) {
161*4882a593Smuzhiyun pm_runtime_put_noidle(priv->device);
162*4882a593Smuzhiyun return ret;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun /* Wait until any existing MII operation is complete */
166*4882a593Smuzhiyun if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
167*4882a593Smuzhiyun !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
168*4882a593Smuzhiyun ret = -EBUSY;
169*4882a593Smuzhiyun goto err_disable_clks;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun if (phyreg & MII_ADDR_C45) {
173*4882a593Smuzhiyun phyreg &= ~MII_ADDR_C45;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
176*4882a593Smuzhiyun if (ret)
177*4882a593Smuzhiyun goto err_disable_clks;
178*4882a593Smuzhiyun } else {
179*4882a593Smuzhiyun ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
180*4882a593Smuzhiyun if (ret)
181*4882a593Smuzhiyun goto err_disable_clks;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun value |= MII_XGMAC_SADDR;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
187*4882a593Smuzhiyun & priv->hw->mii.clk_csr_mask;
188*4882a593Smuzhiyun value |= phydata;
189*4882a593Smuzhiyun value |= MII_XGMAC_WRITE;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun /* Wait until any existing MII operation is complete */
192*4882a593Smuzhiyun if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
193*4882a593Smuzhiyun !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
194*4882a593Smuzhiyun ret = -EBUSY;
195*4882a593Smuzhiyun goto err_disable_clks;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun /* Set the MII address register to write */
199*4882a593Smuzhiyun writel(addr, priv->ioaddr + mii_address);
200*4882a593Smuzhiyun writel(value, priv->ioaddr + mii_data);
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun /* Wait until any existing MII operation is complete */
203*4882a593Smuzhiyun ret = readl_poll_timeout(priv->ioaddr + mii_data, tmp,
204*4882a593Smuzhiyun !(tmp & MII_XGMAC_BUSY), 100, 10000);
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun err_disable_clks:
207*4882a593Smuzhiyun pm_runtime_put(priv->device);
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun return ret;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun /**
213*4882a593Smuzhiyun * stmmac_mdio_read
214*4882a593Smuzhiyun * @bus: points to the mii_bus structure
215*4882a593Smuzhiyun * @phyaddr: MII addr
216*4882a593Smuzhiyun * @phyreg: MII reg
217*4882a593Smuzhiyun * Description: it reads data from the MII register from within the phy device.
218*4882a593Smuzhiyun * For the 7111 GMAC, we must set the bit 0 in the MII address register while
219*4882a593Smuzhiyun * accessing the PHY registers.
220*4882a593Smuzhiyun * Fortunately, it seems this has no drawback for the 7109 MAC.
221*4882a593Smuzhiyun */
stmmac_mdio_read(struct mii_bus * bus,int phyaddr,int phyreg)222*4882a593Smuzhiyun static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun struct net_device *ndev = bus->priv;
225*4882a593Smuzhiyun struct stmmac_priv *priv = netdev_priv(ndev);
226*4882a593Smuzhiyun unsigned int mii_address = priv->hw->mii.addr;
227*4882a593Smuzhiyun unsigned int mii_data = priv->hw->mii.data;
228*4882a593Smuzhiyun u32 value = MII_BUSY;
229*4882a593Smuzhiyun int data = 0;
230*4882a593Smuzhiyun u32 v;
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun data = pm_runtime_get_sync(priv->device);
233*4882a593Smuzhiyun if (data < 0) {
234*4882a593Smuzhiyun pm_runtime_put_noidle(priv->device);
235*4882a593Smuzhiyun return data;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun value |= (phyaddr << priv->hw->mii.addr_shift)
239*4882a593Smuzhiyun & priv->hw->mii.addr_mask;
240*4882a593Smuzhiyun value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
241*4882a593Smuzhiyun value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
242*4882a593Smuzhiyun & priv->hw->mii.clk_csr_mask;
243*4882a593Smuzhiyun if (priv->plat->has_gmac4) {
244*4882a593Smuzhiyun value |= MII_GMAC4_READ;
245*4882a593Smuzhiyun if (phyreg & MII_ADDR_C45) {
246*4882a593Smuzhiyun value |= MII_GMAC4_C45E;
247*4882a593Smuzhiyun value &= ~priv->hw->mii.reg_mask;
248*4882a593Smuzhiyun value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) <<
249*4882a593Smuzhiyun priv->hw->mii.reg_shift) &
250*4882a593Smuzhiyun priv->hw->mii.reg_mask;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun data |= (phyreg & MII_REGADDR_C45_MASK) <<
253*4882a593Smuzhiyun MII_GMAC4_REG_ADDR_SHIFT;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
258*4882a593Smuzhiyun 100, 10000)) {
259*4882a593Smuzhiyun data = -EBUSY;
260*4882a593Smuzhiyun goto err_disable_clks;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun writel(data, priv->ioaddr + mii_data);
264*4882a593Smuzhiyun writel(value, priv->ioaddr + mii_address);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
267*4882a593Smuzhiyun 100, 10000)) {
268*4882a593Smuzhiyun data = -EBUSY;
269*4882a593Smuzhiyun goto err_disable_clks;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun /* Read the data from the MII data register */
273*4882a593Smuzhiyun data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun err_disable_clks:
276*4882a593Smuzhiyun pm_runtime_put(priv->device);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun return data;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun /**
282*4882a593Smuzhiyun * stmmac_mdio_write
283*4882a593Smuzhiyun * @bus: points to the mii_bus structure
284*4882a593Smuzhiyun * @phyaddr: MII addr
285*4882a593Smuzhiyun * @phyreg: MII reg
286*4882a593Smuzhiyun * @phydata: phy data
287*4882a593Smuzhiyun * Description: it writes the data into the MII register from within the device.
288*4882a593Smuzhiyun */
stmmac_mdio_write(struct mii_bus * bus,int phyaddr,int phyreg,u16 phydata)289*4882a593Smuzhiyun static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
290*4882a593Smuzhiyun u16 phydata)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun struct net_device *ndev = bus->priv;
293*4882a593Smuzhiyun struct stmmac_priv *priv = netdev_priv(ndev);
294*4882a593Smuzhiyun unsigned int mii_address = priv->hw->mii.addr;
295*4882a593Smuzhiyun unsigned int mii_data = priv->hw->mii.data;
296*4882a593Smuzhiyun int ret, data = phydata;
297*4882a593Smuzhiyun u32 value = MII_BUSY;
298*4882a593Smuzhiyun u32 v;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun ret = pm_runtime_get_sync(priv->device);
301*4882a593Smuzhiyun if (ret < 0) {
302*4882a593Smuzhiyun pm_runtime_put_noidle(priv->device);
303*4882a593Smuzhiyun return ret;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun value |= (phyaddr << priv->hw->mii.addr_shift)
307*4882a593Smuzhiyun & priv->hw->mii.addr_mask;
308*4882a593Smuzhiyun value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
311*4882a593Smuzhiyun & priv->hw->mii.clk_csr_mask;
312*4882a593Smuzhiyun if (priv->plat->has_gmac4) {
313*4882a593Smuzhiyun value |= MII_GMAC4_WRITE;
314*4882a593Smuzhiyun if (phyreg & MII_ADDR_C45) {
315*4882a593Smuzhiyun value |= MII_GMAC4_C45E;
316*4882a593Smuzhiyun value &= ~priv->hw->mii.reg_mask;
317*4882a593Smuzhiyun value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) <<
318*4882a593Smuzhiyun priv->hw->mii.reg_shift) &
319*4882a593Smuzhiyun priv->hw->mii.reg_mask;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun data |= (phyreg & MII_REGADDR_C45_MASK) <<
322*4882a593Smuzhiyun MII_GMAC4_REG_ADDR_SHIFT;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun } else {
325*4882a593Smuzhiyun value |= MII_WRITE;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun /* Wait until any existing MII operation is complete */
329*4882a593Smuzhiyun if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
330*4882a593Smuzhiyun 100, 10000)) {
331*4882a593Smuzhiyun ret = -EBUSY;
332*4882a593Smuzhiyun goto err_disable_clks;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun /* Set the MII address register to write */
336*4882a593Smuzhiyun writel(data, priv->ioaddr + mii_data);
337*4882a593Smuzhiyun writel(value, priv->ioaddr + mii_address);
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun /* Wait until any existing MII operation is complete */
340*4882a593Smuzhiyun ret = readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
341*4882a593Smuzhiyun 100, 10000);
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun err_disable_clks:
344*4882a593Smuzhiyun pm_runtime_put(priv->device);
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun return ret;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun /**
350*4882a593Smuzhiyun * stmmac_mdio_reset
351*4882a593Smuzhiyun * @bus: points to the mii_bus structure
352*4882a593Smuzhiyun * Description: reset the MII bus
353*4882a593Smuzhiyun */
stmmac_mdio_reset(struct mii_bus * bus)354*4882a593Smuzhiyun int stmmac_mdio_reset(struct mii_bus *bus)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_STMMAC_PLATFORM)
357*4882a593Smuzhiyun struct net_device *ndev = bus->priv;
358*4882a593Smuzhiyun struct stmmac_priv *priv = netdev_priv(ndev);
359*4882a593Smuzhiyun unsigned int mii_address = priv->hw->mii.addr;
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun #ifdef CONFIG_OF
362*4882a593Smuzhiyun if (priv->device->of_node) {
363*4882a593Smuzhiyun struct gpio_desc *reset_gpio;
364*4882a593Smuzhiyun u32 delays[3] = { 0, 0, 0 };
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun reset_gpio = devm_gpiod_get_optional(priv->device,
367*4882a593Smuzhiyun "snps,reset",
368*4882a593Smuzhiyun GPIOD_OUT_LOW);
369*4882a593Smuzhiyun if (IS_ERR(reset_gpio))
370*4882a593Smuzhiyun return PTR_ERR(reset_gpio);
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun device_property_read_u32_array(priv->device,
373*4882a593Smuzhiyun "snps,reset-delays-us",
374*4882a593Smuzhiyun delays, ARRAY_SIZE(delays));
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun if (delays[0])
377*4882a593Smuzhiyun msleep(DIV_ROUND_UP(delays[0], 1000));
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun gpiod_set_value_cansleep(reset_gpio, 1);
380*4882a593Smuzhiyun if (delays[1])
381*4882a593Smuzhiyun msleep(DIV_ROUND_UP(delays[1], 1000));
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun gpiod_set_value_cansleep(reset_gpio, 0);
384*4882a593Smuzhiyun if (delays[2])
385*4882a593Smuzhiyun msleep(DIV_ROUND_UP(delays[2], 1000));
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun #endif
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun /* This is a workaround for problems with the STE101P PHY.
390*4882a593Smuzhiyun * It doesn't complete its reset until at least one clock cycle
391*4882a593Smuzhiyun * on MDC, so perform a dummy mdio read. To be updated for GMAC4
392*4882a593Smuzhiyun * if needed.
393*4882a593Smuzhiyun */
394*4882a593Smuzhiyun if (!priv->plat->has_gmac4)
395*4882a593Smuzhiyun writel(0, priv->ioaddr + mii_address);
396*4882a593Smuzhiyun #endif
397*4882a593Smuzhiyun return 0;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun EXPORT_SYMBOL(stmmac_mdio_reset);
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun /**
402*4882a593Smuzhiyun * stmmac_mdio_register
403*4882a593Smuzhiyun * @ndev: net device structure
404*4882a593Smuzhiyun * Description: it registers the MII bus
405*4882a593Smuzhiyun */
stmmac_mdio_register(struct net_device * ndev)406*4882a593Smuzhiyun int stmmac_mdio_register(struct net_device *ndev)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun int err = 0;
409*4882a593Smuzhiyun struct mii_bus *new_bus;
410*4882a593Smuzhiyun struct stmmac_priv *priv = netdev_priv(ndev);
411*4882a593Smuzhiyun struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
412*4882a593Smuzhiyun struct device_node *mdio_node = priv->plat->mdio_node;
413*4882a593Smuzhiyun struct device *dev = ndev->dev.parent;
414*4882a593Smuzhiyun int addr, found, max_addr;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun if (!mdio_bus_data)
417*4882a593Smuzhiyun return 0;
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun new_bus = mdiobus_alloc();
420*4882a593Smuzhiyun if (!new_bus)
421*4882a593Smuzhiyun return -ENOMEM;
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun if (mdio_bus_data->irqs)
424*4882a593Smuzhiyun memcpy(new_bus->irq, mdio_bus_data->irqs, sizeof(new_bus->irq));
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun new_bus->name = "stmmac";
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun if (priv->plat->has_xgmac) {
429*4882a593Smuzhiyun new_bus->read = &stmmac_xgmac2_mdio_read;
430*4882a593Smuzhiyun new_bus->write = &stmmac_xgmac2_mdio_write;
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun /* Right now only C22 phys are supported */
433*4882a593Smuzhiyun max_addr = MII_XGMAC_MAX_C22ADDR + 1;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun /* Check if DT specified an unsupported phy addr */
436*4882a593Smuzhiyun if (priv->plat->phy_addr > MII_XGMAC_MAX_C22ADDR)
437*4882a593Smuzhiyun dev_err(dev, "Unsupported phy_addr (max=%d)\n",
438*4882a593Smuzhiyun MII_XGMAC_MAX_C22ADDR);
439*4882a593Smuzhiyun } else {
440*4882a593Smuzhiyun new_bus->read = &stmmac_mdio_read;
441*4882a593Smuzhiyun new_bus->write = &stmmac_mdio_write;
442*4882a593Smuzhiyun max_addr = PHY_MAX_ADDR;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun if (mdio_bus_data->has_xpcs) {
446*4882a593Smuzhiyun priv->hw->xpcs = mdio_xpcs_get_ops();
447*4882a593Smuzhiyun if (!priv->hw->xpcs) {
448*4882a593Smuzhiyun err = -ENODEV;
449*4882a593Smuzhiyun goto bus_register_fail;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun if (mdio_bus_data->needs_reset)
454*4882a593Smuzhiyun new_bus->reset = &stmmac_mdio_reset;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x",
457*4882a593Smuzhiyun new_bus->name, priv->plat->bus_id);
458*4882a593Smuzhiyun new_bus->priv = ndev;
459*4882a593Smuzhiyun new_bus->phy_mask = mdio_bus_data->phy_mask;
460*4882a593Smuzhiyun new_bus->parent = priv->device;
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun err = of_mdiobus_register(new_bus, mdio_node);
463*4882a593Smuzhiyun if (err != 0) {
464*4882a593Smuzhiyun dev_err(dev, "Cannot register the MDIO bus\n");
465*4882a593Smuzhiyun goto bus_register_fail;
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun /* Looks like we need a dummy read for XGMAC only and C45 PHYs */
469*4882a593Smuzhiyun if (priv->plat->has_xgmac)
470*4882a593Smuzhiyun stmmac_xgmac2_mdio_read(new_bus, 0, MII_ADDR_C45);
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun if (priv->plat->phy_node || mdio_node)
473*4882a593Smuzhiyun goto bus_register_done;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun found = 0;
476*4882a593Smuzhiyun for (addr = 0; addr < max_addr; addr++) {
477*4882a593Smuzhiyun struct phy_device *phydev = mdiobus_get_phy(new_bus, addr);
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun if (!phydev)
480*4882a593Smuzhiyun continue;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun /*
483*4882a593Smuzhiyun * If an IRQ was provided to be assigned after
484*4882a593Smuzhiyun * the bus probe, do it here.
485*4882a593Smuzhiyun */
486*4882a593Smuzhiyun if (!mdio_bus_data->irqs &&
487*4882a593Smuzhiyun (mdio_bus_data->probed_phy_irq > 0)) {
488*4882a593Smuzhiyun new_bus->irq[addr] = mdio_bus_data->probed_phy_irq;
489*4882a593Smuzhiyun phydev->irq = mdio_bus_data->probed_phy_irq;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun /*
493*4882a593Smuzhiyun * If we're going to bind the MAC to this PHY bus,
494*4882a593Smuzhiyun * and no PHY number was provided to the MAC,
495*4882a593Smuzhiyun * use the one probed here.
496*4882a593Smuzhiyun */
497*4882a593Smuzhiyun if (priv->plat->phy_addr == -1)
498*4882a593Smuzhiyun priv->plat->phy_addr = addr;
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun phy_attached_info(phydev);
501*4882a593Smuzhiyun found = 1;
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun if (!found && !mdio_node) {
505*4882a593Smuzhiyun dev_warn(dev, "No PHY found\n");
506*4882a593Smuzhiyun err = -ENODEV;
507*4882a593Smuzhiyun goto no_phy_found;
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun /* Try to probe the XPCS by scanning all addresses. */
511*4882a593Smuzhiyun if (priv->hw->xpcs) {
512*4882a593Smuzhiyun struct mdio_xpcs_args *xpcs = &priv->hw->xpcs_args;
513*4882a593Smuzhiyun int ret, mode = priv->plat->phy_interface;
514*4882a593Smuzhiyun max_addr = PHY_MAX_ADDR;
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun xpcs->bus = new_bus;
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun found = 0;
519*4882a593Smuzhiyun for (addr = 0; addr < max_addr; addr++) {
520*4882a593Smuzhiyun xpcs->addr = addr;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun ret = stmmac_xpcs_probe(priv, xpcs, mode);
523*4882a593Smuzhiyun if (!ret) {
524*4882a593Smuzhiyun found = 1;
525*4882a593Smuzhiyun break;
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun if (!found && !mdio_node) {
530*4882a593Smuzhiyun dev_warn(dev, "No XPCS found\n");
531*4882a593Smuzhiyun err = -ENODEV;
532*4882a593Smuzhiyun goto no_xpcs_found;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun bus_register_done:
537*4882a593Smuzhiyun priv->mii = new_bus;
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun return 0;
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun no_xpcs_found:
542*4882a593Smuzhiyun no_phy_found:
543*4882a593Smuzhiyun mdiobus_unregister(new_bus);
544*4882a593Smuzhiyun bus_register_fail:
545*4882a593Smuzhiyun mdiobus_free(new_bus);
546*4882a593Smuzhiyun return err;
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun /**
550*4882a593Smuzhiyun * stmmac_mdio_unregister
551*4882a593Smuzhiyun * @ndev: net device structure
552*4882a593Smuzhiyun * Description: it unregisters the MII bus
553*4882a593Smuzhiyun */
stmmac_mdio_unregister(struct net_device * ndev)554*4882a593Smuzhiyun int stmmac_mdio_unregister(struct net_device *ndev)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun struct stmmac_priv *priv = netdev_priv(ndev);
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun if (!priv->mii)
559*4882a593Smuzhiyun return 0;
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun mdiobus_unregister(priv->mii);
562*4882a593Smuzhiyun priv->mii->priv = NULL;
563*4882a593Smuzhiyun mdiobus_free(priv->mii);
564*4882a593Smuzhiyun priv->mii = NULL;
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun return 0;
567*4882a593Smuzhiyun }
568