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