root/drivers/net/phy/mdio-bcm-unimac.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. unimac_mdio_readl
  2. unimac_mdio_writel
  3. unimac_mdio_start
  4. unimac_mdio_busy
  5. unimac_mdio_poll
  6. unimac_mdio_read
  7. unimac_mdio_write
  8. unimac_mdio_reset
  9. unimac_mdio_clk_set
  10. unimac_mdio_probe
  11. unimac_mdio_remove
  12. unimac_mdio_suspend
  13. unimac_mdio_resume

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Broadcom UniMAC MDIO bus controller driver
   4  *
   5  * Copyright (C) 2014-2017 Broadcom
   6  */
   7 
   8 #include <linux/kernel.h>
   9 #include <linux/phy.h>
  10 #include <linux/platform_device.h>
  11 #include <linux/sched.h>
  12 #include <linux/module.h>
  13 #include <linux/io.h>
  14 #include <linux/delay.h>
  15 #include <linux/clk.h>
  16 
  17 #include <linux/of.h>
  18 #include <linux/of_platform.h>
  19 #include <linux/of_mdio.h>
  20 
  21 #include <linux/platform_data/mdio-bcm-unimac.h>
  22 
  23 #define MDIO_CMD                0x00
  24 #define  MDIO_START_BUSY        (1 << 29)
  25 #define  MDIO_READ_FAIL         (1 << 28)
  26 #define  MDIO_RD                (2 << 26)
  27 #define  MDIO_WR                (1 << 26)
  28 #define  MDIO_PMD_SHIFT         21
  29 #define  MDIO_PMD_MASK          0x1F
  30 #define  MDIO_REG_SHIFT         16
  31 #define  MDIO_REG_MASK          0x1F
  32 
  33 #define MDIO_CFG                0x04
  34 #define  MDIO_C22               (1 << 0)
  35 #define  MDIO_C45               0
  36 #define  MDIO_CLK_DIV_SHIFT     4
  37 #define  MDIO_CLK_DIV_MASK      0x3F
  38 #define  MDIO_SUPP_PREAMBLE     (1 << 12)
  39 
  40 struct unimac_mdio_priv {
  41         struct mii_bus          *mii_bus;
  42         void __iomem            *base;
  43         int (*wait_func)        (void *wait_func_data);
  44         void                    *wait_func_data;
  45         struct clk              *clk;
  46         u32                     clk_freq;
  47 };
  48 
  49 static inline u32 unimac_mdio_readl(struct unimac_mdio_priv *priv, u32 offset)
  50 {
  51         /* MIPS chips strapped for BE will automagically configure the
  52          * peripheral registers for CPU-native byte order.
  53          */
  54         if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
  55                 return __raw_readl(priv->base + offset);
  56         else
  57                 return readl_relaxed(priv->base + offset);
  58 }
  59 
  60 static inline void unimac_mdio_writel(struct unimac_mdio_priv *priv, u32 val,
  61                                       u32 offset)
  62 {
  63         if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
  64                 __raw_writel(val, priv->base + offset);
  65         else
  66                 writel_relaxed(val, priv->base + offset);
  67 }
  68 
  69 static inline void unimac_mdio_start(struct unimac_mdio_priv *priv)
  70 {
  71         u32 reg;
  72 
  73         reg = unimac_mdio_readl(priv, MDIO_CMD);
  74         reg |= MDIO_START_BUSY;
  75         unimac_mdio_writel(priv, reg, MDIO_CMD);
  76 }
  77 
  78 static inline unsigned int unimac_mdio_busy(struct unimac_mdio_priv *priv)
  79 {
  80         return unimac_mdio_readl(priv, MDIO_CMD) & MDIO_START_BUSY;
  81 }
  82 
  83 static int unimac_mdio_poll(void *wait_func_data)
  84 {
  85         struct unimac_mdio_priv *priv = wait_func_data;
  86         unsigned int timeout = 1000;
  87 
  88         do {
  89                 if (!unimac_mdio_busy(priv))
  90                         return 0;
  91 
  92                 usleep_range(1000, 2000);
  93         } while (--timeout);
  94 
  95         return -ETIMEDOUT;
  96 }
  97 
  98 static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
  99 {
 100         struct unimac_mdio_priv *priv = bus->priv;
 101         int ret;
 102         u32 cmd;
 103 
 104         /* Prepare the read operation */
 105         cmd = MDIO_RD | (phy_id << MDIO_PMD_SHIFT) | (reg << MDIO_REG_SHIFT);
 106         unimac_mdio_writel(priv, cmd, MDIO_CMD);
 107 
 108         /* Start MDIO transaction */
 109         unimac_mdio_start(priv);
 110 
 111         ret = priv->wait_func(priv->wait_func_data);
 112         if (ret)
 113                 return ret;
 114 
 115         cmd = unimac_mdio_readl(priv, MDIO_CMD);
 116 
 117         /* Some broken devices are known not to release the line during
 118          * turn-around, e.g: Broadcom BCM53125 external switches, so check for
 119          * that condition here and ignore the MDIO controller read failure
 120          * indication.
 121          */
 122         if (!(bus->phy_ignore_ta_mask & 1 << phy_id) && (cmd & MDIO_READ_FAIL))
 123                 return -EIO;
 124 
 125         return cmd & 0xffff;
 126 }
 127 
 128 static int unimac_mdio_write(struct mii_bus *bus, int phy_id,
 129                              int reg, u16 val)
 130 {
 131         struct unimac_mdio_priv *priv = bus->priv;
 132         u32 cmd;
 133 
 134         /* Prepare the write operation */
 135         cmd = MDIO_WR | (phy_id << MDIO_PMD_SHIFT) |
 136                 (reg << MDIO_REG_SHIFT) | (0xffff & val);
 137         unimac_mdio_writel(priv, cmd, MDIO_CMD);
 138 
 139         unimac_mdio_start(priv);
 140 
 141         return priv->wait_func(priv->wait_func_data);
 142 }
 143 
 144 /* Workaround for integrated BCM7xxx Gigabit PHYs which have a problem with
 145  * their internal MDIO management controller making them fail to successfully
 146  * be read from or written to for the first transaction.  We insert a dummy
 147  * BMSR read here to make sure that phy_get_device() and get_phy_id() can
 148  * correctly read the PHY MII_PHYSID1/2 registers and successfully register a
 149  * PHY device for this peripheral.
 150  *
 151  * Once the PHY driver is registered, we can workaround subsequent reads from
 152  * there (e.g: during system-wide power management).
 153  *
 154  * bus->reset is invoked before mdiobus_scan during mdiobus_register and is
 155  * therefore the right location to stick that workaround. Since we do not want
 156  * to read from non-existing PHYs, we either use bus->phy_mask or do a manual
 157  * Device Tree scan to limit the search area.
 158  */
 159 static int unimac_mdio_reset(struct mii_bus *bus)
 160 {
 161         struct device_node *np = bus->dev.of_node;
 162         struct device_node *child;
 163         u32 read_mask = 0;
 164         int addr;
 165 
 166         if (!np) {
 167                 read_mask = ~bus->phy_mask;
 168         } else {
 169                 for_each_available_child_of_node(np, child) {
 170                         addr = of_mdio_parse_addr(&bus->dev, child);
 171                         if (addr < 0)
 172                                 continue;
 173 
 174                         read_mask |= 1 << addr;
 175                 }
 176         }
 177 
 178         for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
 179                 if (read_mask & 1 << addr) {
 180                         dev_dbg(&bus->dev, "Workaround for PHY @ %d\n", addr);
 181                         mdiobus_read(bus, addr, MII_BMSR);
 182                 }
 183         }
 184 
 185         return 0;
 186 }
 187 
 188 static void unimac_mdio_clk_set(struct unimac_mdio_priv *priv)
 189 {
 190         unsigned long rate;
 191         u32 reg, div;
 192 
 193         /* Keep the hardware default values */
 194         if (!priv->clk_freq)
 195                 return;
 196 
 197         if (!priv->clk)
 198                 rate = 250000000;
 199         else
 200                 rate = clk_get_rate(priv->clk);
 201 
 202         div = (rate / (2 * priv->clk_freq)) - 1;
 203         if (div & ~MDIO_CLK_DIV_MASK) {
 204                 pr_warn("Incorrect MDIO clock frequency, ignoring\n");
 205                 return;
 206         }
 207 
 208         /* The MDIO clock is the reference clock (typicaly 250Mhz) divided by
 209          * 2 x (MDIO_CLK_DIV + 1)
 210          */
 211         reg = unimac_mdio_readl(priv, MDIO_CFG);
 212         reg &= ~(MDIO_CLK_DIV_MASK << MDIO_CLK_DIV_SHIFT);
 213         reg |= div << MDIO_CLK_DIV_SHIFT;
 214         unimac_mdio_writel(priv, reg, MDIO_CFG);
 215 }
 216 
 217 static int unimac_mdio_probe(struct platform_device *pdev)
 218 {
 219         struct unimac_mdio_pdata *pdata = pdev->dev.platform_data;
 220         struct unimac_mdio_priv *priv;
 221         struct device_node *np;
 222         struct mii_bus *bus;
 223         struct resource *r;
 224         int ret;
 225 
 226         np = pdev->dev.of_node;
 227 
 228         priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 229         if (!priv)
 230                 return -ENOMEM;
 231 
 232         r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 233         if (!r)
 234                 return -EINVAL;
 235 
 236         /* Just ioremap, as this MDIO block is usually integrated into an
 237          * Ethernet MAC controller register range
 238          */
 239         priv->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
 240         if (!priv->base) {
 241                 dev_err(&pdev->dev, "failed to remap register\n");
 242                 return -ENOMEM;
 243         }
 244 
 245         priv->clk = devm_clk_get_optional(&pdev->dev, NULL);
 246         if (IS_ERR(priv->clk))
 247                 return PTR_ERR(priv->clk);
 248 
 249         ret = clk_prepare_enable(priv->clk);
 250         if (ret)
 251                 return ret;
 252 
 253         if (of_property_read_u32(np, "clock-frequency", &priv->clk_freq))
 254                 priv->clk_freq = 0;
 255 
 256         unimac_mdio_clk_set(priv);
 257 
 258         priv->mii_bus = mdiobus_alloc();
 259         if (!priv->mii_bus) {
 260                 ret = -ENOMEM;
 261                 goto out_clk_disable;
 262         }
 263 
 264         bus = priv->mii_bus;
 265         bus->priv = priv;
 266         if (pdata) {
 267                 bus->name = pdata->bus_name;
 268                 priv->wait_func = pdata->wait_func;
 269                 priv->wait_func_data = pdata->wait_func_data;
 270                 bus->phy_mask = ~pdata->phy_mask;
 271         } else {
 272                 bus->name = "unimac MII bus";
 273                 priv->wait_func_data = priv;
 274                 priv->wait_func = unimac_mdio_poll;
 275         }
 276         bus->parent = &pdev->dev;
 277         bus->read = unimac_mdio_read;
 278         bus->write = unimac_mdio_write;
 279         bus->reset = unimac_mdio_reset;
 280         snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id);
 281 
 282         ret = of_mdiobus_register(bus, np);
 283         if (ret) {
 284                 dev_err(&pdev->dev, "MDIO bus registration failed\n");
 285                 goto out_mdio_free;
 286         }
 287 
 288         platform_set_drvdata(pdev, priv);
 289 
 290         dev_info(&pdev->dev, "Broadcom UniMAC MDIO bus\n");
 291 
 292         return 0;
 293 
 294 out_mdio_free:
 295         mdiobus_free(bus);
 296 out_clk_disable:
 297         clk_disable_unprepare(priv->clk);
 298         return ret;
 299 }
 300 
 301 static int unimac_mdio_remove(struct platform_device *pdev)
 302 {
 303         struct unimac_mdio_priv *priv = platform_get_drvdata(pdev);
 304 
 305         mdiobus_unregister(priv->mii_bus);
 306         mdiobus_free(priv->mii_bus);
 307         clk_disable_unprepare(priv->clk);
 308 
 309         return 0;
 310 }
 311 
 312 static int __maybe_unused unimac_mdio_suspend(struct device *d)
 313 {
 314         struct unimac_mdio_priv *priv = dev_get_drvdata(d);
 315 
 316         clk_disable_unprepare(priv->clk);
 317 
 318         return 0;
 319 }
 320 
 321 static int __maybe_unused unimac_mdio_resume(struct device *d)
 322 {
 323         struct unimac_mdio_priv *priv = dev_get_drvdata(d);
 324         int ret;
 325 
 326         ret = clk_prepare_enable(priv->clk);
 327         if (ret)
 328                 return ret;
 329 
 330         unimac_mdio_clk_set(priv);
 331 
 332         return 0;
 333 }
 334 
 335 static SIMPLE_DEV_PM_OPS(unimac_mdio_pm_ops,
 336                          unimac_mdio_suspend, unimac_mdio_resume);
 337 
 338 static const struct of_device_id unimac_mdio_ids[] = {
 339         { .compatible = "brcm,genet-mdio-v5", },
 340         { .compatible = "brcm,genet-mdio-v4", },
 341         { .compatible = "brcm,genet-mdio-v3", },
 342         { .compatible = "brcm,genet-mdio-v2", },
 343         { .compatible = "brcm,genet-mdio-v1", },
 344         { .compatible = "brcm,unimac-mdio", },
 345         { /* sentinel */ },
 346 };
 347 MODULE_DEVICE_TABLE(of, unimac_mdio_ids);
 348 
 349 static struct platform_driver unimac_mdio_driver = {
 350         .driver = {
 351                 .name = UNIMAC_MDIO_DRV_NAME,
 352                 .of_match_table = unimac_mdio_ids,
 353                 .pm = &unimac_mdio_pm_ops,
 354         },
 355         .probe  = unimac_mdio_probe,
 356         .remove = unimac_mdio_remove,
 357 };
 358 module_platform_driver(unimac_mdio_driver);
 359 
 360 MODULE_AUTHOR("Broadcom Corporation");
 361 MODULE_DESCRIPTION("Broadcom UniMAC MDIO bus controller");
 362 MODULE_LICENSE("GPL");
 363 MODULE_ALIAS("platform:" UNIMAC_MDIO_DRV_NAME);

/* [<][>][^][v][top][bottom][index][help] */