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 
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 
625b0a447eSAndrew Lunn static void stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr,
636fc21117SJose Abreu 				     int phyreg, u32 *hw_addr)
646fc21117SJose Abreu {
656fc21117SJose Abreu 	u32 tmp;
666fc21117SJose Abreu 
676fc21117SJose Abreu 	/* Set port as Clause 22 */
686fc21117SJose Abreu 	tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P);
696fc21117SJose Abreu 	tmp &= ~MII_XGMAC_C22P_MASK;
706fc21117SJose Abreu 	tmp |= BIT(phyaddr);
716fc21117SJose Abreu 	writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P);
726fc21117SJose Abreu 
7304d1190aSJose Abreu 	*hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0x1f);
746fc21117SJose Abreu }
756fc21117SJose Abreu 
765b0a447eSAndrew Lunn static int stmmac_xgmac2_mdio_read(struct stmmac_priv *priv, u32 addr,
775b0a447eSAndrew Lunn 				   u32 value)
786fc21117SJose Abreu {
796fc21117SJose Abreu 	unsigned int mii_address = priv->hw->mii.addr;
806fc21117SJose Abreu 	unsigned int mii_data = priv->hw->mii.data;
815b0a447eSAndrew Lunn 	u32 tmp;
826fc21117SJose Abreu 	int ret;
836fc21117SJose Abreu 
84e2d0acd4SMinghao Chi 	ret = pm_runtime_resume_and_get(priv->device);
85e2d0acd4SMinghao Chi 	if (ret < 0)
865ec55823SJoakim Zhang 		return ret;
875ec55823SJoakim Zhang 
8804d1190aSJose Abreu 	/* Wait until any existing MII operation is complete */
8904d1190aSJose Abreu 	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
905ec55823SJoakim Zhang 			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
915ec55823SJoakim Zhang 		ret = -EBUSY;
925ec55823SJoakim Zhang 		goto err_disable_clks;
935ec55823SJoakim Zhang 	}
9404d1190aSJose Abreu 
956fc21117SJose Abreu 	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
966fc21117SJose Abreu 		& priv->hw->mii.clk_csr_mask;
9704d1190aSJose Abreu 	value |= MII_XGMAC_READ;
986fc21117SJose Abreu 
996fc21117SJose Abreu 	/* Wait until any existing MII operation is complete */
1006fc21117SJose Abreu 	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
1015ec55823SJoakim Zhang 			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
1025ec55823SJoakim Zhang 		ret = -EBUSY;
1035ec55823SJoakim Zhang 		goto err_disable_clks;
1045ec55823SJoakim Zhang 	}
1056fc21117SJose Abreu 
1066fc21117SJose Abreu 	/* Set the MII address register to read */
1076fc21117SJose Abreu 	writel(addr, priv->ioaddr + mii_address);
1086fc21117SJose Abreu 	writel(value, priv->ioaddr + mii_data);
1096fc21117SJose Abreu 
1106fc21117SJose Abreu 	/* Wait until any existing MII operation is complete */
1116fc21117SJose Abreu 	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
1125ec55823SJoakim Zhang 			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
1135ec55823SJoakim Zhang 		ret = -EBUSY;
1145ec55823SJoakim Zhang 		goto err_disable_clks;
1155ec55823SJoakim Zhang 	}
1166fc21117SJose Abreu 
1176fc21117SJose Abreu 	/* Read the data from the MII data register */
1185ec55823SJoakim Zhang 	ret = (int)readl(priv->ioaddr + mii_data) & GENMASK(15, 0);
1195ec55823SJoakim Zhang 
1205ec55823SJoakim Zhang err_disable_clks:
1215ec55823SJoakim Zhang 	pm_runtime_put(priv->device);
1225ec55823SJoakim Zhang 
1235ec55823SJoakim Zhang 	return ret;
1246fc21117SJose Abreu }
1256fc21117SJose Abreu 
1265b0a447eSAndrew Lunn static int stmmac_xgmac2_mdio_read_c22(struct mii_bus *bus, int phyaddr,
1275b0a447eSAndrew Lunn 				       int phyreg)
1286fc21117SJose Abreu {
1296fc21117SJose Abreu 	struct net_device *ndev = bus->priv;
1305b0a447eSAndrew Lunn 	struct stmmac_priv *priv;
1315b0a447eSAndrew Lunn 	u32 addr;
1325b0a447eSAndrew Lunn 
1335b0a447eSAndrew Lunn 	priv = netdev_priv(ndev);
1345b0a447eSAndrew Lunn 
1355b0a447eSAndrew Lunn 	/* HW does not support C22 addr >= 4 */
1365b0a447eSAndrew Lunn 	if (phyaddr > MII_XGMAC_MAX_C22ADDR)
1375b0a447eSAndrew Lunn 		return -ENODEV;
1385b0a447eSAndrew Lunn 
1395b0a447eSAndrew Lunn 	stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
1405b0a447eSAndrew Lunn 
1415b0a447eSAndrew Lunn 	return stmmac_xgmac2_mdio_read(priv, addr, MII_XGMAC_BUSY);
1425b0a447eSAndrew Lunn }
1435b0a447eSAndrew Lunn 
1445b0a447eSAndrew Lunn static int stmmac_xgmac2_mdio_read_c45(struct mii_bus *bus, int phyaddr,
1455b0a447eSAndrew Lunn 				       int devad, int phyreg)
1465b0a447eSAndrew Lunn {
1475b0a447eSAndrew Lunn 	struct net_device *ndev = bus->priv;
1485b0a447eSAndrew Lunn 	struct stmmac_priv *priv;
1495b0a447eSAndrew Lunn 	u32 addr;
1505b0a447eSAndrew Lunn 
1515b0a447eSAndrew Lunn 	priv = netdev_priv(ndev);
1525b0a447eSAndrew Lunn 
1535b0a447eSAndrew Lunn 	stmmac_xgmac2_c45_format(priv, phyaddr, devad, phyreg, &addr);
1545b0a447eSAndrew Lunn 
1555b0a447eSAndrew Lunn 	return stmmac_xgmac2_mdio_read(priv, addr, MII_XGMAC_BUSY);
1565b0a447eSAndrew Lunn }
1575b0a447eSAndrew Lunn 
1585b0a447eSAndrew Lunn static int stmmac_xgmac2_mdio_write(struct stmmac_priv *priv, u32 addr,
1595b0a447eSAndrew Lunn 				    u32 value, u16 phydata)
1605b0a447eSAndrew Lunn {
1616fc21117SJose Abreu 	unsigned int mii_address = priv->hw->mii.addr;
1626fc21117SJose Abreu 	unsigned int mii_data = priv->hw->mii.data;
1635b0a447eSAndrew Lunn 	u32 tmp;
1646fc21117SJose Abreu 	int ret;
1656fc21117SJose Abreu 
166e2d0acd4SMinghao Chi 	ret = pm_runtime_resume_and_get(priv->device);
167e2d0acd4SMinghao Chi 	if (ret < 0)
1685ec55823SJoakim Zhang 		return ret;
1695ec55823SJoakim Zhang 
17004d1190aSJose Abreu 	/* Wait until any existing MII operation is complete */
17104d1190aSJose Abreu 	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
1725ec55823SJoakim Zhang 			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
1735ec55823SJoakim Zhang 		ret = -EBUSY;
1745ec55823SJoakim Zhang 		goto err_disable_clks;
1755ec55823SJoakim Zhang 	}
17604d1190aSJose Abreu 
1776fc21117SJose Abreu 	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
1786fc21117SJose Abreu 		& priv->hw->mii.clk_csr_mask;
17904d1190aSJose Abreu 	value |= phydata;
1806fc21117SJose Abreu 	value |= MII_XGMAC_WRITE;
1816fc21117SJose Abreu 
1826fc21117SJose Abreu 	/* Wait until any existing MII operation is complete */
1836fc21117SJose Abreu 	if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
1845ec55823SJoakim Zhang 			       !(tmp & MII_XGMAC_BUSY), 100, 10000)) {
1855ec55823SJoakim Zhang 		ret = -EBUSY;
1865ec55823SJoakim Zhang 		goto err_disable_clks;
1875ec55823SJoakim Zhang 	}
1886fc21117SJose Abreu 
1896fc21117SJose Abreu 	/* Set the MII address register to write */
1906fc21117SJose Abreu 	writel(addr, priv->ioaddr + mii_address);
1916fc21117SJose Abreu 	writel(value, priv->ioaddr + mii_data);
1926fc21117SJose Abreu 
1936fc21117SJose Abreu 	/* Wait until any existing MII operation is complete */
1945ec55823SJoakim Zhang 	ret = readl_poll_timeout(priv->ioaddr + mii_data, tmp,
1956fc21117SJose Abreu 				 !(tmp & MII_XGMAC_BUSY), 100, 10000);
1965ec55823SJoakim Zhang 
1975ec55823SJoakim Zhang err_disable_clks:
1985ec55823SJoakim Zhang 	pm_runtime_put(priv->device);
1995ec55823SJoakim Zhang 
2005ec55823SJoakim Zhang 	return ret;
2016fc21117SJose Abreu }
2026fc21117SJose Abreu 
2035b0a447eSAndrew Lunn static int stmmac_xgmac2_mdio_write_c22(struct mii_bus *bus, int phyaddr,
2045b0a447eSAndrew Lunn 					int phyreg, u16 phydata)
2055b0a447eSAndrew Lunn {
2065b0a447eSAndrew Lunn 	struct net_device *ndev = bus->priv;
2075b0a447eSAndrew Lunn 	struct stmmac_priv *priv;
2085b0a447eSAndrew Lunn 	u32 addr;
2095b0a447eSAndrew Lunn 
2105b0a447eSAndrew Lunn 	priv = netdev_priv(ndev);
2115b0a447eSAndrew Lunn 
2125b0a447eSAndrew Lunn 	/* HW does not support C22 addr >= 4 */
2135b0a447eSAndrew Lunn 	if (phyaddr > MII_XGMAC_MAX_C22ADDR)
2145b0a447eSAndrew Lunn 		return -ENODEV;
2155b0a447eSAndrew Lunn 
2165b0a447eSAndrew Lunn 	stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
2175b0a447eSAndrew Lunn 
2185b0a447eSAndrew Lunn 	return stmmac_xgmac2_mdio_write(priv, addr,
2195b0a447eSAndrew Lunn 					MII_XGMAC_BUSY | MII_XGMAC_SADDR, phydata);
2205b0a447eSAndrew Lunn }
2215b0a447eSAndrew Lunn 
2225b0a447eSAndrew Lunn static int stmmac_xgmac2_mdio_write_c45(struct mii_bus *bus, int phyaddr,
2235b0a447eSAndrew Lunn 					int devad, int phyreg, u16 phydata)
2245b0a447eSAndrew Lunn {
2255b0a447eSAndrew Lunn 	struct net_device *ndev = bus->priv;
2265b0a447eSAndrew Lunn 	struct stmmac_priv *priv;
2275b0a447eSAndrew Lunn 	u32 addr;
2285b0a447eSAndrew Lunn 
2295b0a447eSAndrew Lunn 	priv = netdev_priv(ndev);
2305b0a447eSAndrew Lunn 
2315b0a447eSAndrew Lunn 	stmmac_xgmac2_c45_format(priv, phyaddr, devad, phyreg, &addr);
2325b0a447eSAndrew Lunn 
2335b0a447eSAndrew Lunn 	return stmmac_xgmac2_mdio_write(priv, addr, MII_XGMAC_BUSY,
2345b0a447eSAndrew Lunn 					phydata);
2355b0a447eSAndrew Lunn }
2365b0a447eSAndrew Lunn 
2373c7826d0SAndrew Lunn static int stmmac_mdio_read(struct stmmac_priv *priv, int data, u32 value)
2383c7826d0SAndrew Lunn {
2393c7826d0SAndrew Lunn 	unsigned int mii_address = priv->hw->mii.addr;
2403c7826d0SAndrew Lunn 	unsigned int mii_data = priv->hw->mii.data;
2413c7826d0SAndrew Lunn 	u32 v;
2423c7826d0SAndrew Lunn 
2433c7826d0SAndrew Lunn 	if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
2443c7826d0SAndrew Lunn 			       100, 10000))
2453c7826d0SAndrew Lunn 		return -EBUSY;
2463c7826d0SAndrew Lunn 
2473c7826d0SAndrew Lunn 	writel(data, priv->ioaddr + mii_data);
2483c7826d0SAndrew Lunn 	writel(value, priv->ioaddr + mii_address);
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 	/* Read the data from the MII data register */
2553c7826d0SAndrew Lunn 	return readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
2563c7826d0SAndrew Lunn }
2573c7826d0SAndrew Lunn 
2587ac6653aSJeff Kirsher /**
2593c7826d0SAndrew Lunn  * stmmac_mdio_read_c22
2607ac6653aSJeff Kirsher  * @bus: points to the mii_bus structure
261b91dce4cSLABBE Corentin  * @phyaddr: MII addr
262b91dce4cSLABBE Corentin  * @phyreg: MII reg
2637ac6653aSJeff Kirsher  * Description: it reads data from the MII register from within the phy device.
2647ac6653aSJeff Kirsher  * For the 7111 GMAC, we must set the bit 0 in the MII address register while
2657ac6653aSJeff Kirsher  * accessing the PHY registers.
2667ac6653aSJeff Kirsher  * Fortunately, it seems this has no drawback for the 7109 MAC.
2677ac6653aSJeff Kirsher  */
2683c7826d0SAndrew Lunn static int stmmac_mdio_read_c22(struct mii_bus *bus, int phyaddr, int phyreg)
2697ac6653aSJeff Kirsher {
2707ac6653aSJeff Kirsher 	struct net_device *ndev = bus->priv;
2717ac6653aSJeff Kirsher 	struct stmmac_priv *priv = netdev_priv(ndev);
272b91dce4cSLABBE Corentin 	u32 value = MII_BUSY;
273d4117d63SKweh Hock Leong 	int data = 0;
274b91dce4cSLABBE Corentin 
275e2d0acd4SMinghao Chi 	data = pm_runtime_resume_and_get(priv->device);
276e2d0acd4SMinghao Chi 	if (data < 0)
2775ec55823SJoakim Zhang 		return data;
2785ec55823SJoakim Zhang 
279b91dce4cSLABBE Corentin 	value |= (phyaddr << priv->hw->mii.addr_shift)
280b91dce4cSLABBE Corentin 		& priv->hw->mii.addr_mask;
281b91dce4cSLABBE Corentin 	value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
282567be786Sjpinto 	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
283567be786Sjpinto 		& priv->hw->mii.clk_csr_mask;
2847c6b942bSAndrew Halaney 	if (priv->plat->has_gmac4)
285b91dce4cSLABBE Corentin 		value |= MII_GMAC4_READ;
2867ac6653aSJeff Kirsher 
2873c7826d0SAndrew Lunn 	data = stmmac_mdio_read(priv, data, value);
28839b401dbSDeepak SIKRI 
2895ec55823SJoakim Zhang 	pm_runtime_put(priv->device);
2905ec55823SJoakim Zhang 
2917ac6653aSJeff Kirsher 	return data;
2927ac6653aSJeff Kirsher }
2937ac6653aSJeff Kirsher 
2947ac6653aSJeff Kirsher /**
2953c7826d0SAndrew Lunn  * stmmac_mdio_read_c45
2963c7826d0SAndrew Lunn  * @bus: points to the mii_bus structure
2973c7826d0SAndrew Lunn  * @phyaddr: MII addr
2983c7826d0SAndrew Lunn  * @devad: device address to read
2993c7826d0SAndrew Lunn  * @phyreg: MII reg
3003c7826d0SAndrew Lunn  * Description: it reads data from the MII register from within the phy device.
3013c7826d0SAndrew Lunn  * For the 7111 GMAC, we must set the bit 0 in the MII address register while
3023c7826d0SAndrew Lunn  * accessing the PHY registers.
3033c7826d0SAndrew Lunn  * Fortunately, it seems this has no drawback for the 7109 MAC.
3043c7826d0SAndrew Lunn  */
3053c7826d0SAndrew Lunn static int stmmac_mdio_read_c45(struct mii_bus *bus, int phyaddr, int devad,
3063c7826d0SAndrew Lunn 				int phyreg)
3073c7826d0SAndrew Lunn {
3083c7826d0SAndrew Lunn 	struct net_device *ndev = bus->priv;
3093c7826d0SAndrew Lunn 	struct stmmac_priv *priv = netdev_priv(ndev);
3103c7826d0SAndrew Lunn 	u32 value = MII_BUSY;
3113c7826d0SAndrew Lunn 	int data = 0;
3123c7826d0SAndrew Lunn 
3133c7826d0SAndrew Lunn 	data = pm_runtime_get_sync(priv->device);
3143c7826d0SAndrew Lunn 	if (data < 0) {
3153c7826d0SAndrew Lunn 		pm_runtime_put_noidle(priv->device);
3163c7826d0SAndrew Lunn 		return data;
3173c7826d0SAndrew Lunn 	}
3183c7826d0SAndrew Lunn 
3193c7826d0SAndrew Lunn 	value |= (phyaddr << priv->hw->mii.addr_shift)
3203c7826d0SAndrew Lunn 		& priv->hw->mii.addr_mask;
3213c7826d0SAndrew Lunn 	value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
3223c7826d0SAndrew Lunn 	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
3233c7826d0SAndrew Lunn 		& priv->hw->mii.clk_csr_mask;
3243c7826d0SAndrew Lunn 	value |= MII_GMAC4_READ;
3253c7826d0SAndrew Lunn 	value |= MII_GMAC4_C45E;
3263c7826d0SAndrew Lunn 	value &= ~priv->hw->mii.reg_mask;
3273c7826d0SAndrew Lunn 	value |= (devad << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
3283c7826d0SAndrew Lunn 
3293c7826d0SAndrew Lunn 	data |= phyreg << MII_GMAC4_REG_ADDR_SHIFT;
3303c7826d0SAndrew Lunn 
3313c7826d0SAndrew Lunn 	data = stmmac_mdio_read(priv, data, value);
3323c7826d0SAndrew Lunn 
3333c7826d0SAndrew Lunn 	pm_runtime_put(priv->device);
3343c7826d0SAndrew Lunn 
3353c7826d0SAndrew Lunn 	return data;
3363c7826d0SAndrew Lunn }
3373c7826d0SAndrew Lunn 
3383c7826d0SAndrew Lunn static int stmmac_mdio_write(struct stmmac_priv *priv, int data, u32 value)
3393c7826d0SAndrew Lunn {
3403c7826d0SAndrew Lunn 	unsigned int mii_address = priv->hw->mii.addr;
3413c7826d0SAndrew Lunn 	unsigned int mii_data = priv->hw->mii.data;
3423c7826d0SAndrew Lunn 	u32 v;
3433c7826d0SAndrew Lunn 
3443c7826d0SAndrew Lunn 	/* Wait until any existing MII operation is complete */
3453c7826d0SAndrew Lunn 	if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
3463c7826d0SAndrew Lunn 			       100, 10000))
3473c7826d0SAndrew Lunn 		return -EBUSY;
3483c7826d0SAndrew Lunn 
3493c7826d0SAndrew Lunn 	/* Set the MII address register to write */
3503c7826d0SAndrew Lunn 	writel(data, priv->ioaddr + mii_data);
3513c7826d0SAndrew Lunn 	writel(value, priv->ioaddr + mii_address);
3523c7826d0SAndrew Lunn 
3533c7826d0SAndrew Lunn 	/* Wait until any existing MII operation is complete */
3543c7826d0SAndrew Lunn 	return readl_poll_timeout(priv->ioaddr + mii_address, v,
3553c7826d0SAndrew Lunn 				  !(v & MII_BUSY), 100, 10000);
3563c7826d0SAndrew Lunn }
3573c7826d0SAndrew Lunn 
3583c7826d0SAndrew Lunn /**
3593c7826d0SAndrew Lunn  * stmmac_mdio_write_c22
3607ac6653aSJeff Kirsher  * @bus: points to the mii_bus structure
361b91dce4cSLABBE Corentin  * @phyaddr: MII addr
362b91dce4cSLABBE Corentin  * @phyreg: MII reg
3637ac6653aSJeff Kirsher  * @phydata: phy data
3647ac6653aSJeff Kirsher  * Description: it writes the data into the MII register from within the device.
3657ac6653aSJeff Kirsher  */
3663c7826d0SAndrew Lunn static int stmmac_mdio_write_c22(struct mii_bus *bus, int phyaddr, int phyreg,
3677ac6653aSJeff Kirsher 				 u16 phydata)
3687ac6653aSJeff Kirsher {
3697ac6653aSJeff Kirsher 	struct net_device *ndev = bus->priv;
3707ac6653aSJeff Kirsher 	struct stmmac_priv *priv = netdev_priv(ndev);
3715ec55823SJoakim Zhang 	int ret, data = phydata;
3725799fc90SKweh, Hock Leong 	u32 value = MII_BUSY;
3737ac6653aSJeff Kirsher 
374e2d0acd4SMinghao Chi 	ret = pm_runtime_resume_and_get(priv->device);
375e2d0acd4SMinghao Chi 	if (ret < 0)
3765ec55823SJoakim Zhang 		return ret;
3775ec55823SJoakim Zhang 
378b91dce4cSLABBE Corentin 	value |= (phyaddr << priv->hw->mii.addr_shift)
379b91dce4cSLABBE Corentin 		& priv->hw->mii.addr_mask;
380b91dce4cSLABBE Corentin 	value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
3817ac6653aSJeff Kirsher 
382567be786Sjpinto 	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
383567be786Sjpinto 		& priv->hw->mii.clk_csr_mask;
3843c7826d0SAndrew Lunn 	if (priv->plat->has_gmac4)
385b91dce4cSLABBE Corentin 		value |= MII_GMAC4_WRITE;
3863c7826d0SAndrew Lunn 	else
3873c7826d0SAndrew Lunn 		value |= MII_WRITE;
3883c7826d0SAndrew Lunn 
3893c7826d0SAndrew Lunn 	ret = stmmac_mdio_write(priv, data, value);
3903c7826d0SAndrew Lunn 
3913c7826d0SAndrew Lunn 	pm_runtime_put(priv->device);
3923c7826d0SAndrew Lunn 
3933c7826d0SAndrew Lunn 	return ret;
3943c7826d0SAndrew Lunn }
3953c7826d0SAndrew Lunn 
3963c7826d0SAndrew Lunn /**
3973c7826d0SAndrew Lunn  * stmmac_mdio_write_c45
3983c7826d0SAndrew Lunn  * @bus: points to the mii_bus structure
3993c7826d0SAndrew Lunn  * @phyaddr: MII addr
4003c7826d0SAndrew Lunn  * @phyreg: MII reg
4013c7826d0SAndrew Lunn  * @devad: device address to read
4023c7826d0SAndrew Lunn  * @phydata: phy data
4033c7826d0SAndrew Lunn  * Description: it writes the data into the MII register from within the device.
4043c7826d0SAndrew Lunn  */
4053c7826d0SAndrew Lunn static int stmmac_mdio_write_c45(struct mii_bus *bus, int phyaddr,
4063c7826d0SAndrew Lunn 				 int devad, int phyreg, u16 phydata)
4073c7826d0SAndrew Lunn {
4083c7826d0SAndrew Lunn 	struct net_device *ndev = bus->priv;
4093c7826d0SAndrew Lunn 	struct stmmac_priv *priv = netdev_priv(ndev);
4103c7826d0SAndrew Lunn 	int ret, data = phydata;
4113c7826d0SAndrew Lunn 	u32 value = MII_BUSY;
4123c7826d0SAndrew Lunn 
4133c7826d0SAndrew Lunn 	ret = pm_runtime_get_sync(priv->device);
4143c7826d0SAndrew Lunn 	if (ret < 0) {
4153c7826d0SAndrew Lunn 		pm_runtime_put_noidle(priv->device);
4163c7826d0SAndrew Lunn 		return ret;
4173c7826d0SAndrew Lunn 	}
4183c7826d0SAndrew Lunn 
4193c7826d0SAndrew Lunn 	value |= (phyaddr << priv->hw->mii.addr_shift)
4203c7826d0SAndrew Lunn 		& priv->hw->mii.addr_mask;
4213c7826d0SAndrew Lunn 	value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
4223c7826d0SAndrew Lunn 
4233c7826d0SAndrew Lunn 	value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift)
4243c7826d0SAndrew Lunn 		& priv->hw->mii.clk_csr_mask;
4253c7826d0SAndrew Lunn 
4263c7826d0SAndrew Lunn 	value |= MII_GMAC4_WRITE;
427d4117d63SKweh Hock Leong 	value |= MII_GMAC4_C45E;
428d4117d63SKweh Hock Leong 	value &= ~priv->hw->mii.reg_mask;
4293c7826d0SAndrew Lunn 	value |= (devad << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
430d4117d63SKweh Hock Leong 
4313c7826d0SAndrew Lunn 	data |= phyreg << MII_GMAC4_REG_ADDR_SHIFT;
432ac1f74a7SAlexandre TORGUE 
4333c7826d0SAndrew Lunn 	ret = stmmac_mdio_write(priv, data, value);
434ac1f74a7SAlexandre TORGUE 
4355ec55823SJoakim Zhang 	pm_runtime_put(priv->device);
4365ec55823SJoakim Zhang 
4375ec55823SJoakim Zhang 	return ret;
438ac1f74a7SAlexandre TORGUE }
439ac1f74a7SAlexandre TORGUE 
440ac1f74a7SAlexandre TORGUE /**
4417ac6653aSJeff Kirsher  * stmmac_mdio_reset
4427ac6653aSJeff Kirsher  * @bus: points to the mii_bus structure
4437ac6653aSJeff Kirsher  * Description: reset the MII bus
4447ac6653aSJeff Kirsher  */
445073752aaSSrinivas Kandagatla int stmmac_mdio_reset(struct mii_bus *bus)
4467ac6653aSJeff Kirsher {
44730549aabSNiklas Cassel #if IS_ENABLED(CONFIG_STMMAC_PLATFORM)
4487ac6653aSJeff Kirsher 	struct net_device *ndev = bus->priv;
4497ac6653aSJeff Kirsher 	struct stmmac_priv *priv = netdev_priv(ndev);
4507ac6653aSJeff Kirsher 	unsigned int mii_address = priv->hw->mii.addr;
4517ac6653aSJeff Kirsher 
4520e076471SSrinivas Kandagatla #ifdef CONFIG_OF
4530e076471SSrinivas Kandagatla 	if (priv->device->of_node) {
4547c86f20dSMartin Blumenstingl 		struct gpio_desc *reset_gpio;
45584ce4d0fSMartin Blumenstingl 		u32 delays[3] = { 0, 0, 0 };
4567c86f20dSMartin Blumenstingl 
4577c86f20dSMartin Blumenstingl 		reset_gpio = devm_gpiod_get_optional(priv->device,
4587c86f20dSMartin Blumenstingl 						     "snps,reset",
4597c86f20dSMartin Blumenstingl 						     GPIOD_OUT_LOW);
4607c86f20dSMartin Blumenstingl 		if (IS_ERR(reset_gpio))
4617c86f20dSMartin Blumenstingl 			return PTR_ERR(reset_gpio);
4620e076471SSrinivas Kandagatla 
463cc5e92c2SMartin Blumenstingl 		device_property_read_u32_array(priv->device,
46442a90766SMartin Blumenstingl 					       "snps,reset-delays-us",
465cc5e92c2SMartin Blumenstingl 					       delays, ARRAY_SIZE(delays));
4660e076471SSrinivas Kandagatla 
467ce4ab73aSMartin Blumenstingl 		if (delays[0])
468ce4ab73aSMartin Blumenstingl 			msleep(DIV_ROUND_UP(delays[0], 1000));
469892aa01dSSjoerd Simons 
4707c86f20dSMartin Blumenstingl 		gpiod_set_value_cansleep(reset_gpio, 1);
471ce4ab73aSMartin Blumenstingl 		if (delays[1])
472ce4ab73aSMartin Blumenstingl 			msleep(DIV_ROUND_UP(delays[1], 1000));
473892aa01dSSjoerd Simons 
4747c86f20dSMartin Blumenstingl 		gpiod_set_value_cansleep(reset_gpio, 0);
475ce4ab73aSMartin Blumenstingl 		if (delays[2])
476ce4ab73aSMartin Blumenstingl 			msleep(DIV_ROUND_UP(delays[2], 1000));
4770e076471SSrinivas Kandagatla 	}
4780e076471SSrinivas Kandagatla #endif
4790e076471SSrinivas Kandagatla 
4807ac6653aSJeff Kirsher 	/* This is a workaround for problems with the STE101P PHY.
4817ac6653aSJeff Kirsher 	 * It doesn't complete its reset until at least one clock cycle
4828d45e42bSLABBE Corentin 	 * on MDC, so perform a dummy mdio read. To be updated for GMAC4
483ac1f74a7SAlexandre TORGUE 	 * if needed.
4847ac6653aSJeff Kirsher 	 */
485ac1f74a7SAlexandre TORGUE 	if (!priv->plat->has_gmac4)
4867ac6653aSJeff Kirsher 		writel(0, priv->ioaddr + mii_address);
487bfab27a1SGiuseppe CAVALLARO #endif
4887ac6653aSJeff Kirsher 	return 0;
4897ac6653aSJeff Kirsher }
4907ac6653aSJeff Kirsher 
491597a68ceSVoon Weifeng int stmmac_xpcs_setup(struct mii_bus *bus)
492597a68ceSVoon Weifeng {
493597a68ceSVoon Weifeng 	struct net_device *ndev = bus->priv;
49447538dbeSVladimir Oltean 	struct stmmac_priv *priv;
49547538dbeSVladimir Oltean 	struct dw_xpcs *xpcs;
49647538dbeSVladimir Oltean 	int mode, addr;
497597a68ceSVoon Weifeng 
498597a68ceSVoon Weifeng 	priv = netdev_priv(ndev);
499597a68ceSVoon Weifeng 	mode = priv->plat->phy_interface;
500597a68ceSVoon Weifeng 
501597a68ceSVoon Weifeng 	/* Try to probe the XPCS by scanning all addresses. */
502597a68ceSVoon Weifeng 	for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
503*727e373fSRussell King (Oracle) 		xpcs = xpcs_create_mdiodev(bus, addr, mode);
504*727e373fSRussell King (Oracle) 		if (IS_ERR(xpcs))
505597a68ceSVoon Weifeng 			continue;
506597a68ceSVoon Weifeng 
507597a68ceSVoon Weifeng 		priv->hw->xpcs = xpcs;
508597a68ceSVoon Weifeng 		break;
509597a68ceSVoon Weifeng 	}
510597a68ceSVoon Weifeng 
511597a68ceSVoon Weifeng 	if (!priv->hw->xpcs) {
512597a68ceSVoon Weifeng 		dev_warn(priv->device, "No xPCS found\n");
513597a68ceSVoon Weifeng 		return -ENODEV;
514597a68ceSVoon Weifeng 	}
515597a68ceSVoon Weifeng 
516597a68ceSVoon Weifeng 	return 0;
517597a68ceSVoon Weifeng }
518597a68ceSVoon Weifeng 
5197ac6653aSJeff Kirsher /**
5207ac6653aSJeff Kirsher  * stmmac_mdio_register
5217ac6653aSJeff Kirsher  * @ndev: net device structure
5227ac6653aSJeff Kirsher  * Description: it registers the MII bus
5237ac6653aSJeff Kirsher  */
5247ac6653aSJeff Kirsher int stmmac_mdio_register(struct net_device *ndev)
5257ac6653aSJeff Kirsher {
5267ac6653aSJeff Kirsher 	int err = 0;
5277ac6653aSJeff Kirsher 	struct mii_bus *new_bus;
5287ac6653aSJeff Kirsher 	struct stmmac_priv *priv = netdev_priv(ndev);
529ab21cf92SOng Boon Leong 	struct fwnode_handle *fwnode = of_fwnode_handle(priv->plat->phylink_node);
5307ac6653aSJeff Kirsher 	struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
531a7657f12SGiuseppe CAVALLARO 	struct device_node *mdio_node = priv->plat->mdio_node;
532fbca1647SRomain Perier 	struct device *dev = ndev->dev.parent;
533ab21cf92SOng Boon Leong 	struct fwnode_handle *fixed_node;
5346fc21117SJose Abreu 	int addr, found, max_addr;
5357ac6653aSJeff Kirsher 
5367ac6653aSJeff Kirsher 	if (!mdio_bus_data)
5377ac6653aSJeff Kirsher 		return 0;
5387ac6653aSJeff Kirsher 
5397ac6653aSJeff Kirsher 	new_bus = mdiobus_alloc();
540efd89b60SLABBE Corentin 	if (!new_bus)
5417ac6653aSJeff Kirsher 		return -ENOMEM;
5427ac6653aSJeff Kirsher 
543e7f4dc35SAndrew Lunn 	if (mdio_bus_data->irqs)
544643d60bfSMarek Vasut 		memcpy(new_bus->irq, mdio_bus_data->irqs, sizeof(new_bus->irq));
5457ac6653aSJeff Kirsher 
54690b9a545SAlessandro Rubini 	new_bus->name = "stmmac";
5476fc21117SJose Abreu 
5486fc21117SJose Abreu 	if (priv->plat->has_xgmac) {
5495b0a447eSAndrew Lunn 		new_bus->read = &stmmac_xgmac2_mdio_read_c22;
5505b0a447eSAndrew Lunn 		new_bus->write = &stmmac_xgmac2_mdio_write_c22;
5515b0a447eSAndrew Lunn 		new_bus->read_c45 = &stmmac_xgmac2_mdio_read_c45;
5525b0a447eSAndrew Lunn 		new_bus->write_c45 = &stmmac_xgmac2_mdio_write_c45;
5536fc21117SJose Abreu 
5546fc21117SJose Abreu 		/* Right now only C22 phys are supported */
5556fc21117SJose Abreu 		max_addr = MII_XGMAC_MAX_C22ADDR + 1;
5566fc21117SJose Abreu 
5576fc21117SJose Abreu 		/* Check if DT specified an unsupported phy addr */
5586fc21117SJose Abreu 		if (priv->plat->phy_addr > MII_XGMAC_MAX_C22ADDR)
5596fc21117SJose Abreu 			dev_err(dev, "Unsupported phy_addr (max=%d)\n",
5606fc21117SJose Abreu 					MII_XGMAC_MAX_C22ADDR);
5616fc21117SJose Abreu 	} else {
5623c7826d0SAndrew Lunn 		new_bus->read = &stmmac_mdio_read_c22;
5633c7826d0SAndrew Lunn 		new_bus->write = &stmmac_mdio_write_c22;
5643c7826d0SAndrew Lunn 		if (priv->plat->has_gmac4) {
5653c7826d0SAndrew Lunn 			new_bus->read_c45 = &stmmac_mdio_read_c45;
5663c7826d0SAndrew Lunn 			new_bus->write_c45 = &stmmac_mdio_write_c45;
5673c7826d0SAndrew Lunn 		}
5683c7826d0SAndrew Lunn 
5696fc21117SJose Abreu 		max_addr = PHY_MAX_ADDR;
5706fc21117SJose Abreu 	}
571ac1f74a7SAlexandre TORGUE 
5721a981c05SThierry Reding 	if (mdio_bus_data->needs_reset)
5737ac6653aSJeff Kirsher 		new_bus->reset = &stmmac_mdio_reset;
5741a981c05SThierry Reding 
575db8857bfSFlorian Fainelli 	snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x",
576d56631a6SSrinivas Kandagatla 		 new_bus->name, priv->plat->bus_id);
5777ac6653aSJeff Kirsher 	new_bus->priv = ndev;
5787ac6653aSJeff Kirsher 	new_bus->phy_mask = mdio_bus_data->phy_mask;
5797ac6653aSJeff Kirsher 	new_bus->parent = priv->device;
580e34d6569SPhil Reid 
581e34d6569SPhil Reid 	err = of_mdiobus_register(new_bus, mdio_node);
5827ac6653aSJeff Kirsher 	if (err != 0) {
583839612d2SRasmus Villemoes 		dev_err_probe(dev, err, "Cannot register the MDIO bus\n");
5847ac6653aSJeff Kirsher 		goto bus_register_fail;
5857ac6653aSJeff Kirsher 	}
5867ac6653aSJeff Kirsher 
58704d1190aSJose Abreu 	/* Looks like we need a dummy read for XGMAC only and C45 PHYs */
58804d1190aSJose Abreu 	if (priv->plat->has_xgmac)
5895b0a447eSAndrew Lunn 		stmmac_xgmac2_mdio_read_c45(new_bus, 0, 0, 0);
59004d1190aSJose Abreu 
591ab21cf92SOng Boon Leong 	/* If fixed-link is set, skip PHY scanning */
592ab21cf92SOng Boon Leong 	if (!fwnode)
593ab21cf92SOng Boon Leong 		fwnode = dev_fwnode(priv->device);
594ab21cf92SOng Boon Leong 
595ab21cf92SOng Boon Leong 	if (fwnode) {
596ab21cf92SOng Boon Leong 		fixed_node = fwnode_get_named_child_node(fwnode, "fixed-link");
597ab21cf92SOng Boon Leong 		if (fixed_node) {
598ab21cf92SOng Boon Leong 			fwnode_handle_put(fixed_node);
599ab21cf92SOng Boon Leong 			goto bus_register_done;
600ab21cf92SOng Boon Leong 		}
601ab21cf92SOng Boon Leong 	}
602ab21cf92SOng Boon Leong 
603cc2fa619SPhil Reid 	if (priv->plat->phy_node || mdio_node)
604cc2fa619SPhil Reid 		goto bus_register_done;
605cc2fa619SPhil Reid 
6067ac6653aSJeff Kirsher 	found = 0;
6076fc21117SJose Abreu 	for (addr = 0; addr < max_addr; addr++) {
6087f854420SAndrew Lunn 		struct phy_device *phydev = mdiobus_get_phy(new_bus, addr);
6097ac6653aSJeff Kirsher 
610cc26dc67SLABBE Corentin 		if (!phydev)
611cc26dc67SLABBE Corentin 			continue;
612cc26dc67SLABBE Corentin 
6137ac6653aSJeff Kirsher 		/*
6147ac6653aSJeff Kirsher 		 * If an IRQ was provided to be assigned after
6157ac6653aSJeff Kirsher 		 * the bus probe, do it here.
6167ac6653aSJeff Kirsher 		 */
617cb2c0aceSLABBE Corentin 		if (!mdio_bus_data->irqs &&
6187ac6653aSJeff Kirsher 		    (mdio_bus_data->probed_phy_irq > 0)) {
619cc26dc67SLABBE Corentin 			new_bus->irq[addr] = mdio_bus_data->probed_phy_irq;
6207ac6653aSJeff Kirsher 			phydev->irq = mdio_bus_data->probed_phy_irq;
6217ac6653aSJeff Kirsher 		}
6227ac6653aSJeff Kirsher 
6237ac6653aSJeff Kirsher 		/*
6247ac6653aSJeff Kirsher 		 * If we're going to bind the MAC to this PHY bus,
6257ac6653aSJeff Kirsher 		 * and no PHY number was provided to the MAC,
6267ac6653aSJeff Kirsher 		 * use the one probed here.
6277ac6653aSJeff Kirsher 		 */
628d56631a6SSrinivas Kandagatla 		if (priv->plat->phy_addr == -1)
6297ac6653aSJeff Kirsher 			priv->plat->phy_addr = addr;
6307ac6653aSJeff Kirsher 
631fbca1647SRomain Perier 		phy_attached_info(phydev);
6327ac6653aSJeff Kirsher 		found = 1;
6337ac6653aSJeff Kirsher 	}
6347ac6653aSJeff Kirsher 
6354751d2aaSVladimir Oltean 	if (!found && !mdio_node) {
6364751d2aaSVladimir Oltean 		dev_warn(dev, "No PHY found\n");
6374751d2aaSVladimir Oltean 		err = -ENODEV;
6384751d2aaSVladimir Oltean 		goto no_phy_found;
6394751d2aaSVladimir Oltean 	}
6404751d2aaSVladimir Oltean 
641cc2fa619SPhil Reid bus_register_done:
6423955b22bSGiuseppe CAVALLARO 	priv->mii = new_bus;
6437ac6653aSJeff Kirsher 
6447ac6653aSJeff Kirsher 	return 0;
6457ac6653aSJeff Kirsher 
6464751d2aaSVladimir Oltean no_phy_found:
6474751d2aaSVladimir Oltean 	mdiobus_unregister(new_bus);
6487ac6653aSJeff Kirsher bus_register_fail:
6497ac6653aSJeff Kirsher 	mdiobus_free(new_bus);
6507ac6653aSJeff Kirsher 	return err;
6517ac6653aSJeff Kirsher }
6527ac6653aSJeff Kirsher 
6537ac6653aSJeff Kirsher /**
6547ac6653aSJeff Kirsher  * stmmac_mdio_unregister
6557ac6653aSJeff Kirsher  * @ndev: net device structure
6567ac6653aSJeff Kirsher  * Description: it unregisters the MII bus
6577ac6653aSJeff Kirsher  */
6587ac6653aSJeff Kirsher int stmmac_mdio_unregister(struct net_device *ndev)
6597ac6653aSJeff Kirsher {
6607ac6653aSJeff Kirsher 	struct stmmac_priv *priv = netdev_priv(ndev);
6617ac6653aSJeff Kirsher 
662a5cf5ce9SSrinivas Kandagatla 	if (!priv->mii)
663a5cf5ce9SSrinivas Kandagatla 		return 0;
664a5cf5ce9SSrinivas Kandagatla 
665*727e373fSRussell King (Oracle) 	if (priv->hw->xpcs)
66611059740SVladimir Oltean 		xpcs_destroy(priv->hw->xpcs);
6672cac15daSVladimir Oltean 
6687ac6653aSJeff Kirsher 	mdiobus_unregister(priv->mii);
6697ac6653aSJeff Kirsher 	priv->mii->priv = NULL;
6707ac6653aSJeff Kirsher 	mdiobus_free(priv->mii);
6717ac6653aSJeff Kirsher 	priv->mii = NULL;
6727ac6653aSJeff Kirsher 
6737ac6653aSJeff Kirsher 	return 0;
6747ac6653aSJeff Kirsher }
675