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