| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /******************************************************************************* |
|---|
| 2 | 3 | STMMAC Ethernet Driver -- MDIO bus implementation |
|---|
| 3 | 4 | Provides Bus interface for MII registers |
|---|
| 4 | 5 | |
|---|
| 5 | 6 | Copyright (C) 2007-2009 STMicroelectronics Ltd |
|---|
| 6 | 7 | |
|---|
| 7 | | - This program is free software; you can redistribute it and/or modify it |
|---|
| 8 | | - under the terms and conditions of the GNU General Public License, |
|---|
| 9 | | - version 2, as published by the Free Software Foundation. |
|---|
| 10 | | - |
|---|
| 11 | | - This program is distributed in the hope it will be useful, but WITHOUT |
|---|
| 12 | | - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 13 | | - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 14 | | - more details. |
|---|
| 15 | | - |
|---|
| 16 | | - The full GNU General Public License is included in this distribution in |
|---|
| 17 | | - the file called "COPYING". |
|---|
| 18 | 8 | |
|---|
| 19 | 9 | Author: Carl Shaw <carl.shaw@st.com> |
|---|
| 20 | 10 | Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com> |
|---|
| 21 | 11 | *******************************************************************************/ |
|---|
| 22 | 12 | |
|---|
| 13 | +#include <linux/gpio/consumer.h> |
|---|
| 23 | 14 | #include <linux/io.h> |
|---|
| 24 | 15 | #include <linux/iopoll.h> |
|---|
| 25 | 16 | #include <linux/mii.h> |
|---|
| 26 | | -#include <linux/of.h> |
|---|
| 27 | | -#include <linux/of_gpio.h> |
|---|
| 28 | 17 | #include <linux/of_mdio.h> |
|---|
| 18 | +#include <linux/pm_runtime.h> |
|---|
| 29 | 19 | #include <linux/phy.h> |
|---|
| 20 | +#include <linux/property.h> |
|---|
| 30 | 21 | #include <linux/slab.h> |
|---|
| 31 | 22 | |
|---|
| 32 | 23 | #include "dwxgmac2.h" |
|---|
| .. | .. |
|---|
| 34 | 25 | |
|---|
| 35 | 26 | #define MII_BUSY 0x00000001 |
|---|
| 36 | 27 | #define MII_WRITE 0x00000002 |
|---|
| 28 | +#define MII_DATA_MASK GENMASK(15, 0) |
|---|
| 37 | 29 | |
|---|
| 38 | 30 | /* GMAC4 defines */ |
|---|
| 39 | 31 | #define MII_GMAC4_GOC_SHIFT 2 |
|---|
| 32 | +#define MII_GMAC4_REG_ADDR_SHIFT 16 |
|---|
| 40 | 33 | #define MII_GMAC4_WRITE (1 << MII_GMAC4_GOC_SHIFT) |
|---|
| 41 | 34 | #define MII_GMAC4_READ (3 << MII_GMAC4_GOC_SHIFT) |
|---|
| 35 | +#define MII_GMAC4_C45E BIT(1) |
|---|
| 42 | 36 | |
|---|
| 43 | 37 | /* XGMAC defines */ |
|---|
| 44 | 38 | #define MII_XGMAC_SADDR BIT(18) |
|---|
| .. | .. |
|---|
| 48 | 42 | #define MII_XGMAC_BUSY BIT(22) |
|---|
| 49 | 43 | #define MII_XGMAC_MAX_C22ADDR 3 |
|---|
| 50 | 44 | #define MII_XGMAC_C22P_MASK GENMASK(MII_XGMAC_MAX_C22ADDR, 0) |
|---|
| 45 | +#define MII_XGMAC_PA_SHIFT 16 |
|---|
| 46 | +#define MII_XGMAC_DA_SHIFT 21 |
|---|
| 47 | + |
|---|
| 48 | +static int stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr, |
|---|
| 49 | + int phyreg, u32 *hw_addr) |
|---|
| 50 | +{ |
|---|
| 51 | + u32 tmp; |
|---|
| 52 | + |
|---|
| 53 | + /* Set port as Clause 45 */ |
|---|
| 54 | + tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P); |
|---|
| 55 | + tmp &= ~BIT(phyaddr); |
|---|
| 56 | + writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P); |
|---|
| 57 | + |
|---|
| 58 | + *hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0xffff); |
|---|
| 59 | + *hw_addr |= (phyreg >> MII_DEVADDR_C45_SHIFT) << MII_XGMAC_DA_SHIFT; |
|---|
| 60 | + return 0; |
|---|
| 61 | +} |
|---|
| 51 | 62 | |
|---|
| 52 | 63 | static int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr, |
|---|
| 53 | 64 | int phyreg, u32 *hw_addr) |
|---|
| 54 | 65 | { |
|---|
| 55 | | - unsigned int mii_data = priv->hw->mii.data; |
|---|
| 56 | 66 | u32 tmp; |
|---|
| 57 | 67 | |
|---|
| 58 | 68 | /* HW does not support C22 addr >= 4 */ |
|---|
| 59 | 69 | if (phyaddr > MII_XGMAC_MAX_C22ADDR) |
|---|
| 60 | 70 | return -ENODEV; |
|---|
| 61 | | - /* Wait until any existing MII operation is complete */ |
|---|
| 62 | | - if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, |
|---|
| 63 | | - !(tmp & MII_XGMAC_BUSY), 100, 10000)) |
|---|
| 64 | | - return -EBUSY; |
|---|
| 65 | 71 | |
|---|
| 66 | 72 | /* Set port as Clause 22 */ |
|---|
| 67 | 73 | tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P); |
|---|
| .. | .. |
|---|
| 69 | 75 | tmp |= BIT(phyaddr); |
|---|
| 70 | 76 | writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P); |
|---|
| 71 | 77 | |
|---|
| 72 | | - *hw_addr = (phyaddr << 16) | (phyreg & 0x1f); |
|---|
| 78 | + *hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0x1f); |
|---|
| 73 | 79 | return 0; |
|---|
| 74 | 80 | } |
|---|
| 75 | 81 | |
|---|
| .. | .. |
|---|
| 82 | 88 | u32 tmp, addr, value = MII_XGMAC_BUSY; |
|---|
| 83 | 89 | int ret; |
|---|
| 84 | 90 | |
|---|
| 91 | + ret = pm_runtime_get_sync(priv->device); |
|---|
| 92 | + if (ret < 0) { |
|---|
| 93 | + pm_runtime_put_noidle(priv->device); |
|---|
| 94 | + return ret; |
|---|
| 95 | + } |
|---|
| 96 | + |
|---|
| 97 | + /* Wait until any existing MII operation is complete */ |
|---|
| 98 | + if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, |
|---|
| 99 | + !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
|---|
| 100 | + ret = -EBUSY; |
|---|
| 101 | + goto err_disable_clks; |
|---|
| 102 | + } |
|---|
| 103 | + |
|---|
| 85 | 104 | if (phyreg & MII_ADDR_C45) { |
|---|
| 86 | | - return -EOPNOTSUPP; |
|---|
| 105 | + phyreg &= ~MII_ADDR_C45; |
|---|
| 106 | + |
|---|
| 107 | + ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr); |
|---|
| 108 | + if (ret) |
|---|
| 109 | + goto err_disable_clks; |
|---|
| 87 | 110 | } else { |
|---|
| 88 | 111 | ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr); |
|---|
| 89 | 112 | if (ret) |
|---|
| 90 | | - return ret; |
|---|
| 113 | + goto err_disable_clks; |
|---|
| 114 | + |
|---|
| 115 | + value |= MII_XGMAC_SADDR; |
|---|
| 91 | 116 | } |
|---|
| 92 | 117 | |
|---|
| 93 | 118 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
|---|
| 94 | 119 | & priv->hw->mii.clk_csr_mask; |
|---|
| 95 | | - value |= MII_XGMAC_SADDR | MII_XGMAC_READ; |
|---|
| 120 | + value |= MII_XGMAC_READ; |
|---|
| 96 | 121 | |
|---|
| 97 | 122 | /* Wait until any existing MII operation is complete */ |
|---|
| 98 | 123 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, |
|---|
| 99 | | - !(tmp & MII_XGMAC_BUSY), 100, 10000)) |
|---|
| 100 | | - return -EBUSY; |
|---|
| 124 | + !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
|---|
| 125 | + ret = -EBUSY; |
|---|
| 126 | + goto err_disable_clks; |
|---|
| 127 | + } |
|---|
| 101 | 128 | |
|---|
| 102 | 129 | /* Set the MII address register to read */ |
|---|
| 103 | 130 | writel(addr, priv->ioaddr + mii_address); |
|---|
| .. | .. |
|---|
| 105 | 132 | |
|---|
| 106 | 133 | /* Wait until any existing MII operation is complete */ |
|---|
| 107 | 134 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, |
|---|
| 108 | | - !(tmp & MII_XGMAC_BUSY), 100, 10000)) |
|---|
| 109 | | - return -EBUSY; |
|---|
| 135 | + !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
|---|
| 136 | + ret = -EBUSY; |
|---|
| 137 | + goto err_disable_clks; |
|---|
| 138 | + } |
|---|
| 110 | 139 | |
|---|
| 111 | 140 | /* Read the data from the MII data register */ |
|---|
| 112 | | - return readl(priv->ioaddr + mii_data) & GENMASK(15, 0); |
|---|
| 141 | + ret = (int)readl(priv->ioaddr + mii_data) & GENMASK(15, 0); |
|---|
| 142 | + |
|---|
| 143 | +err_disable_clks: |
|---|
| 144 | + pm_runtime_put(priv->device); |
|---|
| 145 | + |
|---|
| 146 | + return ret; |
|---|
| 113 | 147 | } |
|---|
| 114 | 148 | |
|---|
| 115 | 149 | static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr, |
|---|
| .. | .. |
|---|
| 122 | 156 | u32 addr, tmp, value = MII_XGMAC_BUSY; |
|---|
| 123 | 157 | int ret; |
|---|
| 124 | 158 | |
|---|
| 159 | + ret = pm_runtime_get_sync(priv->device); |
|---|
| 160 | + if (ret < 0) { |
|---|
| 161 | + pm_runtime_put_noidle(priv->device); |
|---|
| 162 | + return ret; |
|---|
| 163 | + } |
|---|
| 164 | + |
|---|
| 165 | + /* Wait until any existing MII operation is complete */ |
|---|
| 166 | + if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, |
|---|
| 167 | + !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
|---|
| 168 | + ret = -EBUSY; |
|---|
| 169 | + goto err_disable_clks; |
|---|
| 170 | + } |
|---|
| 171 | + |
|---|
| 125 | 172 | if (phyreg & MII_ADDR_C45) { |
|---|
| 126 | | - return -EOPNOTSUPP; |
|---|
| 173 | + phyreg &= ~MII_ADDR_C45; |
|---|
| 174 | + |
|---|
| 175 | + ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr); |
|---|
| 176 | + if (ret) |
|---|
| 177 | + goto err_disable_clks; |
|---|
| 127 | 178 | } else { |
|---|
| 128 | 179 | ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr); |
|---|
| 129 | 180 | if (ret) |
|---|
| 130 | | - return ret; |
|---|
| 181 | + goto err_disable_clks; |
|---|
| 182 | + |
|---|
| 183 | + value |= MII_XGMAC_SADDR; |
|---|
| 131 | 184 | } |
|---|
| 132 | 185 | |
|---|
| 133 | 186 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
|---|
| 134 | 187 | & priv->hw->mii.clk_csr_mask; |
|---|
| 135 | | - value |= phydata | MII_XGMAC_SADDR; |
|---|
| 188 | + value |= phydata; |
|---|
| 136 | 189 | value |= MII_XGMAC_WRITE; |
|---|
| 137 | 190 | |
|---|
| 138 | 191 | /* Wait until any existing MII operation is complete */ |
|---|
| 139 | 192 | if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, |
|---|
| 140 | | - !(tmp & MII_XGMAC_BUSY), 100, 10000)) |
|---|
| 141 | | - return -EBUSY; |
|---|
| 193 | + !(tmp & MII_XGMAC_BUSY), 100, 10000)) { |
|---|
| 194 | + ret = -EBUSY; |
|---|
| 195 | + goto err_disable_clks; |
|---|
| 196 | + } |
|---|
| 142 | 197 | |
|---|
| 143 | 198 | /* Set the MII address register to write */ |
|---|
| 144 | 199 | writel(addr, priv->ioaddr + mii_address); |
|---|
| 145 | 200 | writel(value, priv->ioaddr + mii_data); |
|---|
| 146 | 201 | |
|---|
| 147 | 202 | /* Wait until any existing MII operation is complete */ |
|---|
| 148 | | - return readl_poll_timeout(priv->ioaddr + mii_data, tmp, |
|---|
| 149 | | - !(tmp & MII_XGMAC_BUSY), 100, 10000); |
|---|
| 203 | + ret = readl_poll_timeout(priv->ioaddr + mii_data, tmp, |
|---|
| 204 | + !(tmp & MII_XGMAC_BUSY), 100, 10000); |
|---|
| 205 | + |
|---|
| 206 | +err_disable_clks: |
|---|
| 207 | + pm_runtime_put(priv->device); |
|---|
| 208 | + |
|---|
| 209 | + return ret; |
|---|
| 150 | 210 | } |
|---|
| 151 | 211 | |
|---|
| 152 | 212 | /** |
|---|
| .. | .. |
|---|
| 165 | 225 | struct stmmac_priv *priv = netdev_priv(ndev); |
|---|
| 166 | 226 | unsigned int mii_address = priv->hw->mii.addr; |
|---|
| 167 | 227 | unsigned int mii_data = priv->hw->mii.data; |
|---|
| 168 | | - u32 v; |
|---|
| 169 | | - int data; |
|---|
| 170 | 228 | u32 value = MII_BUSY; |
|---|
| 229 | + int data = 0; |
|---|
| 230 | + u32 v; |
|---|
| 231 | + |
|---|
| 232 | + data = pm_runtime_get_sync(priv->device); |
|---|
| 233 | + if (data < 0) { |
|---|
| 234 | + pm_runtime_put_noidle(priv->device); |
|---|
| 235 | + return data; |
|---|
| 236 | + } |
|---|
| 171 | 237 | |
|---|
| 172 | 238 | value |= (phyaddr << priv->hw->mii.addr_shift) |
|---|
| 173 | 239 | & priv->hw->mii.addr_mask; |
|---|
| 174 | 240 | value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; |
|---|
| 175 | 241 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
|---|
| 176 | 242 | & priv->hw->mii.clk_csr_mask; |
|---|
| 177 | | - if (priv->plat->has_gmac4) |
|---|
| 243 | + if (priv->plat->has_gmac4) { |
|---|
| 178 | 244 | value |= MII_GMAC4_READ; |
|---|
| 245 | + if (phyreg & MII_ADDR_C45) { |
|---|
| 246 | + value |= MII_GMAC4_C45E; |
|---|
| 247 | + value &= ~priv->hw->mii.reg_mask; |
|---|
| 248 | + value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) << |
|---|
| 249 | + priv->hw->mii.reg_shift) & |
|---|
| 250 | + priv->hw->mii.reg_mask; |
|---|
| 251 | + |
|---|
| 252 | + data |= (phyreg & MII_REGADDR_C45_MASK) << |
|---|
| 253 | + MII_GMAC4_REG_ADDR_SHIFT; |
|---|
| 254 | + } |
|---|
| 255 | + } |
|---|
| 179 | 256 | |
|---|
| 180 | 257 | if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), |
|---|
| 181 | | - 100, 10000)) |
|---|
| 182 | | - return -EBUSY; |
|---|
| 258 | + 100, 10000)) { |
|---|
| 259 | + data = -EBUSY; |
|---|
| 260 | + goto err_disable_clks; |
|---|
| 261 | + } |
|---|
| 183 | 262 | |
|---|
| 263 | + writel(data, priv->ioaddr + mii_data); |
|---|
| 184 | 264 | writel(value, priv->ioaddr + mii_address); |
|---|
| 185 | 265 | |
|---|
| 186 | 266 | if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), |
|---|
| 187 | | - 100, 10000)) |
|---|
| 188 | | - return -EBUSY; |
|---|
| 267 | + 100, 10000)) { |
|---|
| 268 | + data = -EBUSY; |
|---|
| 269 | + goto err_disable_clks; |
|---|
| 270 | + } |
|---|
| 189 | 271 | |
|---|
| 190 | 272 | /* Read the data from the MII data register */ |
|---|
| 191 | | - data = (int)readl(priv->ioaddr + mii_data); |
|---|
| 273 | + data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK; |
|---|
| 274 | + |
|---|
| 275 | +err_disable_clks: |
|---|
| 276 | + pm_runtime_put(priv->device); |
|---|
| 192 | 277 | |
|---|
| 193 | 278 | return data; |
|---|
| 194 | 279 | } |
|---|
| .. | .. |
|---|
| 208 | 293 | struct stmmac_priv *priv = netdev_priv(ndev); |
|---|
| 209 | 294 | unsigned int mii_address = priv->hw->mii.addr; |
|---|
| 210 | 295 | unsigned int mii_data = priv->hw->mii.data; |
|---|
| 211 | | - u32 v; |
|---|
| 296 | + int ret, data = phydata; |
|---|
| 212 | 297 | u32 value = MII_BUSY; |
|---|
| 298 | + u32 v; |
|---|
| 299 | + |
|---|
| 300 | + ret = pm_runtime_get_sync(priv->device); |
|---|
| 301 | + if (ret < 0) { |
|---|
| 302 | + pm_runtime_put_noidle(priv->device); |
|---|
| 303 | + return ret; |
|---|
| 304 | + } |
|---|
| 213 | 305 | |
|---|
| 214 | 306 | value |= (phyaddr << priv->hw->mii.addr_shift) |
|---|
| 215 | 307 | & priv->hw->mii.addr_mask; |
|---|
| .. | .. |
|---|
| 217 | 309 | |
|---|
| 218 | 310 | value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) |
|---|
| 219 | 311 | & priv->hw->mii.clk_csr_mask; |
|---|
| 220 | | - if (priv->plat->has_gmac4) |
|---|
| 312 | + if (priv->plat->has_gmac4) { |
|---|
| 221 | 313 | value |= MII_GMAC4_WRITE; |
|---|
| 222 | | - else |
|---|
| 314 | + if (phyreg & MII_ADDR_C45) { |
|---|
| 315 | + value |= MII_GMAC4_C45E; |
|---|
| 316 | + value &= ~priv->hw->mii.reg_mask; |
|---|
| 317 | + value |= ((phyreg >> MII_DEVADDR_C45_SHIFT) << |
|---|
| 318 | + priv->hw->mii.reg_shift) & |
|---|
| 319 | + priv->hw->mii.reg_mask; |
|---|
| 320 | + |
|---|
| 321 | + data |= (phyreg & MII_REGADDR_C45_MASK) << |
|---|
| 322 | + MII_GMAC4_REG_ADDR_SHIFT; |
|---|
| 323 | + } |
|---|
| 324 | + } else { |
|---|
| 223 | 325 | value |= MII_WRITE; |
|---|
| 326 | + } |
|---|
| 224 | 327 | |
|---|
| 225 | 328 | /* Wait until any existing MII operation is complete */ |
|---|
| 226 | 329 | if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), |
|---|
| 227 | | - 100, 10000)) |
|---|
| 228 | | - return -EBUSY; |
|---|
| 330 | + 100, 10000)) { |
|---|
| 331 | + ret = -EBUSY; |
|---|
| 332 | + goto err_disable_clks; |
|---|
| 333 | + } |
|---|
| 229 | 334 | |
|---|
| 230 | 335 | /* Set the MII address register to write */ |
|---|
| 231 | | - writel(phydata, priv->ioaddr + mii_data); |
|---|
| 336 | + writel(data, priv->ioaddr + mii_data); |
|---|
| 232 | 337 | writel(value, priv->ioaddr + mii_address); |
|---|
| 233 | 338 | |
|---|
| 234 | 339 | /* Wait until any existing MII operation is complete */ |
|---|
| 235 | | - return readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), |
|---|
| 236 | | - 100, 10000); |
|---|
| 340 | + ret = readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), |
|---|
| 341 | + 100, 10000); |
|---|
| 342 | + |
|---|
| 343 | +err_disable_clks: |
|---|
| 344 | + pm_runtime_put(priv->device); |
|---|
| 345 | + |
|---|
| 346 | + return ret; |
|---|
| 237 | 347 | } |
|---|
| 238 | 348 | |
|---|
| 239 | 349 | /** |
|---|
| .. | .. |
|---|
| 247 | 357 | struct net_device *ndev = bus->priv; |
|---|
| 248 | 358 | struct stmmac_priv *priv = netdev_priv(ndev); |
|---|
| 249 | 359 | unsigned int mii_address = priv->hw->mii.addr; |
|---|
| 250 | | - struct stmmac_mdio_bus_data *data = priv->plat->mdio_bus_data; |
|---|
| 251 | 360 | |
|---|
| 252 | 361 | #ifdef CONFIG_OF |
|---|
| 253 | 362 | if (priv->device->of_node) { |
|---|
| 254 | | - if (data->reset_gpio < 0) { |
|---|
| 255 | | - struct device_node *np = priv->device->of_node; |
|---|
| 363 | + struct gpio_desc *reset_gpio; |
|---|
| 364 | + u32 delays[3] = { 0, 0, 0 }; |
|---|
| 256 | 365 | |
|---|
| 257 | | - if (!np) |
|---|
| 258 | | - return 0; |
|---|
| 366 | + reset_gpio = devm_gpiod_get_optional(priv->device, |
|---|
| 367 | + "snps,reset", |
|---|
| 368 | + GPIOD_OUT_LOW); |
|---|
| 369 | + if (IS_ERR(reset_gpio)) |
|---|
| 370 | + return PTR_ERR(reset_gpio); |
|---|
| 259 | 371 | |
|---|
| 260 | | - data->reset_gpio = of_get_named_gpio(np, |
|---|
| 261 | | - "snps,reset-gpio", 0); |
|---|
| 262 | | - if (data->reset_gpio < 0) |
|---|
| 263 | | - return 0; |
|---|
| 372 | + device_property_read_u32_array(priv->device, |
|---|
| 373 | + "snps,reset-delays-us", |
|---|
| 374 | + delays, ARRAY_SIZE(delays)); |
|---|
| 264 | 375 | |
|---|
| 265 | | - data->active_low = of_property_read_bool(np, |
|---|
| 266 | | - "snps,reset-active-low"); |
|---|
| 267 | | - of_property_read_u32_array(np, |
|---|
| 268 | | - "snps,reset-delays-us", data->delays, 3); |
|---|
| 376 | + if (delays[0]) |
|---|
| 377 | + msleep(DIV_ROUND_UP(delays[0], 1000)); |
|---|
| 269 | 378 | |
|---|
| 270 | | - if (devm_gpio_request(priv->device, data->reset_gpio, |
|---|
| 271 | | - "mdio-reset")) |
|---|
| 272 | | - return 0; |
|---|
| 273 | | - } |
|---|
| 379 | + gpiod_set_value_cansleep(reset_gpio, 1); |
|---|
| 380 | + if (delays[1]) |
|---|
| 381 | + msleep(DIV_ROUND_UP(delays[1], 1000)); |
|---|
| 274 | 382 | |
|---|
| 275 | | - gpio_direction_output(data->reset_gpio, |
|---|
| 276 | | - data->active_low ? 1 : 0); |
|---|
| 277 | | - if (data->delays[0]) |
|---|
| 278 | | - msleep(DIV_ROUND_UP(data->delays[0], 1000)); |
|---|
| 279 | | - |
|---|
| 280 | | - gpio_set_value(data->reset_gpio, data->active_low ? 0 : 1); |
|---|
| 281 | | - if (data->delays[1]) |
|---|
| 282 | | - msleep(DIV_ROUND_UP(data->delays[1], 1000)); |
|---|
| 283 | | - |
|---|
| 284 | | - gpio_set_value(data->reset_gpio, data->active_low ? 1 : 0); |
|---|
| 285 | | - if (data->delays[2]) |
|---|
| 286 | | - msleep(DIV_ROUND_UP(data->delays[2], 1000)); |
|---|
| 383 | + gpiod_set_value_cansleep(reset_gpio, 0); |
|---|
| 384 | + if (delays[2]) |
|---|
| 385 | + msleep(DIV_ROUND_UP(delays[2], 1000)); |
|---|
| 287 | 386 | } |
|---|
| 288 | 387 | #endif |
|---|
| 289 | | - |
|---|
| 290 | | - if (data->phy_reset) { |
|---|
| 291 | | - netdev_dbg(ndev, "stmmac_mdio_reset: calling phy_reset\n"); |
|---|
| 292 | | - data->phy_reset(priv->plat->bsp_priv); |
|---|
| 293 | | - } |
|---|
| 294 | 388 | |
|---|
| 295 | 389 | /* This is a workaround for problems with the STE101P PHY. |
|---|
| 296 | 390 | * It doesn't complete its reset until at least one clock cycle |
|---|
| .. | .. |
|---|
| 302 | 396 | #endif |
|---|
| 303 | 397 | return 0; |
|---|
| 304 | 398 | } |
|---|
| 399 | +EXPORT_SYMBOL(stmmac_mdio_reset); |
|---|
| 305 | 400 | |
|---|
| 306 | 401 | /** |
|---|
| 307 | 402 | * stmmac_mdio_register |
|---|
| .. | .. |
|---|
| 328 | 423 | if (mdio_bus_data->irqs) |
|---|
| 329 | 424 | memcpy(new_bus->irq, mdio_bus_data->irqs, sizeof(new_bus->irq)); |
|---|
| 330 | 425 | |
|---|
| 331 | | -#ifdef CONFIG_OF |
|---|
| 332 | | - if (priv->device->of_node) |
|---|
| 333 | | - mdio_bus_data->reset_gpio = -1; |
|---|
| 334 | | -#endif |
|---|
| 335 | | - |
|---|
| 336 | 426 | new_bus->name = "stmmac"; |
|---|
| 337 | 427 | |
|---|
| 338 | 428 | if (priv->plat->has_xgmac) { |
|---|
| .. | .. |
|---|
| 352 | 442 | max_addr = PHY_MAX_ADDR; |
|---|
| 353 | 443 | } |
|---|
| 354 | 444 | |
|---|
| 355 | | - new_bus->reset = &stmmac_mdio_reset; |
|---|
| 445 | + if (mdio_bus_data->has_xpcs) { |
|---|
| 446 | + priv->hw->xpcs = mdio_xpcs_get_ops(); |
|---|
| 447 | + if (!priv->hw->xpcs) { |
|---|
| 448 | + err = -ENODEV; |
|---|
| 449 | + goto bus_register_fail; |
|---|
| 450 | + } |
|---|
| 451 | + } |
|---|
| 452 | + |
|---|
| 453 | + if (mdio_bus_data->needs_reset) |
|---|
| 454 | + new_bus->reset = &stmmac_mdio_reset; |
|---|
| 455 | + |
|---|
| 356 | 456 | snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x", |
|---|
| 357 | 457 | new_bus->name, priv->plat->bus_id); |
|---|
| 358 | 458 | new_bus->priv = ndev; |
|---|
| .. | .. |
|---|
| 364 | 464 | dev_err(dev, "Cannot register the MDIO bus\n"); |
|---|
| 365 | 465 | goto bus_register_fail; |
|---|
| 366 | 466 | } |
|---|
| 467 | + |
|---|
| 468 | + /* Looks like we need a dummy read for XGMAC only and C45 PHYs */ |
|---|
| 469 | + if (priv->plat->has_xgmac) |
|---|
| 470 | + stmmac_xgmac2_mdio_read(new_bus, 0, MII_ADDR_C45); |
|---|
| 367 | 471 | |
|---|
| 368 | 472 | if (priv->plat->phy_node || mdio_node) |
|---|
| 369 | 473 | goto bus_register_done; |
|---|
| .. | .. |
|---|
| 399 | 503 | |
|---|
| 400 | 504 | if (!found && !mdio_node) { |
|---|
| 401 | 505 | dev_warn(dev, "No PHY found\n"); |
|---|
| 402 | | - mdiobus_unregister(new_bus); |
|---|
| 403 | | - mdiobus_free(new_bus); |
|---|
| 404 | | - return -ENODEV; |
|---|
| 506 | + err = -ENODEV; |
|---|
| 507 | + goto no_phy_found; |
|---|
| 508 | + } |
|---|
| 509 | + |
|---|
| 510 | + /* Try to probe the XPCS by scanning all addresses. */ |
|---|
| 511 | + if (priv->hw->xpcs) { |
|---|
| 512 | + struct mdio_xpcs_args *xpcs = &priv->hw->xpcs_args; |
|---|
| 513 | + int ret, mode = priv->plat->phy_interface; |
|---|
| 514 | + max_addr = PHY_MAX_ADDR; |
|---|
| 515 | + |
|---|
| 516 | + xpcs->bus = new_bus; |
|---|
| 517 | + |
|---|
| 518 | + found = 0; |
|---|
| 519 | + for (addr = 0; addr < max_addr; addr++) { |
|---|
| 520 | + xpcs->addr = addr; |
|---|
| 521 | + |
|---|
| 522 | + ret = stmmac_xpcs_probe(priv, xpcs, mode); |
|---|
| 523 | + if (!ret) { |
|---|
| 524 | + found = 1; |
|---|
| 525 | + break; |
|---|
| 526 | + } |
|---|
| 527 | + } |
|---|
| 528 | + |
|---|
| 529 | + if (!found && !mdio_node) { |
|---|
| 530 | + dev_warn(dev, "No XPCS found\n"); |
|---|
| 531 | + err = -ENODEV; |
|---|
| 532 | + goto no_xpcs_found; |
|---|
| 533 | + } |
|---|
| 405 | 534 | } |
|---|
| 406 | 535 | |
|---|
| 407 | 536 | bus_register_done: |
|---|
| .. | .. |
|---|
| 409 | 538 | |
|---|
| 410 | 539 | return 0; |
|---|
| 411 | 540 | |
|---|
| 541 | +no_xpcs_found: |
|---|
| 542 | +no_phy_found: |
|---|
| 543 | + mdiobus_unregister(new_bus); |
|---|
| 412 | 544 | bus_register_fail: |
|---|
| 413 | 545 | mdiobus_free(new_bus); |
|---|
| 414 | 546 | return err; |
|---|