root/drivers/net/ethernet/freescale/fsl_pq_mdio.c

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

DEFINITIONS

This source file includes following definitions.
  1. fsl_pq_mdio_write
  2. fsl_pq_mdio_read
  3. fsl_pq_mdio_reset
  4. get_gfar_tbipa_from_mdio
  5. get_gfar_tbipa_from_mii
  6. get_etsec_tbipa
  7. get_ucc_tbipa
  8. ucc_configure
  9. set_tbipa
  10. fsl_pq_mdio_probe
  11. fsl_pq_mdio_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Freescale PowerQUICC Ethernet Driver -- MIIM bus implementation
   4  * Provides Bus interface for MIIM regs
   5  *
   6  * Author: Andy Fleming <afleming@freescale.com>
   7  * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com>
   8  *
   9  * Copyright 2002-2004, 2008-2009 Freescale Semiconductor, Inc.
  10  *
  11  * Based on gianfar_mii.c and ucc_geth_mii.c (Li Yang, Kim Phillips)
  12  */
  13 
  14 #include <linux/kernel.h>
  15 #include <linux/string.h>
  16 #include <linux/errno.h>
  17 #include <linux/slab.h>
  18 #include <linux/delay.h>
  19 #include <linux/module.h>
  20 #include <linux/mii.h>
  21 #include <linux/of_address.h>
  22 #include <linux/of_mdio.h>
  23 #include <linux/of_device.h>
  24 
  25 #include <asm/io.h>
  26 #if IS_ENABLED(CONFIG_UCC_GETH)
  27 #include <soc/fsl/qe/ucc.h>
  28 #endif
  29 
  30 #include "gianfar.h"
  31 
  32 #define MIIMIND_BUSY            0x00000001
  33 #define MIIMIND_NOTVALID        0x00000004
  34 #define MIIMCFG_INIT_VALUE      0x00000007
  35 #define MIIMCFG_RESET           0x80000000
  36 
  37 #define MII_READ_COMMAND        0x00000001
  38 
  39 struct fsl_pq_mii {
  40         u32 miimcfg;    /* MII management configuration reg */
  41         u32 miimcom;    /* MII management command reg */
  42         u32 miimadd;    /* MII management address reg */
  43         u32 miimcon;    /* MII management control reg */
  44         u32 miimstat;   /* MII management status reg */
  45         u32 miimind;    /* MII management indication reg */
  46 };
  47 
  48 struct fsl_pq_mdio {
  49         u8 res1[16];
  50         u32 ieventm;    /* MDIO Interrupt event register (for etsec2)*/
  51         u32 imaskm;     /* MDIO Interrupt mask register (for etsec2)*/
  52         u8 res2[4];
  53         u32 emapm;      /* MDIO Event mapping register (for etsec2)*/
  54         u8 res3[1280];
  55         struct fsl_pq_mii mii;
  56         u8 res4[28];
  57         u32 utbipar;    /* TBI phy address reg (only on UCC) */
  58         u8 res5[2728];
  59 } __packed;
  60 
  61 /* Number of microseconds to wait for an MII register to respond */
  62 #define MII_TIMEOUT     1000
  63 
  64 struct fsl_pq_mdio_priv {
  65         void __iomem *map;
  66         struct fsl_pq_mii __iomem *regs;
  67 };
  68 
  69 /*
  70  * Per-device-type data.  Each type of device tree node that we support gets
  71  * one of these.
  72  *
  73  * @mii_offset: the offset of the MII registers within the memory map of the
  74  * node.  Some nodes define only the MII registers, and some define the whole
  75  * MAC (which includes the MII registers).
  76  *
  77  * @get_tbipa: determines the address of the TBIPA register
  78  *
  79  * @ucc_configure: a special function for extra QE configuration
  80  */
  81 struct fsl_pq_mdio_data {
  82         unsigned int mii_offset;        /* offset of the MII registers */
  83         uint32_t __iomem * (*get_tbipa)(void __iomem *p);
  84         void (*ucc_configure)(phys_addr_t start, phys_addr_t end);
  85 };
  86 
  87 /*
  88  * Write value to the PHY at mii_id at register regnum, on the bus attached
  89  * to the local interface, which may be different from the generic mdio bus
  90  * (tied to a single interface), waiting until the write is done before
  91  * returning. This is helpful in programming interfaces like the TBI which
  92  * control interfaces like onchip SERDES and are always tied to the local
  93  * mdio pins, which may not be the same as system mdio bus, used for
  94  * controlling the external PHYs, for example.
  95  */
  96 static int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
  97                 u16 value)
  98 {
  99         struct fsl_pq_mdio_priv *priv = bus->priv;
 100         struct fsl_pq_mii __iomem *regs = priv->regs;
 101         unsigned int timeout;
 102 
 103         /* Set the PHY address and the register address we want to write */
 104         iowrite32be((mii_id << 8) | regnum, &regs->miimadd);
 105 
 106         /* Write out the value we want */
 107         iowrite32be(value, &regs->miimcon);
 108 
 109         /* Wait for the transaction to finish */
 110         timeout = MII_TIMEOUT;
 111         while ((ioread32be(&regs->miimind) & MIIMIND_BUSY) && timeout) {
 112                 cpu_relax();
 113                 timeout--;
 114         }
 115 
 116         return timeout ? 0 : -ETIMEDOUT;
 117 }
 118 
 119 /*
 120  * Read the bus for PHY at addr mii_id, register regnum, and return the value.
 121  * Clears miimcom first.
 122  *
 123  * All PHY operation done on the bus attached to the local interface, which
 124  * may be different from the generic mdio bus.  This is helpful in programming
 125  * interfaces like the TBI which, in turn, control interfaces like on-chip
 126  * SERDES and are always tied to the local mdio pins, which may not be the
 127  * same as system mdio bus, used for controlling the external PHYs, for eg.
 128  */
 129 static int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 130 {
 131         struct fsl_pq_mdio_priv *priv = bus->priv;
 132         struct fsl_pq_mii __iomem *regs = priv->regs;
 133         unsigned int timeout;
 134         u16 value;
 135 
 136         /* Set the PHY address and the register address we want to read */
 137         iowrite32be((mii_id << 8) | regnum, &regs->miimadd);
 138 
 139         /* Clear miimcom, and then initiate a read */
 140         iowrite32be(0, &regs->miimcom);
 141         iowrite32be(MII_READ_COMMAND, &regs->miimcom);
 142 
 143         /* Wait for the transaction to finish, normally less than 100us */
 144         timeout = MII_TIMEOUT;
 145         while ((ioread32be(&regs->miimind) &
 146                (MIIMIND_NOTVALID | MIIMIND_BUSY)) && timeout) {
 147                 cpu_relax();
 148                 timeout--;
 149         }
 150 
 151         if (!timeout)
 152                 return -ETIMEDOUT;
 153 
 154         /* Grab the value of the register from miimstat */
 155         value = ioread32be(&regs->miimstat);
 156 
 157         dev_dbg(&bus->dev, "read %04x from address %x/%x\n", value, mii_id, regnum);
 158         return value;
 159 }
 160 
 161 /* Reset the MIIM registers, and wait for the bus to free */
 162 static int fsl_pq_mdio_reset(struct mii_bus *bus)
 163 {
 164         struct fsl_pq_mdio_priv *priv = bus->priv;
 165         struct fsl_pq_mii __iomem *regs = priv->regs;
 166         unsigned int timeout;
 167 
 168         mutex_lock(&bus->mdio_lock);
 169 
 170         /* Reset the management interface */
 171         iowrite32be(MIIMCFG_RESET, &regs->miimcfg);
 172 
 173         /* Setup the MII Mgmt clock speed */
 174         iowrite32be(MIIMCFG_INIT_VALUE, &regs->miimcfg);
 175 
 176         /* Wait until the bus is free */
 177         timeout = MII_TIMEOUT;
 178         while ((ioread32be(&regs->miimind) & MIIMIND_BUSY) && timeout) {
 179                 cpu_relax();
 180                 timeout--;
 181         }
 182 
 183         mutex_unlock(&bus->mdio_lock);
 184 
 185         if (!timeout) {
 186                 dev_err(&bus->dev, "timeout waiting for MII bus\n");
 187                 return -EBUSY;
 188         }
 189 
 190         return 0;
 191 }
 192 
 193 #if IS_ENABLED(CONFIG_GIANFAR)
 194 /*
 195  * Return the TBIPA address, starting from the address
 196  * of the mapped GFAR MDIO registers (struct gfar)
 197  * This is mildly evil, but so is our hardware for doing this.
 198  * Also, we have to cast back to struct gfar because of
 199  * definition weirdness done in gianfar.h.
 200  */
 201 static uint32_t __iomem *get_gfar_tbipa_from_mdio(void __iomem *p)
 202 {
 203         struct gfar __iomem *enet_regs = p;
 204 
 205         return &enet_regs->tbipa;
 206 }
 207 
 208 /*
 209  * Return the TBIPA address, starting from the address
 210  * of the mapped GFAR MII registers (gfar_mii_regs[] within struct gfar)
 211  */
 212 static uint32_t __iomem *get_gfar_tbipa_from_mii(void __iomem *p)
 213 {
 214         return get_gfar_tbipa_from_mdio(container_of(p, struct gfar, gfar_mii_regs));
 215 }
 216 
 217 /*
 218  * Return the TBIPAR address for an eTSEC2 node
 219  */
 220 static uint32_t __iomem *get_etsec_tbipa(void __iomem *p)
 221 {
 222         return p;
 223 }
 224 #endif
 225 
 226 #if IS_ENABLED(CONFIG_UCC_GETH)
 227 /*
 228  * Return the TBIPAR address for a QE MDIO node, starting from the address
 229  * of the mapped MII registers (struct fsl_pq_mii)
 230  */
 231 static uint32_t __iomem *get_ucc_tbipa(void __iomem *p)
 232 {
 233         struct fsl_pq_mdio __iomem *mdio = container_of(p, struct fsl_pq_mdio, mii);
 234 
 235         return &mdio->utbipar;
 236 }
 237 
 238 /*
 239  * Find the UCC node that controls the given MDIO node
 240  *
 241  * For some reason, the QE MDIO nodes are not children of the UCC devices
 242  * that control them.  Therefore, we need to scan all UCC nodes looking for
 243  * the one that encompases the given MDIO node.  We do this by comparing
 244  * physical addresses.  The 'start' and 'end' addresses of the MDIO node are
 245  * passed, and the correct UCC node will cover the entire address range.
 246  *
 247  * This assumes that there is only one QE MDIO node in the entire device tree.
 248  */
 249 static void ucc_configure(phys_addr_t start, phys_addr_t end)
 250 {
 251         static bool found_mii_master;
 252         struct device_node *np = NULL;
 253 
 254         if (found_mii_master)
 255                 return;
 256 
 257         for_each_compatible_node(np, NULL, "ucc_geth") {
 258                 struct resource res;
 259                 const uint32_t *iprop;
 260                 uint32_t id;
 261                 int ret;
 262 
 263                 ret = of_address_to_resource(np, 0, &res);
 264                 if (ret < 0) {
 265                         pr_debug("fsl-pq-mdio: no address range in node %pOF\n",
 266                                  np);
 267                         continue;
 268                 }
 269 
 270                 /* if our mdio regs fall within this UCC regs range */
 271                 if ((start < res.start) || (end > res.end))
 272                         continue;
 273 
 274                 iprop = of_get_property(np, "cell-index", NULL);
 275                 if (!iprop) {
 276                         iprop = of_get_property(np, "device-id", NULL);
 277                         if (!iprop) {
 278                                 pr_debug("fsl-pq-mdio: no UCC ID in node %pOF\n",
 279                                          np);
 280                                 continue;
 281                         }
 282                 }
 283 
 284                 id = be32_to_cpup(iprop);
 285 
 286                 /*
 287                  * cell-index and device-id for QE nodes are
 288                  * numbered from 1, not 0.
 289                  */
 290                 if (ucc_set_qe_mux_mii_mng(id - 1) < 0) {
 291                         pr_debug("fsl-pq-mdio: invalid UCC ID in node %pOF\n",
 292                                  np);
 293                         continue;
 294                 }
 295 
 296                 pr_debug("fsl-pq-mdio: setting node UCC%u to MII master\n", id);
 297                 found_mii_master = true;
 298         }
 299 }
 300 
 301 #endif
 302 
 303 static const struct of_device_id fsl_pq_mdio_match[] = {
 304 #if IS_ENABLED(CONFIG_GIANFAR)
 305         {
 306                 .compatible = "fsl,gianfar-tbi",
 307                 .data = &(struct fsl_pq_mdio_data) {
 308                         .mii_offset = 0,
 309                         .get_tbipa = get_gfar_tbipa_from_mii,
 310                 },
 311         },
 312         {
 313                 .compatible = "fsl,gianfar-mdio",
 314                 .data = &(struct fsl_pq_mdio_data) {
 315                         .mii_offset = 0,
 316                         .get_tbipa = get_gfar_tbipa_from_mii,
 317                 },
 318         },
 319         {
 320                 .type = "mdio",
 321                 .compatible = "gianfar",
 322                 .data = &(struct fsl_pq_mdio_data) {
 323                         .mii_offset = offsetof(struct fsl_pq_mdio, mii),
 324                         .get_tbipa = get_gfar_tbipa_from_mdio,
 325                 },
 326         },
 327         {
 328                 .compatible = "fsl,etsec2-tbi",
 329                 .data = &(struct fsl_pq_mdio_data) {
 330                         .mii_offset = offsetof(struct fsl_pq_mdio, mii),
 331                         .get_tbipa = get_etsec_tbipa,
 332                 },
 333         },
 334         {
 335                 .compatible = "fsl,etsec2-mdio",
 336                 .data = &(struct fsl_pq_mdio_data) {
 337                         .mii_offset = offsetof(struct fsl_pq_mdio, mii),
 338                         .get_tbipa = get_etsec_tbipa,
 339                 },
 340         },
 341 #endif
 342 #if IS_ENABLED(CONFIG_UCC_GETH)
 343         {
 344                 .compatible = "fsl,ucc-mdio",
 345                 .data = &(struct fsl_pq_mdio_data) {
 346                         .mii_offset = 0,
 347                         .get_tbipa = get_ucc_tbipa,
 348                         .ucc_configure = ucc_configure,
 349                 },
 350         },
 351         {
 352                 /* Legacy UCC MDIO node */
 353                 .type = "mdio",
 354                 .compatible = "ucc_geth_phy",
 355                 .data = &(struct fsl_pq_mdio_data) {
 356                         .mii_offset = 0,
 357                         .get_tbipa = get_ucc_tbipa,
 358                         .ucc_configure = ucc_configure,
 359                 },
 360         },
 361 #endif
 362         /* No Kconfig option for Fman support yet */
 363         {
 364                 .compatible = "fsl,fman-mdio",
 365                 .data = &(struct fsl_pq_mdio_data) {
 366                         .mii_offset = 0,
 367                         /* Fman TBI operations are handled elsewhere */
 368                 },
 369         },
 370 
 371         {},
 372 };
 373 MODULE_DEVICE_TABLE(of, fsl_pq_mdio_match);
 374 
 375 static void set_tbipa(const u32 tbipa_val, struct platform_device *pdev,
 376                       uint32_t __iomem * (*get_tbipa)(void __iomem *),
 377                       void __iomem *reg_map, struct resource *reg_res)
 378 {
 379         struct device_node *np = pdev->dev.of_node;
 380         uint32_t __iomem *tbipa;
 381         bool tbipa_mapped;
 382 
 383         tbipa = of_iomap(np, 1);
 384         if (tbipa) {
 385                 tbipa_mapped = true;
 386         } else {
 387                 tbipa_mapped = false;
 388                 tbipa = (*get_tbipa)(reg_map);
 389 
 390                 /*
 391                  * Add consistency check to make sure TBI is contained within
 392                  * the mapped range (not because we would get a segfault,
 393                  * rather to catch bugs in computing TBI address). Print error
 394                  * message but continue anyway.
 395                  */
 396                 if ((void *)tbipa > reg_map + resource_size(reg_res) - 4)
 397                         dev_err(&pdev->dev, "invalid register map (should be at least 0x%04zx to contain TBI address)\n",
 398                                 ((void *)tbipa - reg_map) + 4);
 399         }
 400 
 401         iowrite32be(be32_to_cpu(tbipa_val), tbipa);
 402 
 403         if (tbipa_mapped)
 404                 iounmap(tbipa);
 405 }
 406 
 407 static int fsl_pq_mdio_probe(struct platform_device *pdev)
 408 {
 409         const struct of_device_id *id =
 410                 of_match_device(fsl_pq_mdio_match, &pdev->dev);
 411         const struct fsl_pq_mdio_data *data;
 412         struct device_node *np = pdev->dev.of_node;
 413         struct resource res;
 414         struct device_node *tbi;
 415         struct fsl_pq_mdio_priv *priv;
 416         struct mii_bus *new_bus;
 417         int err;
 418 
 419         if (!id) {
 420                 dev_err(&pdev->dev, "Failed to match device\n");
 421                 return -ENODEV;
 422         }
 423 
 424         data = id->data;
 425 
 426         dev_dbg(&pdev->dev, "found %s compatible node\n", id->compatible);
 427 
 428         new_bus = mdiobus_alloc_size(sizeof(*priv));
 429         if (!new_bus)
 430                 return -ENOMEM;
 431 
 432         priv = new_bus->priv;
 433         new_bus->name = "Freescale PowerQUICC MII Bus",
 434         new_bus->read = &fsl_pq_mdio_read;
 435         new_bus->write = &fsl_pq_mdio_write;
 436         new_bus->reset = &fsl_pq_mdio_reset;
 437 
 438         err = of_address_to_resource(np, 0, &res);
 439         if (err < 0) {
 440                 dev_err(&pdev->dev, "could not obtain address information\n");
 441                 goto error;
 442         }
 443 
 444         snprintf(new_bus->id, MII_BUS_ID_SIZE, "%pOFn@%llx", np,
 445                  (unsigned long long)res.start);
 446 
 447         priv->map = of_iomap(np, 0);
 448         if (!priv->map) {
 449                 err = -ENOMEM;
 450                 goto error;
 451         }
 452 
 453         /*
 454          * Some device tree nodes represent only the MII registers, and
 455          * others represent the MAC and MII registers.  The 'mii_offset' field
 456          * contains the offset of the MII registers inside the mapped register
 457          * space.
 458          */
 459         if (data->mii_offset > resource_size(&res)) {
 460                 dev_err(&pdev->dev, "invalid register map\n");
 461                 err = -EINVAL;
 462                 goto error;
 463         }
 464         priv->regs = priv->map + data->mii_offset;
 465 
 466         new_bus->parent = &pdev->dev;
 467         platform_set_drvdata(pdev, new_bus);
 468 
 469         if (data->get_tbipa) {
 470                 for_each_child_of_node(np, tbi) {
 471                         if (of_node_is_type(tbi, "tbi-phy")) {
 472                                 dev_dbg(&pdev->dev, "found TBI PHY node %pOFP\n",
 473                                         tbi);
 474                                 break;
 475                         }
 476                 }
 477 
 478                 if (tbi) {
 479                         const u32 *prop = of_get_property(tbi, "reg", NULL);
 480                         if (!prop) {
 481                                 dev_err(&pdev->dev,
 482                                         "missing 'reg' property in node %pOF\n",
 483                                         tbi);
 484                                 err = -EBUSY;
 485                                 goto error;
 486                         }
 487                         set_tbipa(*prop, pdev,
 488                                   data->get_tbipa, priv->map, &res);
 489                 }
 490         }
 491 
 492         if (data->ucc_configure)
 493                 data->ucc_configure(res.start, res.end);
 494 
 495         err = of_mdiobus_register(new_bus, np);
 496         if (err) {
 497                 dev_err(&pdev->dev, "cannot register %s as MDIO bus\n",
 498                         new_bus->name);
 499                 goto error;
 500         }
 501 
 502         return 0;
 503 
 504 error:
 505         if (priv->map)
 506                 iounmap(priv->map);
 507 
 508         kfree(new_bus);
 509 
 510         return err;
 511 }
 512 
 513 
 514 static int fsl_pq_mdio_remove(struct platform_device *pdev)
 515 {
 516         struct device *device = &pdev->dev;
 517         struct mii_bus *bus = dev_get_drvdata(device);
 518         struct fsl_pq_mdio_priv *priv = bus->priv;
 519 
 520         mdiobus_unregister(bus);
 521 
 522         iounmap(priv->map);
 523         mdiobus_free(bus);
 524 
 525         return 0;
 526 }
 527 
 528 static struct platform_driver fsl_pq_mdio_driver = {
 529         .driver = {
 530                 .name = "fsl-pq_mdio",
 531                 .of_match_table = fsl_pq_mdio_match,
 532         },
 533         .probe = fsl_pq_mdio_probe,
 534         .remove = fsl_pq_mdio_remove,
 535 };
 536 
 537 module_platform_driver(fsl_pq_mdio_driver);
 538 
 539 MODULE_LICENSE("GPL");

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