root/drivers/net/ethernet/freescale/enetc/enetc_mdio.c

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

DEFINITIONS

This source file includes following definitions.
  1. enetc_mdio_wait_complete
  2. enetc_mdio_write
  3. enetc_mdio_read
  4. enetc_mdio_probe
  5. enetc_mdio_remove

   1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
   2 /* Copyright 2019 NXP */
   3 
   4 #include <linux/mdio.h>
   5 #include <linux/of_mdio.h>
   6 #include <linux/iopoll.h>
   7 #include <linux/of.h>
   8 
   9 #include "enetc_mdio.h"
  10 
  11 #define ENETC_MDIO_REG_OFFSET   0x1c00
  12 #define ENETC_MDIO_CFG  0x0     /* MDIO configuration and status */
  13 #define ENETC_MDIO_CTL  0x4     /* MDIO control */
  14 #define ENETC_MDIO_DATA 0x8     /* MDIO data */
  15 #define ENETC_MDIO_ADDR 0xc     /* MDIO address */
  16 
  17 #define enetc_mdio_rd(hw, off) \
  18         enetc_port_rd(hw, ENETC_##off + ENETC_MDIO_REG_OFFSET)
  19 #define enetc_mdio_wr(hw, off, val) \
  20         enetc_port_wr(hw, ENETC_##off + ENETC_MDIO_REG_OFFSET, val)
  21 #define enetc_mdio_rd_reg(off)  enetc_mdio_rd(hw, off)
  22 
  23 #define ENETC_MDC_DIV           258
  24 
  25 #define MDIO_CFG_CLKDIV(x)      ((((x) >> 1) & 0xff) << 8)
  26 #define MDIO_CFG_BSY            BIT(0)
  27 #define MDIO_CFG_RD_ER          BIT(1)
  28 #define MDIO_CFG_ENC45          BIT(6)
  29  /* external MDIO only - driven on neg MDC edge */
  30 #define MDIO_CFG_NEG            BIT(23)
  31 
  32 #define MDIO_CTL_DEV_ADDR(x)    ((x) & 0x1f)
  33 #define MDIO_CTL_PORT_ADDR(x)   (((x) & 0x1f) << 5)
  34 #define MDIO_CTL_READ           BIT(15)
  35 #define MDIO_DATA(x)            ((x) & 0xffff)
  36 
  37 #define TIMEOUT 1000
  38 static int enetc_mdio_wait_complete(struct enetc_hw *hw)
  39 {
  40         u32 val;
  41 
  42         return readx_poll_timeout(enetc_mdio_rd_reg, MDIO_CFG, val,
  43                                   !(val & MDIO_CFG_BSY), 10, 10 * TIMEOUT);
  44 }
  45 
  46 int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value)
  47 {
  48         struct enetc_mdio_priv *mdio_priv = bus->priv;
  49         struct enetc_hw *hw = mdio_priv->hw;
  50         u32 mdio_ctl, mdio_cfg;
  51         u16 dev_addr;
  52         int ret;
  53 
  54         mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG;
  55         if (regnum & MII_ADDR_C45) {
  56                 dev_addr = (regnum >> 16) & 0x1f;
  57                 mdio_cfg |= MDIO_CFG_ENC45;
  58         } else {
  59                 /* clause 22 (ie 1G) */
  60                 dev_addr = regnum & 0x1f;
  61                 mdio_cfg &= ~MDIO_CFG_ENC45;
  62         }
  63 
  64         enetc_mdio_wr(hw, MDIO_CFG, mdio_cfg);
  65 
  66         ret = enetc_mdio_wait_complete(hw);
  67         if (ret)
  68                 return ret;
  69 
  70         /* set port and dev addr */
  71         mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
  72         enetc_mdio_wr(hw, MDIO_CTL, mdio_ctl);
  73 
  74         /* set the register address */
  75         if (regnum & MII_ADDR_C45) {
  76                 enetc_mdio_wr(hw, MDIO_ADDR, regnum & 0xffff);
  77 
  78                 ret = enetc_mdio_wait_complete(hw);
  79                 if (ret)
  80                         return ret;
  81         }
  82 
  83         /* write the value */
  84         enetc_mdio_wr(hw, MDIO_DATA, MDIO_DATA(value));
  85 
  86         ret = enetc_mdio_wait_complete(hw);
  87         if (ret)
  88                 return ret;
  89 
  90         return 0;
  91 }
  92 
  93 int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
  94 {
  95         struct enetc_mdio_priv *mdio_priv = bus->priv;
  96         struct enetc_hw *hw = mdio_priv->hw;
  97         u32 mdio_ctl, mdio_cfg;
  98         u16 dev_addr, value;
  99         int ret;
 100 
 101         mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG;
 102         if (regnum & MII_ADDR_C45) {
 103                 dev_addr = (regnum >> 16) & 0x1f;
 104                 mdio_cfg |= MDIO_CFG_ENC45;
 105         } else {
 106                 dev_addr = regnum & 0x1f;
 107                 mdio_cfg &= ~MDIO_CFG_ENC45;
 108         }
 109 
 110         enetc_mdio_wr(hw, MDIO_CFG, mdio_cfg);
 111 
 112         ret = enetc_mdio_wait_complete(hw);
 113         if (ret)
 114                 return ret;
 115 
 116         /* set port and device addr */
 117         mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
 118         enetc_mdio_wr(hw, MDIO_CTL, mdio_ctl);
 119 
 120         /* set the register address */
 121         if (regnum & MII_ADDR_C45) {
 122                 enetc_mdio_wr(hw, MDIO_ADDR, regnum & 0xffff);
 123 
 124                 ret = enetc_mdio_wait_complete(hw);
 125                 if (ret)
 126                         return ret;
 127         }
 128 
 129         /* initiate the read */
 130         enetc_mdio_wr(hw, MDIO_CTL, mdio_ctl | MDIO_CTL_READ);
 131 
 132         ret = enetc_mdio_wait_complete(hw);
 133         if (ret)
 134                 return ret;
 135 
 136         /* return all Fs if nothing was there */
 137         if (enetc_mdio_rd(hw, MDIO_CFG) & MDIO_CFG_RD_ER) {
 138                 dev_dbg(&bus->dev,
 139                         "Error while reading PHY%d reg at %d.%hhu\n",
 140                         phy_id, dev_addr, regnum);
 141                 return 0xffff;
 142         }
 143 
 144         value = enetc_mdio_rd(hw, MDIO_DATA) & 0xffff;
 145 
 146         return value;
 147 }
 148 
 149 int enetc_mdio_probe(struct enetc_pf *pf)
 150 {
 151         struct device *dev = &pf->si->pdev->dev;
 152         struct enetc_mdio_priv *mdio_priv;
 153         struct device_node *np;
 154         struct mii_bus *bus;
 155         int err;
 156 
 157         bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv));
 158         if (!bus)
 159                 return -ENOMEM;
 160 
 161         bus->name = "Freescale ENETC MDIO Bus";
 162         bus->read = enetc_mdio_read;
 163         bus->write = enetc_mdio_write;
 164         bus->parent = dev;
 165         mdio_priv = bus->priv;
 166         mdio_priv->hw = &pf->si->hw;
 167         snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
 168 
 169         np = of_get_child_by_name(dev->of_node, "mdio");
 170         if (!np) {
 171                 dev_err(dev, "MDIO node missing\n");
 172                 return -EINVAL;
 173         }
 174 
 175         err = of_mdiobus_register(bus, np);
 176         if (err) {
 177                 of_node_put(np);
 178                 dev_err(dev, "cannot register MDIO bus\n");
 179                 return err;
 180         }
 181 
 182         of_node_put(np);
 183         pf->mdio = bus;
 184 
 185         return 0;
 186 }
 187 
 188 void enetc_mdio_remove(struct enetc_pf *pf)
 189 {
 190         if (pf->mdio)
 191                 mdiobus_unregister(pf->mdio);
 192 }

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