uboot/drivers/net/fsl_mdio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2009-2010, 2013 Freescale Semiconductor, Inc.
   4 *      Jun-jie Zhang <b18070@freescale.com>
   5 *      Mingkai Hu <Mingkai.hu@freescale.com>
   6 */
   7
   8#include <common.h>
   9#include <miiphy.h>
  10#include <phy.h>
  11#include <fsl_mdio.h>
  12#include <asm/io.h>
  13#include <linux/errno.h>
  14
  15#ifdef CONFIG_DM_MDIO
  16struct tsec_mdio_priv {
  17        struct tsec_mii_mng __iomem *regs;
  18};
  19#endif
  20
  21void tsec_local_mdio_write(struct tsec_mii_mng __iomem *phyregs, int port_addr,
  22                int dev_addr, int regnum, int value)
  23{
  24        int timeout = 1000000;
  25
  26        out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
  27        out_be32(&phyregs->miimcon, value);
  28        /* Memory barrier */
  29        mb();
  30
  31        while ((in_be32(&phyregs->miimind) & MIIMIND_BUSY) && timeout--)
  32                ;
  33}
  34
  35int tsec_local_mdio_read(struct tsec_mii_mng __iomem *phyregs, int port_addr,
  36                int dev_addr, int regnum)
  37{
  38        int value;
  39        int timeout = 1000000;
  40
  41        /* Put the address of the phy, and the register number into MIIMADD */
  42        out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
  43
  44        /* Clear the command register, and wait */
  45        out_be32(&phyregs->miimcom, 0);
  46        /* Memory barrier */
  47        mb();
  48
  49        /* Initiate a read command, and wait */
  50        out_be32(&phyregs->miimcom, MIIMCOM_READ_CYCLE);
  51        /* Memory barrier */
  52        mb();
  53
  54        /* Wait for the the indication that the read is done */
  55        while ((in_be32(&phyregs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY))
  56                        && timeout--)
  57                ;
  58
  59        /* Grab the value read from the PHY */
  60        value = in_be32(&phyregs->miimstat);
  61
  62        return value;
  63}
  64
  65#if defined(CONFIG_PHYLIB)
  66static int fsl_pq_mdio_reset(struct mii_dev *bus)
  67{
  68        struct tsec_mii_mng __iomem *regs;
  69#ifndef CONFIG_DM_MDIO
  70        regs = (struct tsec_mii_mng __iomem *)bus->priv;
  71#else
  72        struct tsec_mdio_priv *priv;
  73
  74        if (!bus->priv)
  75                return -EINVAL;
  76
  77        priv = dev_get_priv(bus->priv);
  78        regs = priv->regs;
  79#endif
  80
  81        /* Reset MII (due to new addresses) */
  82        out_be32(&regs->miimcfg, MIIMCFG_RESET_MGMT);
  83
  84        out_be32(&regs->miimcfg, MIIMCFG_INIT_VALUE);
  85
  86        while (in_be32(&regs->miimind) & MIIMIND_BUSY)
  87                ;
  88
  89        return 0;
  90}
  91#endif
  92
  93int tsec_phy_read(struct mii_dev *bus, int addr, int dev_addr, int regnum)
  94{
  95        struct tsec_mii_mng __iomem *phyregs;
  96#ifndef CONFIG_DM_MDIO
  97        phyregs = (struct tsec_mii_mng __iomem *)bus->priv;
  98#else
  99        struct tsec_mdio_priv *priv;
 100
 101        if (!bus->priv)
 102                return -EINVAL;
 103
 104        priv = dev_get_priv(bus->priv);
 105        phyregs = priv->regs;
 106#endif
 107
 108        return tsec_local_mdio_read(phyregs, addr, dev_addr, regnum);
 109}
 110
 111int tsec_phy_write(struct mii_dev *bus, int addr, int dev_addr, int regnum,
 112                        u16 value)
 113{
 114        struct tsec_mii_mng __iomem *phyregs;
 115#ifndef CONFIG_DM_MDIO
 116        phyregs = (struct tsec_mii_mng __iomem *)bus->priv;
 117#else
 118        struct tsec_mdio_priv *priv;
 119
 120        if (!bus->priv)
 121                return -EINVAL;
 122
 123        priv = dev_get_priv(bus->priv);
 124        phyregs = priv->regs;
 125#endif
 126
 127        tsec_local_mdio_write(phyregs, addr, dev_addr, regnum, value);
 128
 129        return 0;
 130}
 131
 132#ifndef CONFIG_DM_MDIO
 133int fsl_pq_mdio_init(bd_t *bis, struct fsl_pq_mdio_info *info)
 134{
 135        struct mii_dev *bus = mdio_alloc();
 136
 137        if (!bus) {
 138                printf("Failed to allocate FSL MDIO bus\n");
 139                return -1;
 140        }
 141
 142        bus->read = tsec_phy_read;
 143        bus->write = tsec_phy_write;
 144        bus->reset = fsl_pq_mdio_reset;
 145        strcpy(bus->name, info->name);
 146
 147        bus->priv = (void *)info->regs;
 148
 149        return mdio_register(bus);
 150}
 151#else /* CONFIG_DM_MDIO */
 152#if defined(CONFIG_PHYLIB)
 153static int tsec_mdio_read(struct udevice *dev, int addr, int devad, int reg)
 154{
 155        struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) :
 156                                                 NULL;
 157
 158        if (pdata && pdata->mii_bus)
 159                return tsec_phy_read(pdata->mii_bus, addr, devad, reg);
 160
 161        return -1;
 162}
 163
 164static int tsec_mdio_write(struct udevice *dev, int addr, int devad, int reg,
 165                           u16 val)
 166{
 167        struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) :
 168                                                 NULL;
 169
 170        if (pdata && pdata->mii_bus)
 171                return tsec_phy_write(pdata->mii_bus, addr, devad, reg, val);
 172
 173        return -1;
 174}
 175
 176static int tsec_mdio_reset(struct udevice *dev)
 177{
 178        struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) :
 179                                                 NULL;
 180
 181        if (pdata && pdata->mii_bus)
 182                return fsl_pq_mdio_reset(pdata->mii_bus);
 183
 184        return -1;
 185}
 186
 187static const struct mdio_ops tsec_mdio_ops = {
 188        .read = tsec_mdio_read,
 189        .write = tsec_mdio_write,
 190        .reset = tsec_mdio_reset,
 191};
 192
 193static const struct udevice_id tsec_mdio_ids[] = {
 194        { .compatible = "fsl,gianfar-tbi" },
 195        { .compatible = "fsl,gianfar-mdio" },
 196        { .compatible = "fsl,etsec2-tbi" },
 197        { .compatible = "fsl,etsec2-mdio" },
 198        { .compatible = "fsl,fman-mdio" },
 199        {}
 200};
 201
 202static int tsec_mdio_probe(struct udevice *dev)
 203{
 204        struct tsec_mdio_priv *priv = (dev) ? dev_get_priv(dev) : NULL;
 205        struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) :
 206                                                 NULL;
 207
 208        if (!dev) {
 209                printf("%s dev = NULL\n", __func__);
 210                return -1;
 211        }
 212        if (!priv) {
 213                printf("dev_get_priv(dev %p) = NULL\n", dev);
 214                return -1;
 215        }
 216        priv->regs = (void *)(uintptr_t)dev_read_addr(dev);
 217        debug("%s priv %p @ regs %p, pdata %p\n", __func__,
 218              priv, priv->regs, pdata);
 219
 220        return 0;
 221}
 222
 223static int tsec_mdio_remove(struct udevice *dev)
 224{
 225        return 0;
 226}
 227
 228U_BOOT_DRIVER(tsec_mdio) = {
 229        .name = "tsec_mdio",
 230        .id = UCLASS_MDIO,
 231        .of_match = tsec_mdio_ids,
 232        .probe = tsec_mdio_probe,
 233        .remove = tsec_mdio_remove,
 234        .ops = &tsec_mdio_ops,
 235        .priv_auto_alloc_size = sizeof(struct tsec_mdio_priv),
 236        .platdata_auto_alloc_size = sizeof(struct mdio_perdev_priv),
 237};
 238#endif /* CONFIG_PHYLIB */
 239#endif /* CONFIG_DM_MDIO */
 240