linux/drivers/net/ethernet/marvell/mvmdio.c
<<
>>
Prefs
   1/*
   2 * Driver for the MDIO interface of Marvell network interfaces.
   3 *
   4 * Since the MDIO interface of Marvell network interfaces is shared
   5 * between all network interfaces, having a single driver allows to
   6 * handle concurrent accesses properly (you may have four Ethernet
   7 * ports, but they in fact share the same SMI interface to access
   8 * the MDIO bus). This driver is currently used by the mvneta and
   9 * mv643xx_eth drivers.
  10 *
  11 * Copyright (C) 2012 Marvell
  12 *
  13 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
  14 *
  15 * This file is licensed under the terms of the GNU General Public
  16 * License version 2. This program is licensed "as is" without any
  17 * warranty of any kind, whether express or implied.
  18 */
  19
  20#include <linux/acpi.h>
  21#include <linux/acpi_mdio.h>
  22#include <linux/clk.h>
  23#include <linux/delay.h>
  24#include <linux/interrupt.h>
  25#include <linux/io.h>
  26#include <linux/kernel.h>
  27#include <linux/module.h>
  28#include <linux/of_device.h>
  29#include <linux/of_mdio.h>
  30#include <linux/phy.h>
  31#include <linux/platform_device.h>
  32#include <linux/sched.h>
  33#include <linux/wait.h>
  34
  35#define MVMDIO_SMI_DATA_SHIFT           0
  36#define MVMDIO_SMI_PHY_ADDR_SHIFT       16
  37#define MVMDIO_SMI_PHY_REG_SHIFT        21
  38#define MVMDIO_SMI_READ_OPERATION       BIT(26)
  39#define MVMDIO_SMI_WRITE_OPERATION      0
  40#define MVMDIO_SMI_READ_VALID           BIT(27)
  41#define MVMDIO_SMI_BUSY                 BIT(28)
  42#define MVMDIO_ERR_INT_CAUSE            0x007C
  43#define  MVMDIO_ERR_INT_SMI_DONE        0x00000010
  44#define MVMDIO_ERR_INT_MASK             0x0080
  45
  46#define MVMDIO_XSMI_MGNT_REG            0x0
  47#define  MVMDIO_XSMI_PHYADDR_SHIFT      16
  48#define  MVMDIO_XSMI_DEVADDR_SHIFT      21
  49#define  MVMDIO_XSMI_WRITE_OPERATION    (0x5 << 26)
  50#define  MVMDIO_XSMI_READ_OPERATION     (0x7 << 26)
  51#define  MVMDIO_XSMI_READ_VALID         BIT(29)
  52#define  MVMDIO_XSMI_BUSY               BIT(30)
  53#define MVMDIO_XSMI_ADDR_REG            0x8
  54
  55/*
  56 * SMI Timeout measurements:
  57 * - Kirkwood 88F6281 (Globalscale Dreamplug): 45us to 95us (Interrupt)
  58 * - Armada 370       (Globalscale Mirabox):   41us to 43us (Polled)
  59 */
  60#define MVMDIO_SMI_TIMEOUT              1000 /* 1000us = 1ms */
  61#define MVMDIO_SMI_POLL_INTERVAL_MIN    45
  62#define MVMDIO_SMI_POLL_INTERVAL_MAX    55
  63
  64#define MVMDIO_XSMI_POLL_INTERVAL_MIN   150
  65#define MVMDIO_XSMI_POLL_INTERVAL_MAX   160
  66
  67struct orion_mdio_dev {
  68        void __iomem *regs;
  69        struct clk *clk[4];
  70        /*
  71         * If we have access to the error interrupt pin (which is
  72         * somewhat misnamed as it not only reflects internal errors
  73         * but also reflects SMI completion), use that to wait for
  74         * SMI access completion instead of polling the SMI busy bit.
  75         */
  76        int err_interrupt;
  77        wait_queue_head_t smi_busy_wait;
  78};
  79
  80enum orion_mdio_bus_type {
  81        BUS_TYPE_SMI,
  82        BUS_TYPE_XSMI
  83};
  84
  85struct orion_mdio_ops {
  86        int (*is_done)(struct orion_mdio_dev *);
  87        unsigned int poll_interval_min;
  88        unsigned int poll_interval_max;
  89};
  90
  91/* Wait for the SMI unit to be ready for another operation
  92 */
  93static int orion_mdio_wait_ready(const struct orion_mdio_ops *ops,
  94                                 struct mii_bus *bus)
  95{
  96        struct orion_mdio_dev *dev = bus->priv;
  97        unsigned long timeout = usecs_to_jiffies(MVMDIO_SMI_TIMEOUT);
  98        unsigned long end = jiffies + timeout;
  99        int timedout = 0;
 100
 101        while (1) {
 102                if (ops->is_done(dev))
 103                        return 0;
 104                else if (timedout)
 105                        break;
 106
 107                if (dev->err_interrupt <= 0) {
 108                        usleep_range(ops->poll_interval_min,
 109                                     ops->poll_interval_max);
 110
 111                        if (time_is_before_jiffies(end))
 112                                ++timedout;
 113                } else {
 114                        /* wait_event_timeout does not guarantee a delay of at
 115                         * least one whole jiffie, so timeout must be no less
 116                         * than two.
 117                         */
 118                        if (timeout < 2)
 119                                timeout = 2;
 120                        wait_event_timeout(dev->smi_busy_wait,
 121                                           ops->is_done(dev), timeout);
 122
 123                        ++timedout;
 124                }
 125        }
 126
 127        dev_err(bus->parent, "Timeout: SMI busy for too long\n");
 128        return  -ETIMEDOUT;
 129}
 130
 131static int orion_mdio_smi_is_done(struct orion_mdio_dev *dev)
 132{
 133        return !(readl(dev->regs) & MVMDIO_SMI_BUSY);
 134}
 135
 136static const struct orion_mdio_ops orion_mdio_smi_ops = {
 137        .is_done = orion_mdio_smi_is_done,
 138        .poll_interval_min = MVMDIO_SMI_POLL_INTERVAL_MIN,
 139        .poll_interval_max = MVMDIO_SMI_POLL_INTERVAL_MAX,
 140};
 141
 142static int orion_mdio_smi_read(struct mii_bus *bus, int mii_id,
 143                               int regnum)
 144{
 145        struct orion_mdio_dev *dev = bus->priv;
 146        u32 val;
 147        int ret;
 148
 149        if (regnum & MII_ADDR_C45)
 150                return -EOPNOTSUPP;
 151
 152        ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
 153        if (ret < 0)
 154                return ret;
 155
 156        writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) |
 157                (regnum << MVMDIO_SMI_PHY_REG_SHIFT)  |
 158                MVMDIO_SMI_READ_OPERATION),
 159               dev->regs);
 160
 161        ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
 162        if (ret < 0)
 163                return ret;
 164
 165        val = readl(dev->regs);
 166        if (!(val & MVMDIO_SMI_READ_VALID)) {
 167                dev_err(bus->parent, "SMI bus read not valid\n");
 168                return -ENODEV;
 169        }
 170
 171        return val & GENMASK(15, 0);
 172}
 173
 174static int orion_mdio_smi_write(struct mii_bus *bus, int mii_id,
 175                                int regnum, u16 value)
 176{
 177        struct orion_mdio_dev *dev = bus->priv;
 178        int ret;
 179
 180        if (regnum & MII_ADDR_C45)
 181                return -EOPNOTSUPP;
 182
 183        ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
 184        if (ret < 0)
 185                return ret;
 186
 187        writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) |
 188                (regnum << MVMDIO_SMI_PHY_REG_SHIFT)  |
 189                MVMDIO_SMI_WRITE_OPERATION            |
 190                (value << MVMDIO_SMI_DATA_SHIFT)),
 191               dev->regs);
 192
 193        return 0;
 194}
 195
 196static int orion_mdio_xsmi_is_done(struct orion_mdio_dev *dev)
 197{
 198        return !(readl(dev->regs + MVMDIO_XSMI_MGNT_REG) & MVMDIO_XSMI_BUSY);
 199}
 200
 201static const struct orion_mdio_ops orion_mdio_xsmi_ops = {
 202        .is_done = orion_mdio_xsmi_is_done,
 203        .poll_interval_min = MVMDIO_XSMI_POLL_INTERVAL_MIN,
 204        .poll_interval_max = MVMDIO_XSMI_POLL_INTERVAL_MAX,
 205};
 206
 207static int orion_mdio_xsmi_read(struct mii_bus *bus, int mii_id,
 208                                int regnum)
 209{
 210        struct orion_mdio_dev *dev = bus->priv;
 211        u16 dev_addr = (regnum >> 16) & GENMASK(4, 0);
 212        int ret;
 213
 214        if (!(regnum & MII_ADDR_C45))
 215                return -EOPNOTSUPP;
 216
 217        ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus);
 218        if (ret < 0)
 219                return ret;
 220
 221        writel(regnum & GENMASK(15, 0), dev->regs + MVMDIO_XSMI_ADDR_REG);
 222        writel((mii_id << MVMDIO_XSMI_PHYADDR_SHIFT) |
 223               (dev_addr << MVMDIO_XSMI_DEVADDR_SHIFT) |
 224               MVMDIO_XSMI_READ_OPERATION,
 225               dev->regs + MVMDIO_XSMI_MGNT_REG);
 226
 227        ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus);
 228        if (ret < 0)
 229                return ret;
 230
 231        if (!(readl(dev->regs + MVMDIO_XSMI_MGNT_REG) &
 232              MVMDIO_XSMI_READ_VALID)) {
 233                dev_err(bus->parent, "XSMI bus read not valid\n");
 234                return -ENODEV;
 235        }
 236
 237        return readl(dev->regs + MVMDIO_XSMI_MGNT_REG) & GENMASK(15, 0);
 238}
 239
 240static int orion_mdio_xsmi_write(struct mii_bus *bus, int mii_id,
 241                                int regnum, u16 value)
 242{
 243        struct orion_mdio_dev *dev = bus->priv;
 244        u16 dev_addr = (regnum >> 16) & GENMASK(4, 0);
 245        int ret;
 246
 247        if (!(regnum & MII_ADDR_C45))
 248                return -EOPNOTSUPP;
 249
 250        ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus);
 251        if (ret < 0)
 252                return ret;
 253
 254        writel(regnum & GENMASK(15, 0), dev->regs + MVMDIO_XSMI_ADDR_REG);
 255        writel((mii_id << MVMDIO_XSMI_PHYADDR_SHIFT) |
 256               (dev_addr << MVMDIO_XSMI_DEVADDR_SHIFT) |
 257               MVMDIO_XSMI_WRITE_OPERATION | value,
 258               dev->regs + MVMDIO_XSMI_MGNT_REG);
 259
 260        return 0;
 261}
 262
 263static irqreturn_t orion_mdio_err_irq(int irq, void *dev_id)
 264{
 265        struct orion_mdio_dev *dev = dev_id;
 266
 267        if (readl(dev->regs + MVMDIO_ERR_INT_CAUSE) &
 268                        MVMDIO_ERR_INT_SMI_DONE) {
 269                writel(~MVMDIO_ERR_INT_SMI_DONE,
 270                                dev->regs + MVMDIO_ERR_INT_CAUSE);
 271                wake_up(&dev->smi_busy_wait);
 272                return IRQ_HANDLED;
 273        }
 274
 275        return IRQ_NONE;
 276}
 277
 278static int orion_mdio_probe(struct platform_device *pdev)
 279{
 280        enum orion_mdio_bus_type type;
 281        struct resource *r;
 282        struct mii_bus *bus;
 283        struct orion_mdio_dev *dev;
 284        int i, ret;
 285
 286        type = (enum orion_mdio_bus_type)device_get_match_data(&pdev->dev);
 287
 288        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 289        if (!r) {
 290                dev_err(&pdev->dev, "No SMI register address given\n");
 291                return -ENODEV;
 292        }
 293
 294        bus = devm_mdiobus_alloc_size(&pdev->dev,
 295                                      sizeof(struct orion_mdio_dev));
 296        if (!bus)
 297                return -ENOMEM;
 298
 299        switch (type) {
 300        case BUS_TYPE_SMI:
 301                bus->read = orion_mdio_smi_read;
 302                bus->write = orion_mdio_smi_write;
 303                break;
 304        case BUS_TYPE_XSMI:
 305                bus->read = orion_mdio_xsmi_read;
 306                bus->write = orion_mdio_xsmi_write;
 307                break;
 308        }
 309
 310        bus->name = "orion_mdio_bus";
 311        snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii",
 312                 dev_name(&pdev->dev));
 313        bus->parent = &pdev->dev;
 314
 315        dev = bus->priv;
 316        dev->regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
 317        if (!dev->regs) {
 318                dev_err(&pdev->dev, "Unable to remap SMI register\n");
 319                return -ENODEV;
 320        }
 321
 322        init_waitqueue_head(&dev->smi_busy_wait);
 323
 324        if (pdev->dev.of_node) {
 325                for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
 326                        dev->clk[i] = of_clk_get(pdev->dev.of_node, i);
 327                        if (PTR_ERR(dev->clk[i]) == -EPROBE_DEFER) {
 328                                ret = -EPROBE_DEFER;
 329                                goto out_clk;
 330                        }
 331                        if (IS_ERR(dev->clk[i]))
 332                                break;
 333                        clk_prepare_enable(dev->clk[i]);
 334                }
 335
 336                if (!IS_ERR(of_clk_get(pdev->dev.of_node,
 337                                       ARRAY_SIZE(dev->clk))))
 338                        dev_warn(&pdev->dev,
 339                                 "unsupported number of clocks, limiting to the first "
 340                                 __stringify(ARRAY_SIZE(dev->clk)) "\n");
 341        } else {
 342                dev->clk[0] = clk_get(&pdev->dev, NULL);
 343                if (PTR_ERR(dev->clk[0]) == -EPROBE_DEFER) {
 344                        ret = -EPROBE_DEFER;
 345                        goto out_clk;
 346                }
 347                if (!IS_ERR(dev->clk[0]))
 348                        clk_prepare_enable(dev->clk[0]);
 349        }
 350
 351
 352        dev->err_interrupt = platform_get_irq_optional(pdev, 0);
 353        if (dev->err_interrupt > 0 &&
 354            resource_size(r) < MVMDIO_ERR_INT_MASK + 4) {
 355                dev_err(&pdev->dev,
 356                        "disabling interrupt, resource size is too small\n");
 357                dev->err_interrupt = 0;
 358        }
 359        if (dev->err_interrupt > 0) {
 360                ret = devm_request_irq(&pdev->dev, dev->err_interrupt,
 361                                        orion_mdio_err_irq,
 362                                        IRQF_SHARED, pdev->name, dev);
 363                if (ret)
 364                        goto out_mdio;
 365
 366                writel(MVMDIO_ERR_INT_SMI_DONE,
 367                        dev->regs + MVMDIO_ERR_INT_MASK);
 368
 369        } else if (dev->err_interrupt == -EPROBE_DEFER) {
 370                ret = -EPROBE_DEFER;
 371                goto out_mdio;
 372        }
 373
 374        /* For the platforms not supporting DT/ACPI fall-back
 375         * to mdiobus_register via of_mdiobus_register.
 376         */
 377        if (is_acpi_node(pdev->dev.fwnode))
 378                ret = acpi_mdiobus_register(bus, pdev->dev.fwnode);
 379        else
 380                ret = of_mdiobus_register(bus, pdev->dev.of_node);
 381        if (ret < 0) {
 382                dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret);
 383                goto out_mdio;
 384        }
 385
 386        platform_set_drvdata(pdev, bus);
 387
 388        return 0;
 389
 390out_mdio:
 391        if (dev->err_interrupt > 0)
 392                writel(0, dev->regs + MVMDIO_ERR_INT_MASK);
 393
 394out_clk:
 395        for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
 396                if (IS_ERR(dev->clk[i]))
 397                        break;
 398                clk_disable_unprepare(dev->clk[i]);
 399                clk_put(dev->clk[i]);
 400        }
 401
 402        return ret;
 403}
 404
 405static int orion_mdio_remove(struct platform_device *pdev)
 406{
 407        struct mii_bus *bus = platform_get_drvdata(pdev);
 408        struct orion_mdio_dev *dev = bus->priv;
 409        int i;
 410
 411        if (dev->err_interrupt > 0)
 412                writel(0, dev->regs + MVMDIO_ERR_INT_MASK);
 413        mdiobus_unregister(bus);
 414
 415        for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
 416                if (IS_ERR(dev->clk[i]))
 417                        break;
 418                clk_disable_unprepare(dev->clk[i]);
 419                clk_put(dev->clk[i]);
 420        }
 421
 422        return 0;
 423}
 424
 425static const struct of_device_id orion_mdio_match[] = {
 426        { .compatible = "marvell,orion-mdio", .data = (void *)BUS_TYPE_SMI },
 427        { .compatible = "marvell,xmdio", .data = (void *)BUS_TYPE_XSMI },
 428        { }
 429};
 430MODULE_DEVICE_TABLE(of, orion_mdio_match);
 431
 432static const struct acpi_device_id orion_mdio_acpi_match[] = {
 433        { "MRVL0100", BUS_TYPE_SMI },
 434        { "MRVL0101", BUS_TYPE_XSMI },
 435        { },
 436};
 437MODULE_DEVICE_TABLE(acpi, orion_mdio_acpi_match);
 438
 439static struct platform_driver orion_mdio_driver = {
 440        .probe = orion_mdio_probe,
 441        .remove = orion_mdio_remove,
 442        .driver = {
 443                .name = "orion-mdio",
 444                .of_match_table = orion_mdio_match,
 445                .acpi_match_table = ACPI_PTR(orion_mdio_acpi_match),
 446        },
 447};
 448
 449module_platform_driver(orion_mdio_driver);
 450
 451MODULE_DESCRIPTION("Marvell MDIO interface driver");
 452MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
 453MODULE_LICENSE("GPL");
 454MODULE_ALIAS("platform:orion-mdio");
 455