14fa9c49fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
27ac6653aSJeff Kirsher /*******************************************************************************
37ac6653aSJeff Kirsher   STMMAC Ethernet Driver -- MDIO bus implementation
47ac6653aSJeff Kirsher   Provides Bus interface for MII registers
57ac6653aSJeff Kirsher 
67ac6653aSJeff Kirsher   Copyright (C) 2007-2009  STMicroelectronics Ltd
77ac6653aSJeff Kirsher 
87ac6653aSJeff Kirsher 
97ac6653aSJeff Kirsher   Author: Carl Shaw <carl.shaw@st.com>
107ac6653aSJeff Kirsher   Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
117ac6653aSJeff Kirsher *******************************************************************************/
127ac6653aSJeff Kirsher 
137c86f20dSMartin Blumenstingl #include <linux/gpio/consumer.h>
14bbf89284SLABBE Corentin #include <linux/io.h>
15a5f48adcSLABBE Corentin #include <linux/iopoll.h>
167ac6653aSJeff Kirsher #include <linux/mii.h>
17e34d6569SPhil Reid #include <linux/of_mdio.h>
185ec55823SJoakim Zhang #include <linux/pm_runtime.h>
19bbf89284SLABBE Corentin #include <linux/phy.h>
2042a90766SMartin Blumenstingl #include <linux/property.h>
21bbf89284SLABBE Corentin #include <linux/slab.h>
227ac6653aSJeff Kirsher 
236fc21117SJose Abreu #include "dwxgmac2.h"
247ac6653aSJeff Kirsher #include "stmmac.h"
257ac6653aSJeff Kirsher 
267ac6653aSJeff Kirsher #define MII_BUSY 0x00000001
277ac6653aSJeff Kirsher #define MII_WRITE 0x00000002
28d4117d63SKweh Hock Leong #define MII_DATA_MASK GENMASK(15, 0)
297ac6653aSJeff Kirsher 
30ac1f74a7SAlexandre TORGUE /* GMAC4 defines */
31ac1f74a7SAlexandre TORGUE #define MII_GMAC4_GOC_SHIFT		2
32d4117d63SKweh Hock Leong #define MII_GMAC4_REG_ADDR_SHIFT	16
33ac1f74a7SAlexandre TORGUE #define MII_GMAC4_WRITE			(1 << MII_GMAC4_GOC_SHIFT)
34ac1f74a7SAlexandre TORGUE #define MII_GMAC4_READ			(3 << MII_GMAC4_GOC_SHIFT)
35d4117d63SKweh Hock Leong #define MII_GMAC4_C45E			BIT(1)
36ac1f74a7SAlexandre TORGUE 
376fc21117SJose Abreu /* XGMAC defines */
386fc21117SJose Abreu #define MII_XGMAC_SADDR			BIT(18)
396fc21117SJose Abreu #define MII_XGMAC_CMD_SHIFT		16
406fc21117SJose Abreu #define MII_XGMAC_WRITE			(1 << MII_XGMAC_CMD_SHIFT)
416fc21117SJose Abreu #define MII_XGMAC_READ			(3 << MII_XGMAC_CMD_SHIFT)
426fc21117SJose Abreu #define MII_XGMAC_BUSY			BIT(22)
436fc21117SJose Abreu #define MII_XGMAC_MAX_C22ADDR		3
446fc21117SJose Abreu #define MII_XGMAC_C22P_MASK		GENMASK(MII_XGMAC_MAX_C22ADDR, 0)
4504d1190aSJose Abreu #define MII_XGMAC_PA_SHIFT		16
4604d1190aSJose Abreu #define MII_XGMAC_DA_SHIFT		21
4704d1190aSJose Abreu 
stmmac_xgmac2_c45_format(struct stmmac_priv * priv,int phyaddr,int devad,int phyreg,u32 * hw_addr)485b0a447eSAndrew Lunn static void stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr,
495b0a447eSAndrew Lunn 				     int devad, int phyreg, u32 *hw_addr)
5004d1190aSJose Abreu {
5104d1190aSJose Abreu 	u32 tmp;
5204d1190aSJose Abreu 
5304d1190aSJose Abreu 	/* Set port as Clause 45 */
5404d1190aSJose Abreu 	tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
5504d1190aSJose Abreu 	tmp &= ~BIT(phyaddr);
5604d1190aSJose Abreu 	writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P);
5704d1190aSJose Abreu 
5804d1190aSJose Abreu 	*hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0xffff);
595b0a447eSAndrew Lunn 	*hw_addr |= devad << MII_XGMAC_DA_SHIFT;
6004d1190aSJose Abreu }
616fc21117SJose Abreu 
stmmac_xgmac2_c22_format(struct stmmac_priv * priv,int phyaddr,int phyreg,u32 * hw_addr)625b0a447eSAndrew Lunn static void stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr,
636fc21117SJose Abreu 				     int phyreg, u32 *hw_addr)
646fc21117SJose Abreu {
6510857e67SRohan G Thomas 	u32 tmp = 0;
666fc21117SJose Abreu 
6710857e67SRohan G Thomas 	if (priv->synopsys_id < DWXGMAC_CORE_2_20) {
6810857e67SRohan G Thomas 		/* Until ver 2.20 XGMAC does not support C22 addr >= 4. Those
6910857e67SRohan G Thomas 		 * bits above bit 3 of XGMAC_MDIO_C22P register are reserved.
7010857e67SRohan G Thomas 		 */
716fc21117SJose Abreu 		tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
726fc21117SJose Abreu 		tmp &= ~MII_XGMAC_C22P_MASK;
7310857e67SRohan G Thomas 	}
7410857e67SRohan G Thomas 	/* Set port as Clause 22 */
756fc21117SJose Abreu 	tmp |= BIT(phyaddr);
766fc21117SJose Abreu 	writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P);
776fc21117SJose Abreu 
7804d1190aSJose Abreu 	*hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0x1f);
796fc21117SJose Abreu }
806fc21117SJose Abreu 
stmmac_xgmac2_mdio_read(struct stmmac_priv * priv,u32 addr,u32 value)815b0a447eSAndrew Lunn static int stmmac_xgmac2_mdio_read(struct stmmac_priv *priv, u32 addr,
825b0a447eSAndrew Lunn 				   u32 value)
836fc21117SJose Abreu {
846fc21117SJose Abreu 	unsigned int mii_address = priv->hw->mii.addr;
856fc21117SJose Abreu 	unsigned int mii_data = priv->hw->mii.data;
865b0a447eSAndrew Lunn 	u32 tmp;
876fc21117SJose Abreu 	int ret;
886fc21117SJose Abreu 
89e2d0acd4SMinghao Chi 	ret = pm_runtime_resume_and_get(priv->device);
90e2d0acd4SMinghao Chi 	if (ret < 0)
915ec55823SJoakim Zhang 		return ret;
925ec55823SJoakim Zhang 
9304d1190aSJose Abreu 	/* Wait until any existing MII operation is complete */
9404d1190aSJose Abreu 	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
955ec55823SJoakim Zhang 			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
965ec55823SJoakim Zhang 		ret = -EBUSY;
975ec55823SJoakim Zhang 		goto err_disable_clks;
985ec55823SJoakim Zhang 	}
9904d1190aSJose Abreu 
1006fc21117SJose Abreu 	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
1016fc21117SJose Abreu 		& priv->hw->mii.clk_csr_mask;
10204d1190aSJose Abreu 	value |= MII_XGMAC_READ;
1036fc21117SJose Abreu 
1046fc21117SJose Abreu 	/* Wait until any existing MII operation is complete */
1056fc21117SJose Abreu 	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
1065ec55823SJoakim Zhang 			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
1075ec55823SJoakim Zhang 		ret = -EBUSY;
1085ec55823SJoakim Zhang 		goto err_disable_clks;
1095ec55823SJoakim Zhang 	}
1106fc21117SJose Abreu 
1116fc21117SJose Abreu 	/* Set the MII address register to read */
1126fc21117SJose Abreu 	writel(addr, priv->ioaddr + mii_address);
1136fc21117SJose Abreu 	writel(value, priv->ioaddr + mii_data);
1146fc21117SJose Abreu 
1156fc21117SJose Abreu 	/* Wait until any existing MII operation is complete */
1166fc21117SJose Abreu 	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
1175ec55823SJoakim Zhang 			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
1185ec55823SJoakim Zhang 		ret = -EBUSY;
1195ec55823SJoakim Zhang 		goto err_disable_clks;
1205ec55823SJoakim Zhang 	}
1216fc21117SJose Abreu 
1226fc21117SJose Abreu 	/* Read the data from the MII data register */
1235ec55823SJoakim Zhang 	ret = (int)readl(priv->ioaddr + mii_data) & GENMASK(15, 0);
1245ec55823SJoakim Zhang 
1255ec55823SJoakim Zhang err_disable_clks:
1265ec55823SJoakim Zhang 	pm_runtime_put(priv->device);
1275ec55823SJoakim Zhang 
1285ec55823SJoakim Zhang 	return ret;
1296fc21117SJose Abreu }
1306fc21117SJose Abreu 
stmmac_xgmac2_mdio_read_c22(struct mii_bus * bus,int phyaddr,int phyreg)1315b0a447eSAndrew Lunn static int stmmac_xgmac2_mdio_read_c22(struct mii_bus *bus, int phyaddr,
1325b0a447eSAndrew Lunn 				       int phyreg)
1336fc21117SJose Abreu {
1346fc21117SJose Abreu 	struct net_device *ndev = bus->priv;
1355b0a447eSAndrew Lunn 	struct stmmac_priv *priv;
1365b0a447eSAndrew Lunn 	u32 addr;
1375b0a447eSAndrew Lunn 
1385b0a447eSAndrew Lunn 	priv = netdev_priv(ndev);
1395b0a447eSAndrew Lunn 
14010857e67SRohan G Thomas 	/* Until ver 2.20 XGMAC does not support C22 addr >= 4 */
14110857e67SRohan G Thomas 	if (priv->synopsys_id < DWXGMAC_CORE_2_20 &&
14210857e67SRohan G Thomas 	    phyaddr > MII_XGMAC_MAX_C22ADDR)
1435b0a447eSAndrew Lunn 		return -ENODEV;
1445b0a447eSAndrew Lunn 
1455b0a447eSAndrew Lunn 	stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
1465b0a447eSAndrew Lunn 
1475b0a447eSAndrew Lunn 	return stmmac_xgmac2_mdio_read(priv, addr, MII_XGMAC_BUSY);
1485b0a447eSAndrew Lunn }
1495b0a447eSAndrew Lunn 
stmmac_xgmac2_mdio_read_c45(struct mii_bus * bus,int phyaddr,int devad,int phyreg)1505b0a447eSAndrew Lunn static int stmmac_xgmac2_mdio_read_c45(struct mii_bus *bus, int phyaddr,
1515b0a447eSAndrew Lunn 				       int devad, int phyreg)
1525b0a447eSAndrew Lunn {
1535b0a447eSAndrew Lunn 	struct net_device *ndev = bus->priv;
1545b0a447eSAndrew Lunn 	struct stmmac_priv *priv;
1555b0a447eSAndrew Lunn 	u32 addr;
1565b0a447eSAndrew Lunn 
1575b0a447eSAndrew Lunn 	priv = netdev_priv(ndev);
1585b0a447eSAndrew Lunn 
1595b0a447eSAndrew Lunn 	stmmac_xgmac2_c45_format(priv, phyaddr, devad, phyreg, &addr);
1605b0a447eSAndrew Lunn 
1615b0a447eSAndrew Lunn 	return stmmac_xgmac2_mdio_read(priv, addr, MII_XGMAC_BUSY);
1625b0a447eSAndrew Lunn }
1635b0a447eSAndrew Lunn 
stmmac_xgmac2_mdio_write(struct stmmac_priv * priv,u32 addr,u32 value,u16 phydata)1645b0a447eSAndrew Lunn static int stmmac_xgmac2_mdio_write(struct stmmac_priv *priv, u32 addr,
1655b0a447eSAndrew Lunn 				    u32 value, u16 phydata)
1665b0a447eSAndrew Lunn {
1676fc21117SJose Abreu 	unsigned int mii_address = priv->hw->mii.addr;
1686fc21117SJose Abreu 	unsigned int mii_data = priv->hw->mii.data;
1695b0a447eSAndrew Lunn 	u32 tmp;
1706fc21117SJose Abreu 	int ret;
1716fc21117SJose Abreu 
172e2d0acd4SMinghao Chi 	ret = pm_runtime_resume_and_get(priv->device);
173e2d0acd4SMinghao Chi 	if (ret < 0)
1745ec55823SJoakim Zhang 		return ret;
1755ec55823SJoakim Zhang 
17604d1190aSJose Abreu 	/* Wait until any existing MII operation is complete */
17704d1190aSJose Abreu 	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
1785ec55823SJoakim Zhang 			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
1795ec55823SJoakim Zhang 		ret = -EBUSY;
1805ec55823SJoakim Zhang 		goto err_disable_clks;
1815ec55823SJoakim Zhang 	}
18204d1190aSJose Abreu 
1836fc21117SJose Abreu 	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
1846fc21117SJose Abreu 		& priv->hw->mii.clk_csr_mask;
18504d1190aSJose Abreu 	value |= phydata;
1866fc21117SJose Abreu 	value |= MII_XGMAC_WRITE;
1876fc21117SJose Abreu 
1886fc21117SJose Abreu 	/* Wait until any existing MII operation is complete */
1896fc21117SJose Abreu 	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
1905ec55823SJoakim Zhang 			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
1915ec55823SJoakim Zhang 		ret = -EBUSY;
1925ec55823SJoakim Zhang 		goto err_disable_clks;
1935ec55823SJoakim Zhang 	}
1946fc21117SJose Abreu 
1956fc21117SJose Abreu 	/* Set the MII address register to write */
1966fc21117SJose Abreu 	writel(addr, priv->ioaddr + mii_address);
1976fc21117SJose Abreu 	writel(value, priv->ioaddr + mii_data);
1986fc21117SJose Abreu 
1996fc21117SJose Abreu 	/* Wait until any existing MII operation is complete */
2005ec55823SJoakim Zhang 	ret = readl_poll_timeout(priv->ioaddr + mii_data, tmp,
2016fc21117SJose Abreu 				 !(tmp & MII_XGMAC_BUSY), 100, 10000);
2025ec55823SJoakim Zhang 
2035ec55823SJoakim Zhang err_disable_clks:
2045ec55823SJoakim Zhang 	pm_runtime_put(priv->device);
2055ec55823SJoakim Zhang 
2065ec55823SJoakim Zhang 	return ret;
2076fc21117SJose Abreu }
2086fc21117SJose Abreu 
stmmac_xgmac2_mdio_write_c22(struct mii_bus * bus,int phyaddr,int phyreg,u16 phydata)2095b0a447eSAndrew Lunn static int stmmac_xgmac2_mdio_write_c22(struct mii_bus *bus, int phyaddr,
2105b0a447eSAndrew Lunn 					int phyreg, u16 phydata)
2115b0a447eSAndrew Lunn {
2125b0a447eSAndrew Lunn 	struct net_device *ndev = bus->priv;
2135b0a447eSAndrew Lunn 	struct stmmac_priv *priv;
2145b0a447eSAndrew Lunn 	u32 addr;
2155b0a447eSAndrew Lunn 
2165b0a447eSAndrew Lunn 	priv = netdev_priv(ndev);
2175b0a447eSAndrew Lunn 
21810857e67SRohan G Thomas 	/* Until ver 2.20 XGMAC does not support C22 addr >= 4 */
21910857e67SRohan G Thomas 	if (priv->synopsys_id < DWXGMAC_CORE_2_20 &&
22010857e67SRohan G Thomas 	    phyaddr > MII_XGMAC_MAX_C22ADDR)
2215b0a447eSAndrew Lunn 		return -ENODEV;
2225b0a447eSAndrew Lunn 
2235b0a447eSAndrew Lunn 	stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
2245b0a447eSAndrew Lunn 
2255b0a447eSAndrew Lunn 	return stmmac_xgmac2_mdio_write(priv, addr,
2265b0a447eSAndrew Lunn 					MII_XGMAC_BUSY | MII_XGMAC_SADDR, phydata);
2275b0a447eSAndrew Lunn }
2285b0a447eSAndrew Lunn 
stmmac_xgmac2_mdio_write_c45(struct mii_bus * bus,int phyaddr,int devad,int phyreg,u16 phydata)2295b0a447eSAndrew Lunn static int stmmac_xgmac2_mdio_write_c45(struct mii_bus *bus, int phyaddr,
2305b0a447eSAndrew Lunn 					int devad, int phyreg, u16 phydata)
2315b0a447eSAndrew Lunn {
2325b0a447eSAndrew Lunn 	struct net_device *ndev = bus->priv;
2335b0a447eSAndrew Lunn 	struct stmmac_priv *priv;
2345b0a447eSAndrew Lunn 	u32 addr;
2355b0a447eSAndrew Lunn 
2365b0a447eSAndrew Lunn 	priv = netdev_priv(ndev);
2375b0a447eSAndrew Lunn 
2385b0a447eSAndrew Lunn 	stmmac_xgmac2_c45_format(priv, phyaddr, devad, phyreg, &addr);
2395b0a447eSAndrew Lunn 
2405b0a447eSAndrew Lunn 	return stmmac_xgmac2_mdio_write(priv, addr, MII_XGMAC_BUSY,
2415b0a447eSAndrew Lunn 					phydata);
2425b0a447eSAndrew Lunn }
2435b0a447eSAndrew Lunn 
stmmac_mdio_read(struct stmmac_priv * priv,int data,u32 value)2443c7826d0SAndrew Lunn static int stmmac_mdio_read(struct stmmac_priv *priv, int data, u32 value)
2453c7826d0SAndrew Lunn {
2463c7826d0SAndrew Lunn 	unsigned int mii_address = priv->hw->mii.addr;
2473c7826d0SAndrew Lunn 	unsigned int mii_data = priv->hw->mii.data;
2483c7826d0SAndrew Lunn 	u32 v;
2493c7826d0SAndrew Lunn 
2503c7826d0SAndrew Lunn 	if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
2513c7826d0SAndrew Lunn 			       100, 10000))
2523c7826d0SAndrew Lunn 		return -EBUSY;
2533c7826d0SAndrew Lunn 
2543c7826d0SAndrew Lunn 	writel(data, priv->ioaddr + mii_data);
2553c7826d0SAndrew Lunn 	writel(value, priv->ioaddr + mii_address);
2563c7826d0SAndrew Lunn 
2573c7826d0SAndrew Lunn 	if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
2583c7826d0SAndrew Lunn 			       100, 10000))
2593c7826d0SAndrew Lunn 		return -EBUSY;
2603c7826d0SAndrew Lunn 
2613c7826d0SAndrew Lunn 	/* Read the data from the MII data register */
2623c7826d0SAndrew Lunn 	return readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
2633c7826d0SAndrew Lunn }
2643c7826d0SAndrew Lunn 
2657ac6653aSJeff Kirsher /**
2663c7826d0SAndrew Lunn  * stmmac_mdio_read_c22
2677ac6653aSJeff Kirsher  * @bus: points to the mii_bus structure
268b91dce4cSLABBE Corentin  * @phyaddr: MII addr
269b91dce4cSLABBE Corentin  * @phyreg: MII reg
2707ac6653aSJeff Kirsher  * Description: it reads data from the MII register from within the phy device.
2717ac6653aSJeff Kirsher  * For the 7111 GMAC, we must set the bit 0 in the MII address register while
2727ac6653aSJeff Kirsher  * accessing the PHY registers.
2737ac6653aSJeff Kirsher  * Fortunately, it seems this has no drawback for the 7109 MAC.
2747ac6653aSJeff Kirsher  */
stmmac_mdio_read_c22(struct mii_bus * bus,int phyaddr,int phyreg)2753c7826d0SAndrew Lunn static int stmmac_mdio_read_c22(struct mii_bus *bus, int phyaddr, int phyreg)
2767ac6653aSJeff Kirsher {
2777ac6653aSJeff Kirsher 	struct net_device *ndev = bus->priv;
2787ac6653aSJeff Kirsher 	struct stmmac_priv *priv = netdev_priv(ndev);
279b91dce4cSLABBE Corentin 	u32 value = MII_BUSY;
280d4117d63SKweh Hock Leong 	int data = 0;
281b91dce4cSLABBE Corentin 
282e2d0acd4SMinghao Chi 	data = pm_runtime_resume_and_get(priv->device);
283e2d0acd4SMinghao Chi 	if (data < 0)
2845ec55823SJoakim Zhang 		return data;
2855ec55823SJoakim Zhang 
286b91dce4cSLABBE Corentin 	value |= (phyaddr << priv->hw->mii.addr_shift)
287b91dce4cSLABBE Corentin 		& priv->hw->mii.addr_mask;
288b91dce4cSLABBE Corentin 	value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
289567be786Sjpinto 	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
290567be786Sjpinto 		& priv->hw->mii.clk_csr_mask;
2917c6b942bSAndrew Halaney 	if (priv->plat->has_gmac4)
292b91dce4cSLABBE Corentin 		value |= MII_GMAC4_READ;
2937ac6653aSJeff Kirsher 
2943c7826d0SAndrew Lunn 	data = stmmac_mdio_read(priv, data, value);
29539b401dbSDeepak SIKRI 
2965ec55823SJoakim Zhang 	pm_runtime_put(priv->device);
2975ec55823SJoakim Zhang 
2987ac6653aSJeff Kirsher 	return data;
2997ac6653aSJeff Kirsher }
3007ac6653aSJeff Kirsher 
3017ac6653aSJeff Kirsher /**
3023c7826d0SAndrew Lunn  * stmmac_mdio_read_c45
3033c7826d0SAndrew Lunn  * @bus: points to the mii_bus structure
3043c7826d0SAndrew Lunn  * @phyaddr: MII addr
3053c7826d0SAndrew Lunn  * @devad: device address to read
3063c7826d0SAndrew Lunn  * @phyreg: MII reg
3073c7826d0SAndrew Lunn  * Description: it reads data from the MII register from within the phy device.
3083c7826d0SAndrew Lunn  * For the 7111 GMAC, we must set the bit 0 in the MII address register while
3093c7826d0SAndrew Lunn  * accessing the PHY registers.
3103c7826d0SAndrew Lunn  * Fortunately, it seems this has no drawback for the 7109 MAC.
3113c7826d0SAndrew Lunn  */
stmmac_mdio_read_c45(struct mii_bus * bus,int phyaddr,int devad,int phyreg)3123c7826d0SAndrew Lunn static int stmmac_mdio_read_c45(struct mii_bus *bus, int phyaddr, int devad,
3133c7826d0SAndrew Lunn 				int phyreg)
3143c7826d0SAndrew Lunn {
3153c7826d0SAndrew Lunn 	struct net_device *ndev = bus->priv;
3163c7826d0SAndrew Lunn 	struct stmmac_priv *priv = netdev_priv(ndev);
3173c7826d0SAndrew Lunn 	u32 value = MII_BUSY;
3183c7826d0SAndrew Lunn 	int data = 0;
3193c7826d0SAndrew Lunn 
3203c7826d0SAndrew Lunn 	data = pm_runtime_get_sync(priv->device);
3213c7826d0SAndrew Lunn 	if (data < 0) {
3223c7826d0SAndrew Lunn 		pm_runtime_put_noidle(priv->device);
3233c7826d0SAndrew Lunn 		return data;
3243c7826d0SAndrew Lunn 	}
3253c7826d0SAndrew Lunn 
3263c7826d0SAndrew Lunn 	value |= (phyaddr << priv->hw->mii.addr_shift)
3273c7826d0SAndrew Lunn 		& priv->hw->mii.addr_mask;
3283c7826d0SAndrew Lunn 	value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
3293c7826d0SAndrew Lunn 	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
3303c7826d0SAndrew Lunn 		& priv->hw->mii.clk_csr_mask;
3313c7826d0SAndrew Lunn 	value |= MII_GMAC4_READ;
3323c7826d0SAndrew Lunn 	value |= MII_GMAC4_C45E;
3333c7826d0SAndrew Lunn 	value &= ~priv->hw->mii.reg_mask;
3343c7826d0SAndrew Lunn 	value |= (devad << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
3353c7826d0SAndrew Lunn 
3363c7826d0SAndrew Lunn 	data |= phyreg << MII_GMAC4_REG_ADDR_SHIFT;
3373c7826d0SAndrew Lunn 
3383c7826d0SAndrew Lunn 	data = stmmac_mdio_read(priv, data, value);
3393c7826d0SAndrew Lunn 
3403c7826d0SAndrew Lunn 	pm_runtime_put(priv->device);
3413c7826d0SAndrew Lunn 
3423c7826d0SAndrew Lunn 	return data;
3433c7826d0SAndrew Lunn }
3443c7826d0SAndrew Lunn 
stmmac_mdio_write(struct stmmac_priv * priv,int data,u32 value)3453c7826d0SAndrew Lunn static int stmmac_mdio_write(struct stmmac_priv *priv, int data, u32 value)
3463c7826d0SAndrew Lunn {
3473c7826d0SAndrew Lunn 	unsigned int mii_address = priv->hw->mii.addr;
3483c7826d0SAndrew Lunn 	unsigned int mii_data = priv->hw->mii.data;
3493c7826d0SAndrew Lunn 	u32 v;
3503c7826d0SAndrew Lunn 
3513c7826d0SAndrew Lunn 	/* Wait until any existing MII operation is complete */
3523c7826d0SAndrew Lunn 	if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
3533c7826d0SAndrew Lunn 			       100, 10000))
3543c7826d0SAndrew Lunn 		return -EBUSY;
3553c7826d0SAndrew Lunn 
3563c7826d0SAndrew Lunn 	/* Set the MII address register to write */
3573c7826d0SAndrew Lunn 	writel(data, priv->ioaddr + mii_data);
3583c7826d0SAndrew Lunn 	writel(value, priv->ioaddr + mii_address);
3593c7826d0SAndrew Lunn 
3603c7826d0SAndrew Lunn 	/* Wait until any existing MII operation is complete */
3613c7826d0SAndrew Lunn 	return readl_poll_timeout(priv->ioaddr + mii_address, v,
3623c7826d0SAndrew Lunn 				  !(v & MII_BUSY), 100, 10000);
3633c7826d0SAndrew Lunn }
3643c7826d0SAndrew Lunn 
3653c7826d0SAndrew Lunn /**
3663c7826d0SAndrew Lunn  * stmmac_mdio_write_c22
3677ac6653aSJeff Kirsher  * @bus: points to the mii_bus structure
368b91dce4cSLABBE Corentin  * @phyaddr: MII addr
369b91dce4cSLABBE Corentin  * @phyreg: MII reg
3707ac6653aSJeff Kirsher  * @phydata: phy data
3717ac6653aSJeff Kirsher  * Description: it writes the data into the MII register from within the device.
3727ac6653aSJeff Kirsher  */
stmmac_mdio_write_c22(struct mii_bus * bus,int phyaddr,int phyreg,u16 phydata)3733c7826d0SAndrew Lunn static int stmmac_mdio_write_c22(struct mii_bus *bus, int phyaddr, int phyreg,
3747ac6653aSJeff Kirsher 				 u16 phydata)
3757ac6653aSJeff Kirsher {
3767ac6653aSJeff Kirsher 	struct net_device *ndev = bus->priv;
3777ac6653aSJeff Kirsher 	struct stmmac_priv *priv = netdev_priv(ndev);
3785ec55823SJoakim Zhang 	int ret, data = phydata;
3795799fc90SKweh, Hock Leong 	u32 value = MII_BUSY;
3807ac6653aSJeff Kirsher 
381e2d0acd4SMinghao Chi 	ret = pm_runtime_resume_and_get(priv->device);
382e2d0acd4SMinghao Chi 	if (ret < 0)
3835ec55823SJoakim Zhang 		return ret;
3845ec55823SJoakim Zhang 
385b91dce4cSLABBE Corentin 	value |= (phyaddr << priv->hw->mii.addr_shift)
386b91dce4cSLABBE Corentin 		& priv->hw->mii.addr_mask;
387b91dce4cSLABBE Corentin 	value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
3887ac6653aSJeff Kirsher 
389567be786Sjpinto 	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
390567be786Sjpinto 		& priv->hw->mii.clk_csr_mask;
3913c7826d0SAndrew Lunn 	if (priv->plat->has_gmac4)
392b91dce4cSLABBE Corentin 		value |= MII_GMAC4_WRITE;
3933c7826d0SAndrew Lunn 	else
3943c7826d0SAndrew Lunn 		value |= MII_WRITE;
3953c7826d0SAndrew Lunn 
3963c7826d0SAndrew Lunn 	ret = stmmac_mdio_write(priv, data, value);
3973c7826d0SAndrew Lunn 
3983c7826d0SAndrew Lunn 	pm_runtime_put(priv->device);
3993c7826d0SAndrew Lunn 
4003c7826d0SAndrew Lunn 	return ret;
4013c7826d0SAndrew Lunn }
4023c7826d0SAndrew Lunn 
4033c7826d0SAndrew Lunn /**
4043c7826d0SAndrew Lunn  * stmmac_mdio_write_c45
4053c7826d0SAndrew Lunn  * @bus: points to the mii_bus structure
4063c7826d0SAndrew Lunn  * @phyaddr: MII addr
4073c7826d0SAndrew Lunn  * @phyreg: MII reg
4083c7826d0SAndrew Lunn  * @devad: device address to read
4093c7826d0SAndrew Lunn  * @phydata: phy data
4103c7826d0SAndrew Lunn  * Description: it writes the data into the MII register from within the device.
4113c7826d0SAndrew Lunn  */
stmmac_mdio_write_c45(struct mii_bus * bus,int phyaddr,int devad,int phyreg,u16 phydata)4123c7826d0SAndrew Lunn static int stmmac_mdio_write_c45(struct mii_bus *bus, int phyaddr,
4133c7826d0SAndrew Lunn 				 int devad, int phyreg, u16 phydata)
4143c7826d0SAndrew Lunn {
4153c7826d0SAndrew Lunn 	struct net_device *ndev = bus->priv;
4163c7826d0SAndrew Lunn 	struct stmmac_priv *priv = netdev_priv(ndev);
4173c7826d0SAndrew Lunn 	int ret, data = phydata;
4183c7826d0SAndrew Lunn 	u32 value = MII_BUSY;
4193c7826d0SAndrew Lunn 
4203c7826d0SAndrew Lunn 	ret = pm_runtime_get_sync(priv->device);
4213c7826d0SAndrew Lunn 	if (ret < 0) {
4223c7826d0SAndrew Lunn 		pm_runtime_put_noidle(priv->device);
4233c7826d0SAndrew Lunn 		return ret;
4243c7826d0SAndrew Lunn 	}
4253c7826d0SAndrew Lunn 
4263c7826d0SAndrew Lunn 	value |= (phyaddr << priv->hw->mii.addr_shift)
4273c7826d0SAndrew Lunn 		& priv->hw->mii.addr_mask;
4283c7826d0SAndrew Lunn 	value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
4293c7826d0SAndrew Lunn 
4303c7826d0SAndrew Lunn 	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
4313c7826d0SAndrew Lunn 		& priv->hw->mii.clk_csr_mask;
4323c7826d0SAndrew Lunn 
4333c7826d0SAndrew Lunn 	value |= MII_GMAC4_WRITE;
434d4117d63SKweh Hock Leong 	value |= MII_GMAC4_C45E;
435d4117d63SKweh Hock Leong 	value &= ~priv->hw->mii.reg_mask;
4363c7826d0SAndrew Lunn 	value |= (devad << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
437d4117d63SKweh Hock Leong 
4383c7826d0SAndrew Lunn 	data |= phyreg << MII_GMAC4_REG_ADDR_SHIFT;
439ac1f74a7SAlexandre TORGUE 
4403c7826d0SAndrew Lunn 	ret = stmmac_mdio_write(priv, data, value);
441ac1f74a7SAlexandre TORGUE 
4425ec55823SJoakim Zhang 	pm_runtime_put(priv->device);
4435ec55823SJoakim Zhang 
4445ec55823SJoakim Zhang 	return ret;
445ac1f74a7SAlexandre TORGUE }
446ac1f74a7SAlexandre TORGUE 
447ac1f74a7SAlexandre TORGUE /**
4487ac6653aSJeff Kirsher  * stmmac_mdio_reset
4497ac6653aSJeff Kirsher  * @bus: points to the mii_bus structure
4507ac6653aSJeff Kirsher  * Description: reset the MII bus
4517ac6653aSJeff Kirsher  */
stmmac_mdio_reset(struct mii_bus * bus)452073752aaSSrinivas Kandagatla int stmmac_mdio_reset(struct mii_bus *bus)
4537ac6653aSJeff Kirsher {
45430549aabSNiklas Cassel #if IS_ENABLED(CONFIG_STMMAC_PLATFORM)
4557ac6653aSJeff Kirsher 	struct net_device *ndev = bus->priv;
4567ac6653aSJeff Kirsher 	struct stmmac_priv *priv = netdev_priv(ndev);
4577ac6653aSJeff Kirsher 	unsigned int mii_address = priv->hw->mii.addr;
4587ac6653aSJeff Kirsher 
4590e076471SSrinivas Kandagatla #ifdef CONFIG_OF
4600e076471SSrinivas Kandagatla 	if (priv->device->of_node) {
4617c86f20dSMartin Blumenstingl 		struct gpio_desc *reset_gpio;
46284ce4d0fSMartin Blumenstingl 		u32 delays[3] = { 0, 0, 0 };
4637c86f20dSMartin Blumenstingl 
4647c86f20dSMartin Blumenstingl 		reset_gpio = devm_gpiod_get_optional(priv->device,
4657c86f20dSMartin Blumenstingl 						     "snps,reset",
4667c86f20dSMartin Blumenstingl 						     GPIOD_OUT_LOW);
4677c86f20dSMartin Blumenstingl 		if (IS_ERR(reset_gpio))
4687c86f20dSMartin Blumenstingl 			return PTR_ERR(reset_gpio);
4690e076471SSrinivas Kandagatla 
470cc5e92c2SMartin Blumenstingl 		device_property_read_u32_array(priv->device,
47142a90766SMartin Blumenstingl 					       "snps,reset-delays-us",
472cc5e92c2SMartin Blumenstingl 					       delays, ARRAY_SIZE(delays));
4730e076471SSrinivas Kandagatla 
474ce4ab73aSMartin Blumenstingl 		if (delays[0])
475ce4ab73aSMartin Blumenstingl 			msleep(DIV_ROUND_UP(delays[0], 1000));
476892aa01dSSjoerd Simons 
4777c86f20dSMartin Blumenstingl 		gpiod_set_value_cansleep(reset_gpio, 1);
478ce4ab73aSMartin Blumenstingl 		if (delays[1])
479ce4ab73aSMartin Blumenstingl 			msleep(DIV_ROUND_UP(delays[1], 1000));
480892aa01dSSjoerd Simons 
4817c86f20dSMartin Blumenstingl 		gpiod_set_value_cansleep(reset_gpio, 0);
482ce4ab73aSMartin Blumenstingl 		if (delays[2])
483ce4ab73aSMartin Blumenstingl 			msleep(DIV_ROUND_UP(delays[2], 1000));
4840e076471SSrinivas Kandagatla 	}
4850e076471SSrinivas Kandagatla #endif
4860e076471SSrinivas Kandagatla 
4877ac6653aSJeff Kirsher 	/* This is a workaround for problems with the STE101P PHY.
4887ac6653aSJeff Kirsher 	 * It doesn't complete its reset until at least one clock cycle
4898d45e42bSLABBE Corentin 	 * on MDC, so perform a dummy mdio read. To be updated for GMAC4
490ac1f74a7SAlexandre TORGUE 	 * if needed.
4917ac6653aSJeff Kirsher 	 */
492ac1f74a7SAlexandre TORGUE 	if (!priv->plat->has_gmac4)
4937ac6653aSJeff Kirsher 		writel(0, priv->ioaddr + mii_address);
494bfab27a1SGiuseppe CAVALLARO #endif
4957ac6653aSJeff Kirsher 	return 0;
4967ac6653aSJeff Kirsher }
4977ac6653aSJeff Kirsher 
stmmac_xpcs_setup(struct mii_bus * bus)498597a68ceSVoon Weifeng int stmmac_xpcs_setup(struct mii_bus *bus)
499597a68ceSVoon Weifeng {
500597a68ceSVoon Weifeng 	struct net_device *ndev = bus->priv;
50147538dbeSVladimir Oltean 	struct stmmac_priv *priv;
50247538dbeSVladimir Oltean 	struct dw_xpcs *xpcs;
50347538dbeSVladimir Oltean 	int mode, addr;
504597a68ceSVoon Weifeng 
505597a68ceSVoon Weifeng 	priv = netdev_priv(ndev);
506597a68ceSVoon Weifeng 	mode = priv->plat->phy_interface;
507597a68ceSVoon Weifeng 
508597a68ceSVoon Weifeng 	/* Try to probe the XPCS by scanning all addresses. */
509597a68ceSVoon Weifeng 	for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
510727e373fSRussell King (Oracle) 		xpcs = xpcs_create_mdiodev(bus, addr, mode);
511727e373fSRussell King (Oracle) 		if (IS_ERR(xpcs))
512597a68ceSVoon Weifeng 			continue;
513597a68ceSVoon Weifeng 
514597a68ceSVoon Weifeng 		priv->hw->xpcs = xpcs;
515597a68ceSVoon Weifeng 		break;
516597a68ceSVoon Weifeng 	}
517597a68ceSVoon Weifeng 
518597a68ceSVoon Weifeng 	if (!priv->hw->xpcs) {
519597a68ceSVoon Weifeng 		dev_warn(priv->device, "No xPCS found\n");
520597a68ceSVoon Weifeng 		return -ENODEV;
521597a68ceSVoon Weifeng 	}
522597a68ceSVoon Weifeng 
523597a68ceSVoon Weifeng 	return 0;
524597a68ceSVoon Weifeng }
525597a68ceSVoon Weifeng 
5267ac6653aSJeff Kirsher /**
5277ac6653aSJeff Kirsher  * stmmac_mdio_register
5287ac6653aSJeff Kirsher  * @ndev: net device structure
5297ac6653aSJeff Kirsher  * Description: it registers the MII bus
5307ac6653aSJeff Kirsher  */
stmmac_mdio_register(struct net_device * ndev)5317ac6653aSJeff Kirsher int stmmac_mdio_register(struct net_device *ndev)
5327ac6653aSJeff Kirsher {
5337ac6653aSJeff Kirsher 	int err = 0;
5347ac6653aSJeff Kirsher 	struct mii_bus *new_bus;
5357ac6653aSJeff Kirsher 	struct stmmac_priv *priv = netdev_priv(ndev);
5367ac6653aSJeff Kirsher 	struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
537a7657f12SGiuseppe CAVALLARO 	struct device_node *mdio_node = priv->plat->mdio_node;
538fbca1647SRomain Perier 	struct device *dev = ndev->dev.parent;
539ab21cf92SOng Boon Leong 	struct fwnode_handle *fixed_node;
540e80af2acSRussell King (Oracle) 	struct fwnode_handle *fwnode;
5416fc21117SJose Abreu 	int addr, found, max_addr;
5427ac6653aSJeff Kirsher 
5437ac6653aSJeff Kirsher 	if (!mdio_bus_data)
5447ac6653aSJeff Kirsher 		return 0;
5457ac6653aSJeff Kirsher 
5467ac6653aSJeff Kirsher 	new_bus = mdiobus_alloc();
547efd89b60SLABBE Corentin 	if (!new_bus)
5487ac6653aSJeff Kirsher 		return -ENOMEM;
5497ac6653aSJeff Kirsher 
550e7f4dc35SAndrew Lunn 	if (mdio_bus_data->irqs)
551643d60bfSMarek Vasut 		memcpy(new_bus->irq, mdio_bus_data->irqs, sizeof(new_bus->irq));
5527ac6653aSJeff Kirsher 
55390b9a545SAlessandro Rubini 	new_bus->name = "stmmac";
5546fc21117SJose Abreu 
5556fc21117SJose Abreu 	if (priv->plat->has_xgmac) {
5565b0a447eSAndrew Lunn 		new_bus->read = &stmmac_xgmac2_mdio_read_c22;
5575b0a447eSAndrew Lunn 		new_bus->write = &stmmac_xgmac2_mdio_write_c22;
5585b0a447eSAndrew Lunn 		new_bus->read_c45 = &stmmac_xgmac2_mdio_read_c45;
5595b0a447eSAndrew Lunn 		new_bus->write_c45 = &stmmac_xgmac2_mdio_write_c45;
5606fc21117SJose Abreu 
56110857e67SRohan G Thomas 		if (priv->synopsys_id < DWXGMAC_CORE_2_20) {
5626fc21117SJose Abreu 			/* Right now only C22 phys are supported */
5636fc21117SJose Abreu 			max_addr = MII_XGMAC_MAX_C22ADDR + 1;
5646fc21117SJose Abreu 
5656fc21117SJose Abreu 			/* Check if DT specified an unsupported phy addr */
5666fc21117SJose Abreu 			if (priv->plat->phy_addr > MII_XGMAC_MAX_C22ADDR)
5676fc21117SJose Abreu 				dev_err(dev, "Unsupported phy_addr (max=%d)\n",
5686fc21117SJose Abreu 					MII_XGMAC_MAX_C22ADDR);
5696fc21117SJose Abreu 		} else {
57010857e67SRohan G Thomas 			/* XGMAC version 2.20 onwards support 32 phy addr */
57110857e67SRohan G Thomas 			max_addr = PHY_MAX_ADDR;
57210857e67SRohan G Thomas 		}
57310857e67SRohan G Thomas 	} else {
5743c7826d0SAndrew Lunn 		new_bus->read = &stmmac_mdio_read_c22;
5753c7826d0SAndrew Lunn 		new_bus->write = &stmmac_mdio_write_c22;
5763c7826d0SAndrew Lunn 		if (priv->plat->has_gmac4) {
5773c7826d0SAndrew Lunn 			new_bus->read_c45 = &stmmac_mdio_read_c45;
5783c7826d0SAndrew Lunn 			new_bus->write_c45 = &stmmac_mdio_write_c45;
5793c7826d0SAndrew Lunn 		}
5803c7826d0SAndrew Lunn 
5816fc21117SJose Abreu 		max_addr = PHY_MAX_ADDR;
5826fc21117SJose Abreu 	}
583ac1f74a7SAlexandre TORGUE 
5841a981c05SThierry Reding 	if (mdio_bus_data->needs_reset)
5857ac6653aSJeff Kirsher 		new_bus->reset = &stmmac_mdio_reset;
5861a981c05SThierry Reding 
587db8857bfSFlorian Fainelli 	snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x",
588d56631a6SSrinivas Kandagatla 		 new_bus->name, priv->plat->bus_id);
5897ac6653aSJeff Kirsher 	new_bus->priv = ndev;
5907ac6653aSJeff Kirsher 	new_bus->phy_mask = mdio_bus_data->phy_mask;
5917ac6653aSJeff Kirsher 	new_bus->parent = priv->device;
592e34d6569SPhil Reid 
593e34d6569SPhil Reid 	err = of_mdiobus_register(new_bus, mdio_node);
594*58c55666SAndrew Halaney 	if (err == -ENODEV) {
595*58c55666SAndrew Halaney 		err = 0;
596*58c55666SAndrew Halaney 		dev_info(dev, "MDIO bus is disabled\n");
597*58c55666SAndrew Halaney 		goto bus_register_fail;
598*58c55666SAndrew Halaney 	} else if (err) {
599839612d2SRasmus Villemoes 		dev_err_probe(dev, err, "Cannot register the MDIO bus\n");
6007ac6653aSJeff Kirsher 		goto bus_register_fail;
6017ac6653aSJeff Kirsher 	}
6027ac6653aSJeff Kirsher 
60304d1190aSJose Abreu 	/* Looks like we need a dummy read for XGMAC only and C45 PHYs */
60404d1190aSJose Abreu 	if (priv->plat->has_xgmac)
6055b0a447eSAndrew Lunn 		stmmac_xgmac2_mdio_read_c45(new_bus, 0, 0, 0);
60604d1190aSJose Abreu 
607ab21cf92SOng Boon Leong 	/* If fixed-link is set, skip PHY scanning */
608e80af2acSRussell King (Oracle) 	fwnode = priv->plat->port_node;
609ab21cf92SOng Boon Leong 	if (!fwnode)
610ab21cf92SOng Boon Leong 		fwnode = dev_fwnode(priv->device);
611ab21cf92SOng Boon Leong 
612ab21cf92SOng Boon Leong 	if (fwnode) {
613ab21cf92SOng Boon Leong 		fixed_node = fwnode_get_named_child_node(fwnode, "fixed-link");
614ab21cf92SOng Boon Leong 		if (fixed_node) {
615ab21cf92SOng Boon Leong 			fwnode_handle_put(fixed_node);
616ab21cf92SOng Boon Leong 			goto bus_register_done;
617ab21cf92SOng Boon Leong 		}
618ab21cf92SOng Boon Leong 	}
619ab21cf92SOng Boon Leong 
620cc2fa619SPhil Reid 	if (priv->plat->phy_node || mdio_node)
621cc2fa619SPhil Reid 		goto bus_register_done;
622cc2fa619SPhil Reid 
6237ac6653aSJeff Kirsher 	found = 0;
6246fc21117SJose Abreu 	for (addr = 0; addr < max_addr; addr++) {
6257f854420SAndrew Lunn 		struct phy_device *phydev = mdiobus_get_phy(new_bus, addr);
6267ac6653aSJeff Kirsher 
627cc26dc67SLABBE Corentin 		if (!phydev)
628cc26dc67SLABBE Corentin 			continue;
629cc26dc67SLABBE Corentin 
6307ac6653aSJeff Kirsher 		/*
6317ac6653aSJeff Kirsher 		 * If an IRQ was provided to be assigned after
6327ac6653aSJeff Kirsher 		 * the bus probe, do it here.
6337ac6653aSJeff Kirsher 		 */
634cb2c0aceSLABBE Corentin 		if (!mdio_bus_data->irqs &&
6357ac6653aSJeff Kirsher 		    (mdio_bus_data->probed_phy_irq > 0)) {
636cc26dc67SLABBE Corentin 			new_bus->irq[addr] = mdio_bus_data->probed_phy_irq;
6377ac6653aSJeff Kirsher 			phydev->irq = mdio_bus_data->probed_phy_irq;
6387ac6653aSJeff Kirsher 		}
6397ac6653aSJeff Kirsher 
6407ac6653aSJeff Kirsher 		/*
6417ac6653aSJeff Kirsher 		 * If we're going to bind the MAC to this PHY bus,
6427ac6653aSJeff Kirsher 		 * and no PHY number was provided to the MAC,
6437ac6653aSJeff Kirsher 		 * use the one probed here.
6447ac6653aSJeff Kirsher 		 */
645d56631a6SSrinivas Kandagatla 		if (priv->plat->phy_addr == -1)
6467ac6653aSJeff Kirsher 			priv->plat->phy_addr = addr;
6477ac6653aSJeff Kirsher 
648fbca1647SRomain Perier 		phy_attached_info(phydev);
6497ac6653aSJeff Kirsher 		found = 1;
6507ac6653aSJeff Kirsher 	}
6517ac6653aSJeff Kirsher 
6524751d2aaSVladimir Oltean 	if (!found && !mdio_node) {
6534751d2aaSVladimir Oltean 		dev_warn(dev, "No PHY found\n");
6544751d2aaSVladimir Oltean 		err = -ENODEV;
6554751d2aaSVladimir Oltean 		goto no_phy_found;
6564751d2aaSVladimir Oltean 	}
6574751d2aaSVladimir Oltean 
658cc2fa619SPhil Reid bus_register_done:
6593955b22bSGiuseppe CAVALLARO 	priv->mii = new_bus;
6607ac6653aSJeff Kirsher 
6617ac6653aSJeff Kirsher 	return 0;
6627ac6653aSJeff Kirsher 
6634751d2aaSVladimir Oltean no_phy_found:
6644751d2aaSVladimir Oltean 	mdiobus_unregister(new_bus);
6657ac6653aSJeff Kirsher bus_register_fail:
6667ac6653aSJeff Kirsher 	mdiobus_free(new_bus);
6677ac6653aSJeff Kirsher 	return err;
6687ac6653aSJeff Kirsher }
6697ac6653aSJeff Kirsher 
6707ac6653aSJeff Kirsher /**
6717ac6653aSJeff Kirsher  * stmmac_mdio_unregister
6727ac6653aSJeff Kirsher  * @ndev: net device structure
6737ac6653aSJeff Kirsher  * Description: it unregisters the MII bus
6747ac6653aSJeff Kirsher  */
stmmac_mdio_unregister(struct net_device * ndev)6757ac6653aSJeff Kirsher int stmmac_mdio_unregister(struct net_device *ndev)
6767ac6653aSJeff Kirsher {
6777ac6653aSJeff Kirsher 	struct stmmac_priv *priv = netdev_priv(ndev);
6787ac6653aSJeff Kirsher 
679a5cf5ce9SSrinivas Kandagatla 	if (!priv->mii)
680a5cf5ce9SSrinivas Kandagatla 		return 0;
681a5cf5ce9SSrinivas Kandagatla 
682727e373fSRussell King (Oracle) 	if (priv->hw->xpcs)
68311059740SVladimir Oltean 		xpcs_destroy(priv->hw->xpcs);
6842cac15daSVladimir Oltean 
6857ac6653aSJeff Kirsher 	mdiobus_unregister(priv->mii);
6867ac6653aSJeff Kirsher 	priv->mii->priv = NULL;
6877ac6653aSJeff Kirsher 	mdiobus_free(priv->mii);
6887ac6653aSJeff Kirsher 	priv->mii = NULL;
6897ac6653aSJeff Kirsher 
6907ac6653aSJeff Kirsher 	return 0;
6917ac6653aSJeff Kirsher }
692