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 4804d1190aSJose Abreu static int stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr, 4904d1190aSJose Abreu 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); 5904d1190aSJose Abreu *hw_addr |= (phyreg >> MII_DEVADDR_C45_SHIFT) << MII_XGMAC_DA_SHIFT; 6004d1190aSJose Abreu return 0; 6104d1190aSJose Abreu } 626fc21117SJose Abreu 636fc21117SJose Abreu static int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr, 646fc21117SJose Abreu int phyreg, u32 *hw_addr) 656fc21117SJose Abreu { 666fc21117SJose Abreu u32 tmp; 676fc21117SJose Abreu 686fc21117SJose Abreu /* HW does not support C22 addr >= 4 */ 696fc21117SJose Abreu if (phyaddr > MII_XGMAC_MAX_C22ADDR) 706fc21117SJose Abreu return -ENODEV; 716fc21117SJose Abreu 726fc21117SJose Abreu /* Set port as Clause 22 */ 736fc21117SJose Abreu tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P); 746fc21117SJose Abreu tmp &= ~MII_XGMAC_C22P_MASK; 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 return 0; 806fc21117SJose Abreu } 816fc21117SJose Abreu 826fc21117SJose Abreu static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) 836fc21117SJose Abreu { 846fc21117SJose Abreu struct net_device *ndev = bus->priv; 856fc21117SJose Abreu struct stmmac_priv *priv = netdev_priv(ndev); 866fc21117SJose Abreu unsigned int mii_address = priv->hw->mii.addr; 876fc21117SJose Abreu unsigned int mii_data = priv->hw->mii.data; 886fc21117SJose Abreu u32 tmp, addr, value = MII_XGMAC_BUSY; 896fc21117SJose Abreu int ret; 906fc21117SJose Abreu 91e2d0acd4SMinghao Chi ret = pm_runtime_resume_and_get(priv->device); 92e2d0acd4SMinghao Chi if (ret < 0) 935ec55823SJoakim Zhang return ret; 945ec55823SJoakim Zhang 9504d1190aSJose Abreu /* Wait until any existing MII operation is complete */ 9604d1190aSJose Abreu if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, 975ec55823SJoakim Zhang !(tmp & MII_XGMAC_BUSY), 100, 10000)) { 985ec55823SJoakim Zhang ret = -EBUSY; 995ec55823SJoakim Zhang goto err_disable_clks; 1005ec55823SJoakim Zhang } 10104d1190aSJose Abreu 1026fc21117SJose Abreu if (phyreg & MII_ADDR_C45) { 10304d1190aSJose Abreu phyreg &= ~MII_ADDR_C45; 10404d1190aSJose Abreu 10504d1190aSJose Abreu ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr); 10604d1190aSJose Abreu if (ret) 1075ec55823SJoakim Zhang goto err_disable_clks; 1086fc21117SJose Abreu } else { 1096fc21117SJose Abreu ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr); 1106fc21117SJose Abreu if (ret) 1115ec55823SJoakim Zhang goto err_disable_clks; 11204d1190aSJose Abreu 11304d1190aSJose Abreu value |= MII_XGMAC_SADDR; 1146fc21117SJose Abreu } 1156fc21117SJose Abreu 1166fc21117SJose Abreu value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) 1176fc21117SJose Abreu & priv->hw->mii.clk_csr_mask; 11804d1190aSJose Abreu value |= MII_XGMAC_READ; 1196fc21117SJose Abreu 1206fc21117SJose Abreu /* Wait until any existing MII operation is complete */ 1216fc21117SJose Abreu if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, 1225ec55823SJoakim Zhang !(tmp & MII_XGMAC_BUSY), 100, 10000)) { 1235ec55823SJoakim Zhang ret = -EBUSY; 1245ec55823SJoakim Zhang goto err_disable_clks; 1255ec55823SJoakim Zhang } 1266fc21117SJose Abreu 1276fc21117SJose Abreu /* Set the MII address register to read */ 1286fc21117SJose Abreu writel(addr, priv->ioaddr + mii_address); 1296fc21117SJose Abreu writel(value, priv->ioaddr + mii_data); 1306fc21117SJose Abreu 1316fc21117SJose Abreu /* Wait until any existing MII operation is complete */ 1326fc21117SJose Abreu if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, 1335ec55823SJoakim Zhang !(tmp & MII_XGMAC_BUSY), 100, 10000)) { 1345ec55823SJoakim Zhang ret = -EBUSY; 1355ec55823SJoakim Zhang goto err_disable_clks; 1365ec55823SJoakim Zhang } 1376fc21117SJose Abreu 1386fc21117SJose Abreu /* Read the data from the MII data register */ 1395ec55823SJoakim Zhang ret = (int)readl(priv->ioaddr + mii_data) & GENMASK(15, 0); 1405ec55823SJoakim Zhang 1415ec55823SJoakim Zhang err_disable_clks: 1425ec55823SJoakim Zhang pm_runtime_put(priv->device); 1435ec55823SJoakim Zhang 1445ec55823SJoakim Zhang return ret; 1456fc21117SJose Abreu } 1466fc21117SJose Abreu 1476fc21117SJose Abreu static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr, 1486fc21117SJose Abreu int phyreg, u16 phydata) 1496fc21117SJose Abreu { 1506fc21117SJose Abreu struct net_device *ndev = bus->priv; 1516fc21117SJose Abreu struct stmmac_priv *priv = netdev_priv(ndev); 1526fc21117SJose Abreu unsigned int mii_address = priv->hw->mii.addr; 1536fc21117SJose Abreu unsigned int mii_data = priv->hw->mii.data; 1546fc21117SJose Abreu u32 addr, tmp, value = MII_XGMAC_BUSY; 1556fc21117SJose Abreu int ret; 1566fc21117SJose Abreu 157e2d0acd4SMinghao Chi ret = pm_runtime_resume_and_get(priv->device); 158e2d0acd4SMinghao Chi if (ret < 0) 1595ec55823SJoakim Zhang return ret; 1605ec55823SJoakim Zhang 16104d1190aSJose Abreu /* Wait until any existing MII operation is complete */ 16204d1190aSJose Abreu if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, 1635ec55823SJoakim Zhang !(tmp & MII_XGMAC_BUSY), 100, 10000)) { 1645ec55823SJoakim Zhang ret = -EBUSY; 1655ec55823SJoakim Zhang goto err_disable_clks; 1665ec55823SJoakim Zhang } 16704d1190aSJose Abreu 1686fc21117SJose Abreu if (phyreg & MII_ADDR_C45) { 16904d1190aSJose Abreu phyreg &= ~MII_ADDR_C45; 17004d1190aSJose Abreu 17104d1190aSJose Abreu ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr); 17204d1190aSJose Abreu if (ret) 1735ec55823SJoakim Zhang goto err_disable_clks; 1746fc21117SJose Abreu } else { 1756fc21117SJose Abreu ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr); 1766fc21117SJose Abreu if (ret) 1775ec55823SJoakim Zhang goto err_disable_clks; 17804d1190aSJose Abreu 17904d1190aSJose Abreu value |= MII_XGMAC_SADDR; 1806fc21117SJose Abreu } 1816fc21117SJose Abreu 1826fc21117SJose Abreu value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) 1836fc21117SJose Abreu & priv->hw->mii.clk_csr_mask; 18404d1190aSJose Abreu value |= phydata; 1856fc21117SJose Abreu value |= MII_XGMAC_WRITE; 1866fc21117SJose Abreu 1876fc21117SJose Abreu /* Wait until any existing MII operation is complete */ 1886fc21117SJose Abreu if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, 1895ec55823SJoakim Zhang !(tmp & MII_XGMAC_BUSY), 100, 10000)) { 1905ec55823SJoakim Zhang ret = -EBUSY; 1915ec55823SJoakim Zhang goto err_disable_clks; 1925ec55823SJoakim Zhang } 1936fc21117SJose Abreu 1946fc21117SJose Abreu /* Set the MII address register to write */ 1956fc21117SJose Abreu writel(addr, priv->ioaddr + mii_address); 1966fc21117SJose Abreu writel(value, priv->ioaddr + mii_data); 1976fc21117SJose Abreu 1986fc21117SJose Abreu /* Wait until any existing MII operation is complete */ 1995ec55823SJoakim Zhang ret = readl_poll_timeout(priv->ioaddr + mii_data, tmp, 2006fc21117SJose Abreu !(tmp & MII_XGMAC_BUSY), 100, 10000); 2015ec55823SJoakim Zhang 2025ec55823SJoakim Zhang err_disable_clks: 2035ec55823SJoakim Zhang pm_runtime_put(priv->device); 2045ec55823SJoakim Zhang 2055ec55823SJoakim Zhang return ret; 2066fc21117SJose Abreu } 2076fc21117SJose Abreu 2087ac6653aSJeff Kirsher /** 2097ac6653aSJeff Kirsher * stmmac_mdio_read 2107ac6653aSJeff Kirsher * @bus: points to the mii_bus structure 211b91dce4cSLABBE Corentin * @phyaddr: MII addr 212b91dce4cSLABBE Corentin * @phyreg: MII reg 2137ac6653aSJeff Kirsher * Description: it reads data from the MII register from within the phy device. 2147ac6653aSJeff Kirsher * For the 7111 GMAC, we must set the bit 0 in the MII address register while 2157ac6653aSJeff Kirsher * accessing the PHY registers. 2167ac6653aSJeff Kirsher * Fortunately, it seems this has no drawback for the 7109 MAC. 2177ac6653aSJeff Kirsher */ 2187ac6653aSJeff Kirsher static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) 2197ac6653aSJeff Kirsher { 2207ac6653aSJeff Kirsher struct net_device *ndev = bus->priv; 2217ac6653aSJeff Kirsher struct stmmac_priv *priv = netdev_priv(ndev); 2227ac6653aSJeff Kirsher unsigned int mii_address = priv->hw->mii.addr; 2237ac6653aSJeff Kirsher unsigned int mii_data = priv->hw->mii.data; 224b91dce4cSLABBE Corentin u32 value = MII_BUSY; 225d4117d63SKweh Hock Leong int data = 0; 226d4117d63SKweh Hock Leong u32 v; 227b91dce4cSLABBE Corentin 228e2d0acd4SMinghao Chi data = pm_runtime_resume_and_get(priv->device); 229e2d0acd4SMinghao Chi if (data < 0) 2305ec55823SJoakim Zhang return data; 2315ec55823SJoakim Zhang 232b91dce4cSLABBE Corentin value |= (phyaddr << priv->hw->mii.addr_shift) 233b91dce4cSLABBE Corentin & priv->hw->mii.addr_mask; 234b91dce4cSLABBE Corentin value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; 235567be786Sjpinto value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) 236567be786Sjpinto & priv->hw->mii.clk_csr_mask; 237d4117d63SKweh Hock Leong if (priv->plat->has_gmac4) { 238b91dce4cSLABBE Corentin value |= MII_GMAC4_READ; 239d4117d63SKweh Hock Leong if (phyreg & MII_ADDR_C45) { 240d4117d63SKweh Hock Leong value |= MII_GMAC4_C45E; 241d4117d63SKweh Hock Leong value &= ~priv->hw->mii.reg_mask; 242d4117d63SKweh Hock Leong value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) << 243d4117d63SKweh Hock Leong priv->hw->mii.reg_shift) & 244d4117d63SKweh Hock Leong priv->hw->mii.reg_mask; 245d4117d63SKweh Hock Leong 246d4117d63SKweh Hock Leong data |= (phyreg & MII_REGADDR_C45_MASK) << 247d4117d63SKweh Hock Leong MII_GMAC4_REG_ADDR_SHIFT; 248d4117d63SKweh Hock Leong } 249d4117d63SKweh Hock Leong } 2507ac6653aSJeff Kirsher 251a5f48adcSLABBE Corentin if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), 2525ec55823SJoakim Zhang 100, 10000)) { 2535ec55823SJoakim Zhang data = -EBUSY; 2545ec55823SJoakim Zhang goto err_disable_clks; 2555ec55823SJoakim Zhang } 25639b401dbSDeepak SIKRI 257d4117d63SKweh Hock Leong writel(data, priv->ioaddr + mii_data); 25801f1f615SLABBE Corentin writel(value, priv->ioaddr + mii_address); 25939b401dbSDeepak SIKRI 260a5f48adcSLABBE Corentin if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), 2615ec55823SJoakim Zhang 100, 10000)) { 2625ec55823SJoakim Zhang data = -EBUSY; 2635ec55823SJoakim Zhang goto err_disable_clks; 2645ec55823SJoakim Zhang } 2657ac6653aSJeff Kirsher 2667ac6653aSJeff Kirsher /* Read the data from the MII data register */ 267d4117d63SKweh Hock Leong data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK; 2687ac6653aSJeff Kirsher 2695ec55823SJoakim Zhang err_disable_clks: 2705ec55823SJoakim Zhang pm_runtime_put(priv->device); 2715ec55823SJoakim Zhang 2727ac6653aSJeff Kirsher return data; 2737ac6653aSJeff Kirsher } 2747ac6653aSJeff Kirsher 2757ac6653aSJeff Kirsher /** 2767ac6653aSJeff Kirsher * stmmac_mdio_write 2777ac6653aSJeff Kirsher * @bus: points to the mii_bus structure 278b91dce4cSLABBE Corentin * @phyaddr: MII addr 279b91dce4cSLABBE Corentin * @phyreg: MII reg 2807ac6653aSJeff Kirsher * @phydata: phy data 2817ac6653aSJeff Kirsher * Description: it writes the data into the MII register from within the device. 2827ac6653aSJeff Kirsher */ 2837ac6653aSJeff Kirsher static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, 2847ac6653aSJeff Kirsher u16 phydata) 2857ac6653aSJeff Kirsher { 2867ac6653aSJeff Kirsher struct net_device *ndev = bus->priv; 2877ac6653aSJeff Kirsher struct stmmac_priv *priv = netdev_priv(ndev); 2887ac6653aSJeff Kirsher unsigned int mii_address = priv->hw->mii.addr; 2897ac6653aSJeff Kirsher unsigned int mii_data = priv->hw->mii.data; 2905ec55823SJoakim Zhang int ret, data = phydata; 2915799fc90SKweh, Hock Leong u32 value = MII_BUSY; 292d4117d63SKweh Hock Leong u32 v; 2937ac6653aSJeff Kirsher 294e2d0acd4SMinghao Chi ret = pm_runtime_resume_and_get(priv->device); 295e2d0acd4SMinghao Chi if (ret < 0) 2965ec55823SJoakim Zhang return ret; 2975ec55823SJoakim Zhang 298b91dce4cSLABBE Corentin value |= (phyaddr << priv->hw->mii.addr_shift) 299b91dce4cSLABBE Corentin & priv->hw->mii.addr_mask; 300b91dce4cSLABBE Corentin value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; 3017ac6653aSJeff Kirsher 302567be786Sjpinto value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) 303567be786Sjpinto & priv->hw->mii.clk_csr_mask; 304d4117d63SKweh Hock Leong if (priv->plat->has_gmac4) { 305b91dce4cSLABBE Corentin value |= MII_GMAC4_WRITE; 306d4117d63SKweh Hock Leong if (phyreg & MII_ADDR_C45) { 307d4117d63SKweh Hock Leong value |= MII_GMAC4_C45E; 308d4117d63SKweh Hock Leong value &= ~priv->hw->mii.reg_mask; 309d4117d63SKweh Hock Leong value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) << 310d4117d63SKweh Hock Leong priv->hw->mii.reg_shift) & 311d4117d63SKweh Hock Leong priv->hw->mii.reg_mask; 312d4117d63SKweh Hock Leong 313d4117d63SKweh Hock Leong data |= (phyreg & MII_REGADDR_C45_MASK) << 314d4117d63SKweh Hock Leong MII_GMAC4_REG_ADDR_SHIFT; 315d4117d63SKweh Hock Leong } 316d4117d63SKweh Hock Leong } else { 3175799fc90SKweh, Hock Leong value |= MII_WRITE; 318d4117d63SKweh Hock Leong } 319ac1f74a7SAlexandre TORGUE 320ac1f74a7SAlexandre TORGUE /* Wait until any existing MII operation is complete */ 321a5f48adcSLABBE Corentin if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), 3225ec55823SJoakim Zhang 100, 10000)) { 3235ec55823SJoakim Zhang ret = -EBUSY; 3245ec55823SJoakim Zhang goto err_disable_clks; 3255ec55823SJoakim Zhang } 326ac1f74a7SAlexandre TORGUE 327ac1f74a7SAlexandre TORGUE /* Set the MII address register to write */ 328d4117d63SKweh Hock Leong writel(data, priv->ioaddr + mii_data); 329ac1f74a7SAlexandre TORGUE writel(value, priv->ioaddr + mii_address); 330ac1f74a7SAlexandre TORGUE 331ac1f74a7SAlexandre TORGUE /* Wait until any existing MII operation is complete */ 3325ec55823SJoakim Zhang ret = readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), 333a5f48adcSLABBE Corentin 100, 10000); 3345ec55823SJoakim Zhang 3355ec55823SJoakim Zhang err_disable_clks: 3365ec55823SJoakim Zhang pm_runtime_put(priv->device); 3375ec55823SJoakim Zhang 3385ec55823SJoakim Zhang return ret; 339ac1f74a7SAlexandre TORGUE } 340ac1f74a7SAlexandre TORGUE 341ac1f74a7SAlexandre TORGUE /** 3427ac6653aSJeff Kirsher * stmmac_mdio_reset 3437ac6653aSJeff Kirsher * @bus: points to the mii_bus structure 3447ac6653aSJeff Kirsher * Description: reset the MII bus 3457ac6653aSJeff Kirsher */ 346073752aaSSrinivas Kandagatla int stmmac_mdio_reset(struct mii_bus *bus) 3477ac6653aSJeff Kirsher { 34830549aabSNiklas Cassel #if IS_ENABLED(CONFIG_STMMAC_PLATFORM) 3497ac6653aSJeff Kirsher struct net_device *ndev = bus->priv; 3507ac6653aSJeff Kirsher struct stmmac_priv *priv = netdev_priv(ndev); 3517ac6653aSJeff Kirsher unsigned int mii_address = priv->hw->mii.addr; 3527ac6653aSJeff Kirsher 3530e076471SSrinivas Kandagatla #ifdef CONFIG_OF 3540e076471SSrinivas Kandagatla if (priv->device->of_node) { 3557c86f20dSMartin Blumenstingl struct gpio_desc *reset_gpio; 35684ce4d0fSMartin Blumenstingl u32 delays[3] = { 0, 0, 0 }; 3577c86f20dSMartin Blumenstingl 3587c86f20dSMartin Blumenstingl reset_gpio = devm_gpiod_get_optional(priv->device, 3597c86f20dSMartin Blumenstingl "snps,reset", 3607c86f20dSMartin Blumenstingl GPIOD_OUT_LOW); 3617c86f20dSMartin Blumenstingl if (IS_ERR(reset_gpio)) 3627c86f20dSMartin Blumenstingl return PTR_ERR(reset_gpio); 3630e076471SSrinivas Kandagatla 364cc5e92c2SMartin Blumenstingl device_property_read_u32_array(priv->device, 36542a90766SMartin Blumenstingl "snps,reset-delays-us", 366cc5e92c2SMartin Blumenstingl delays, ARRAY_SIZE(delays)); 3670e076471SSrinivas Kandagatla 368ce4ab73aSMartin Blumenstingl if (delays[0]) 369ce4ab73aSMartin Blumenstingl msleep(DIV_ROUND_UP(delays[0], 1000)); 370892aa01dSSjoerd Simons 3717c86f20dSMartin Blumenstingl gpiod_set_value_cansleep(reset_gpio, 1); 372ce4ab73aSMartin Blumenstingl if (delays[1]) 373ce4ab73aSMartin Blumenstingl msleep(DIV_ROUND_UP(delays[1], 1000)); 374892aa01dSSjoerd Simons 3757c86f20dSMartin Blumenstingl gpiod_set_value_cansleep(reset_gpio, 0); 376ce4ab73aSMartin Blumenstingl if (delays[2]) 377ce4ab73aSMartin Blumenstingl msleep(DIV_ROUND_UP(delays[2], 1000)); 3780e076471SSrinivas Kandagatla } 3790e076471SSrinivas Kandagatla #endif 3800e076471SSrinivas Kandagatla 3817ac6653aSJeff Kirsher /* This is a workaround for problems with the STE101P PHY. 3827ac6653aSJeff Kirsher * It doesn't complete its reset until at least one clock cycle 3838d45e42bSLABBE Corentin * on MDC, so perform a dummy mdio read. To be updated for GMAC4 384ac1f74a7SAlexandre TORGUE * if needed. 3857ac6653aSJeff Kirsher */ 386ac1f74a7SAlexandre TORGUE if (!priv->plat->has_gmac4) 3877ac6653aSJeff Kirsher writel(0, priv->ioaddr + mii_address); 388bfab27a1SGiuseppe CAVALLARO #endif 3897ac6653aSJeff Kirsher return 0; 3907ac6653aSJeff Kirsher } 3917ac6653aSJeff Kirsher 392597a68ceSVoon Weifeng int stmmac_xpcs_setup(struct mii_bus *bus) 393597a68ceSVoon Weifeng { 394597a68ceSVoon Weifeng struct net_device *ndev = bus->priv; 395597a68ceSVoon Weifeng struct mdio_device *mdiodev; 39647538dbeSVladimir Oltean struct stmmac_priv *priv; 39747538dbeSVladimir Oltean struct dw_xpcs *xpcs; 39847538dbeSVladimir Oltean int mode, addr; 399597a68ceSVoon Weifeng 400597a68ceSVoon Weifeng priv = netdev_priv(ndev); 401597a68ceSVoon Weifeng mode = priv->plat->phy_interface; 402597a68ceSVoon Weifeng 403597a68ceSVoon Weifeng /* Try to probe the XPCS by scanning all addresses. */ 404597a68ceSVoon Weifeng for (addr = 0; addr < PHY_MAX_ADDR; addr++) { 405597a68ceSVoon Weifeng mdiodev = mdio_device_create(bus, addr); 406597a68ceSVoon Weifeng if (IS_ERR(mdiodev)) 407597a68ceSVoon Weifeng continue; 408597a68ceSVoon Weifeng 409597a68ceSVoon Weifeng xpcs = xpcs_create(mdiodev, mode); 410597a68ceSVoon Weifeng if (IS_ERR_OR_NULL(xpcs)) { 411597a68ceSVoon Weifeng mdio_device_free(mdiodev); 412597a68ceSVoon Weifeng continue; 413597a68ceSVoon Weifeng } 414597a68ceSVoon Weifeng 415597a68ceSVoon Weifeng priv->hw->xpcs = xpcs; 416597a68ceSVoon Weifeng break; 417597a68ceSVoon Weifeng } 418597a68ceSVoon Weifeng 419597a68ceSVoon Weifeng if (!priv->hw->xpcs) { 420597a68ceSVoon Weifeng dev_warn(priv->device, "No xPCS found\n"); 421597a68ceSVoon Weifeng return -ENODEV; 422597a68ceSVoon Weifeng } 423597a68ceSVoon Weifeng 424597a68ceSVoon Weifeng return 0; 425597a68ceSVoon Weifeng } 426597a68ceSVoon Weifeng 4277ac6653aSJeff Kirsher /** 4287ac6653aSJeff Kirsher * stmmac_mdio_register 4297ac6653aSJeff Kirsher * @ndev: net device structure 4307ac6653aSJeff Kirsher * Description: it registers the MII bus 4317ac6653aSJeff Kirsher */ 4327ac6653aSJeff Kirsher int stmmac_mdio_register(struct net_device *ndev) 4337ac6653aSJeff Kirsher { 4347ac6653aSJeff Kirsher int err = 0; 4357ac6653aSJeff Kirsher struct mii_bus *new_bus; 4367ac6653aSJeff Kirsher struct stmmac_priv *priv = netdev_priv(ndev); 437*ab21cf92SOng Boon Leong struct fwnode_handle *fwnode = of_fwnode_handle(priv->plat->phylink_node); 4387ac6653aSJeff Kirsher struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data; 439a7657f12SGiuseppe CAVALLARO struct device_node *mdio_node = priv->plat->mdio_node; 440fbca1647SRomain Perier struct device *dev = ndev->dev.parent; 441*ab21cf92SOng Boon Leong struct fwnode_handle *fixed_node; 4426fc21117SJose Abreu int addr, found, max_addr; 4437ac6653aSJeff Kirsher 4447ac6653aSJeff Kirsher if (!mdio_bus_data) 4457ac6653aSJeff Kirsher return 0; 4467ac6653aSJeff Kirsher 4477ac6653aSJeff Kirsher new_bus = mdiobus_alloc(); 448efd89b60SLABBE Corentin if (!new_bus) 4497ac6653aSJeff Kirsher return -ENOMEM; 4507ac6653aSJeff Kirsher 451e7f4dc35SAndrew Lunn if (mdio_bus_data->irqs) 452643d60bfSMarek Vasut memcpy(new_bus->irq, mdio_bus_data->irqs, sizeof(new_bus->irq)); 4537ac6653aSJeff Kirsher 45490b9a545SAlessandro Rubini new_bus->name = "stmmac"; 4556fc21117SJose Abreu 456523437d7SWong Vee Khee if (priv->plat->has_gmac4) 457523437d7SWong Vee Khee new_bus->probe_capabilities = MDIOBUS_C22_C45; 458523437d7SWong Vee Khee 4596fc21117SJose Abreu if (priv->plat->has_xgmac) { 4606fc21117SJose Abreu new_bus->read = &stmmac_xgmac2_mdio_read; 4616fc21117SJose Abreu new_bus->write = &stmmac_xgmac2_mdio_write; 4626fc21117SJose Abreu 4636fc21117SJose Abreu /* Right now only C22 phys are supported */ 4646fc21117SJose Abreu max_addr = MII_XGMAC_MAX_C22ADDR + 1; 4656fc21117SJose Abreu 4666fc21117SJose Abreu /* Check if DT specified an unsupported phy addr */ 4676fc21117SJose Abreu if (priv->plat->phy_addr > MII_XGMAC_MAX_C22ADDR) 4686fc21117SJose Abreu dev_err(dev, "Unsupported phy_addr (max=%d)\n", 4696fc21117SJose Abreu MII_XGMAC_MAX_C22ADDR); 4706fc21117SJose Abreu } else { 4717ac6653aSJeff Kirsher new_bus->read = &stmmac_mdio_read; 4727ac6653aSJeff Kirsher new_bus->write = &stmmac_mdio_write; 4736fc21117SJose Abreu max_addr = PHY_MAX_ADDR; 4746fc21117SJose Abreu } 475ac1f74a7SAlexandre TORGUE 4761a981c05SThierry Reding if (mdio_bus_data->needs_reset) 4777ac6653aSJeff Kirsher new_bus->reset = &stmmac_mdio_reset; 4781a981c05SThierry Reding 479db8857bfSFlorian Fainelli snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x", 480d56631a6SSrinivas Kandagatla new_bus->name, priv->plat->bus_id); 4817ac6653aSJeff Kirsher new_bus->priv = ndev; 4827ac6653aSJeff Kirsher new_bus->phy_mask = mdio_bus_data->phy_mask; 4837ac6653aSJeff Kirsher new_bus->parent = priv->device; 484e34d6569SPhil Reid 485e34d6569SPhil Reid err = of_mdiobus_register(new_bus, mdio_node); 4867ac6653aSJeff Kirsher if (err != 0) { 487839612d2SRasmus Villemoes dev_err_probe(dev, err, "Cannot register the MDIO bus\n"); 4887ac6653aSJeff Kirsher goto bus_register_fail; 4897ac6653aSJeff Kirsher } 4907ac6653aSJeff Kirsher 49104d1190aSJose Abreu /* Looks like we need a dummy read for XGMAC only and C45 PHYs */ 49204d1190aSJose Abreu if (priv->plat->has_xgmac) 49304d1190aSJose Abreu stmmac_xgmac2_mdio_read(new_bus, 0, MII_ADDR_C45); 49404d1190aSJose Abreu 495*ab21cf92SOng Boon Leong /* If fixed-link is set, skip PHY scanning */ 496*ab21cf92SOng Boon Leong if (!fwnode) 497*ab21cf92SOng Boon Leong fwnode = dev_fwnode(priv->device); 498*ab21cf92SOng Boon Leong 499*ab21cf92SOng Boon Leong if (fwnode) { 500*ab21cf92SOng Boon Leong fixed_node = fwnode_get_named_child_node(fwnode, "fixed-link"); 501*ab21cf92SOng Boon Leong if (fixed_node) { 502*ab21cf92SOng Boon Leong fwnode_handle_put(fixed_node); 503*ab21cf92SOng Boon Leong goto bus_register_done; 504*ab21cf92SOng Boon Leong } 505*ab21cf92SOng Boon Leong } 506*ab21cf92SOng Boon Leong 507cc2fa619SPhil Reid if (priv->plat->phy_node || mdio_node) 508cc2fa619SPhil Reid goto bus_register_done; 509cc2fa619SPhil Reid 5107ac6653aSJeff Kirsher found = 0; 5116fc21117SJose Abreu for (addr = 0; addr < max_addr; addr++) { 5127f854420SAndrew Lunn struct phy_device *phydev = mdiobus_get_phy(new_bus, addr); 5137ac6653aSJeff Kirsher 514cc26dc67SLABBE Corentin if (!phydev) 515cc26dc67SLABBE Corentin continue; 516cc26dc67SLABBE Corentin 5177ac6653aSJeff Kirsher /* 5187ac6653aSJeff Kirsher * If an IRQ was provided to be assigned after 5197ac6653aSJeff Kirsher * the bus probe, do it here. 5207ac6653aSJeff Kirsher */ 521cb2c0aceSLABBE Corentin if (!mdio_bus_data->irqs && 5227ac6653aSJeff Kirsher (mdio_bus_data->probed_phy_irq > 0)) { 523cc26dc67SLABBE Corentin new_bus->irq[addr] = mdio_bus_data->probed_phy_irq; 5247ac6653aSJeff Kirsher phydev->irq = mdio_bus_data->probed_phy_irq; 5257ac6653aSJeff Kirsher } 5267ac6653aSJeff Kirsher 5277ac6653aSJeff Kirsher /* 5287ac6653aSJeff Kirsher * If we're going to bind the MAC to this PHY bus, 5297ac6653aSJeff Kirsher * and no PHY number was provided to the MAC, 5307ac6653aSJeff Kirsher * use the one probed here. 5317ac6653aSJeff Kirsher */ 532d56631a6SSrinivas Kandagatla if (priv->plat->phy_addr == -1) 5337ac6653aSJeff Kirsher priv->plat->phy_addr = addr; 5347ac6653aSJeff Kirsher 535fbca1647SRomain Perier phy_attached_info(phydev); 5367ac6653aSJeff Kirsher found = 1; 5377ac6653aSJeff Kirsher } 5387ac6653aSJeff Kirsher 5394751d2aaSVladimir Oltean if (!found && !mdio_node) { 5404751d2aaSVladimir Oltean dev_warn(dev, "No PHY found\n"); 5414751d2aaSVladimir Oltean err = -ENODEV; 5424751d2aaSVladimir Oltean goto no_phy_found; 5434751d2aaSVladimir Oltean } 5444751d2aaSVladimir Oltean 545cc2fa619SPhil Reid bus_register_done: 5463955b22bSGiuseppe CAVALLARO priv->mii = new_bus; 5477ac6653aSJeff Kirsher 5487ac6653aSJeff Kirsher return 0; 5497ac6653aSJeff Kirsher 5504751d2aaSVladimir Oltean no_phy_found: 5514751d2aaSVladimir Oltean mdiobus_unregister(new_bus); 5527ac6653aSJeff Kirsher bus_register_fail: 5537ac6653aSJeff Kirsher mdiobus_free(new_bus); 5547ac6653aSJeff Kirsher return err; 5557ac6653aSJeff Kirsher } 5567ac6653aSJeff Kirsher 5577ac6653aSJeff Kirsher /** 5587ac6653aSJeff Kirsher * stmmac_mdio_unregister 5597ac6653aSJeff Kirsher * @ndev: net device structure 5607ac6653aSJeff Kirsher * Description: it unregisters the MII bus 5617ac6653aSJeff Kirsher */ 5627ac6653aSJeff Kirsher int stmmac_mdio_unregister(struct net_device *ndev) 5637ac6653aSJeff Kirsher { 5647ac6653aSJeff Kirsher struct stmmac_priv *priv = netdev_priv(ndev); 5657ac6653aSJeff Kirsher 566a5cf5ce9SSrinivas Kandagatla if (!priv->mii) 567a5cf5ce9SSrinivas Kandagatla return 0; 568a5cf5ce9SSrinivas Kandagatla 5692cac15daSVladimir Oltean if (priv->hw->xpcs) { 57011059740SVladimir Oltean mdio_device_free(priv->hw->xpcs->mdiodev); 57111059740SVladimir Oltean xpcs_destroy(priv->hw->xpcs); 5722cac15daSVladimir Oltean } 5732cac15daSVladimir Oltean 5747ac6653aSJeff Kirsher mdiobus_unregister(priv->mii); 5757ac6653aSJeff Kirsher priv->mii->priv = NULL; 5767ac6653aSJeff Kirsher mdiobus_free(priv->mii); 5777ac6653aSJeff Kirsher priv->mii = NULL; 5787ac6653aSJeff Kirsher 5797ac6653aSJeff Kirsher return 0; 5807ac6653aSJeff Kirsher } 581