root/drivers/net/ethernet/apm/xgene-v2/mdio.c

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

DEFINITIONS

This source file includes following definitions.
  1. xge_mdio_write
  2. xge_mdio_read
  3. xge_adjust_link
  4. xge_mdio_remove
  5. xge_mdio_config

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Applied Micro X-Gene SoC Ethernet v2 Driver
   4  *
   5  * Copyright (c) 2017, Applied Micro Circuits Corporation
   6  * Author(s): Iyappan Subramanian <isubramanian@apm.com>
   7  *            Keyur Chudgar <kchudgar@apm.com>
   8  */
   9 
  10 #include "main.h"
  11 
  12 static int xge_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 data)
  13 {
  14         struct xge_pdata *pdata = bus->priv;
  15         u32 done, val = 0;
  16         u8 wait = 10;
  17 
  18         SET_REG_BITS(&val, PHY_ADDR, phy_id);
  19         SET_REG_BITS(&val, REG_ADDR, reg);
  20         xge_wr_csr(pdata, MII_MGMT_ADDRESS, val);
  21 
  22         xge_wr_csr(pdata, MII_MGMT_CONTROL, data);
  23         do {
  24                 usleep_range(5, 10);
  25                 done = xge_rd_csr(pdata, MII_MGMT_INDICATORS);
  26         } while ((done & MII_MGMT_BUSY) && wait--);
  27 
  28         if (done & MII_MGMT_BUSY) {
  29                 dev_err(&bus->dev, "MII_MGMT write failed\n");
  30                 return -ETIMEDOUT;
  31         }
  32 
  33         return 0;
  34 }
  35 
  36 static int xge_mdio_read(struct mii_bus *bus, int phy_id, int reg)
  37 {
  38         struct xge_pdata *pdata = bus->priv;
  39         u32 data, done, val = 0;
  40         u8 wait = 10;
  41 
  42         SET_REG_BITS(&val, PHY_ADDR, phy_id);
  43         SET_REG_BITS(&val, REG_ADDR, reg);
  44         xge_wr_csr(pdata, MII_MGMT_ADDRESS, val);
  45 
  46         xge_wr_csr(pdata, MII_MGMT_COMMAND, MII_READ_CYCLE);
  47         do {
  48                 usleep_range(5, 10);
  49                 done = xge_rd_csr(pdata, MII_MGMT_INDICATORS);
  50         } while ((done & MII_MGMT_BUSY) && wait--);
  51 
  52         if (done & MII_MGMT_BUSY) {
  53                 dev_err(&bus->dev, "MII_MGMT read failed\n");
  54                 return -ETIMEDOUT;
  55         }
  56 
  57         data = xge_rd_csr(pdata, MII_MGMT_STATUS);
  58         xge_wr_csr(pdata, MII_MGMT_COMMAND, 0);
  59 
  60         return data;
  61 }
  62 
  63 static void xge_adjust_link(struct net_device *ndev)
  64 {
  65         struct xge_pdata *pdata = netdev_priv(ndev);
  66         struct phy_device *phydev = ndev->phydev;
  67 
  68         if (phydev->link) {
  69                 if (pdata->phy_speed != phydev->speed) {
  70                         pdata->phy_speed = phydev->speed;
  71                         xge_mac_set_speed(pdata);
  72                         xge_mac_enable(pdata);
  73                         phy_print_status(phydev);
  74                 }
  75         } else {
  76                 if (pdata->phy_speed != SPEED_UNKNOWN) {
  77                         pdata->phy_speed = SPEED_UNKNOWN;
  78                         xge_mac_disable(pdata);
  79                         phy_print_status(phydev);
  80                 }
  81         }
  82 }
  83 
  84 void xge_mdio_remove(struct net_device *ndev)
  85 {
  86         struct xge_pdata *pdata = netdev_priv(ndev);
  87         struct mii_bus *mdio_bus = pdata->mdio_bus;
  88 
  89         if (ndev->phydev)
  90                 phy_disconnect(ndev->phydev);
  91 
  92         if (mdio_bus->state == MDIOBUS_REGISTERED)
  93                 mdiobus_unregister(mdio_bus);
  94 
  95         mdiobus_free(mdio_bus);
  96 }
  97 
  98 int xge_mdio_config(struct net_device *ndev)
  99 {
 100         __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
 101         struct xge_pdata *pdata = netdev_priv(ndev);
 102         struct device *dev = &pdata->pdev->dev;
 103         struct mii_bus *mdio_bus;
 104         struct phy_device *phydev;
 105         int ret;
 106 
 107         mdio_bus = mdiobus_alloc();
 108         if (!mdio_bus)
 109                 return -ENOMEM;
 110 
 111         mdio_bus->name = "APM X-Gene Ethernet (v2) MDIO Bus";
 112         mdio_bus->read = xge_mdio_read;
 113         mdio_bus->write = xge_mdio_write;
 114         mdio_bus->priv = pdata;
 115         mdio_bus->parent = dev;
 116         snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(dev));
 117         pdata->mdio_bus = mdio_bus;
 118 
 119         mdio_bus->phy_mask = 0x1;
 120         ret = mdiobus_register(mdio_bus);
 121         if (ret)
 122                 goto err;
 123 
 124         phydev = phy_find_first(mdio_bus);
 125         if (!phydev) {
 126                 dev_err(dev, "no PHY found\n");
 127                 ret = -ENODEV;
 128                 goto err;
 129         }
 130         phydev = phy_connect(ndev, phydev_name(phydev),
 131                              &xge_adjust_link,
 132                              pdata->resources.phy_mode);
 133 
 134         if (IS_ERR(phydev)) {
 135                 netdev_err(ndev, "Could not attach to PHY\n");
 136                 ret = PTR_ERR(phydev);
 137                 goto err;
 138         }
 139 
 140         linkmode_set_bit_array(phy_10_100_features_array,
 141                                ARRAY_SIZE(phy_10_100_features_array),
 142                                mask);
 143         linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, mask);
 144         linkmode_set_bit(ETHTOOL_LINK_MODE_AUI_BIT, mask);
 145         linkmode_set_bit(ETHTOOL_LINK_MODE_MII_BIT, mask);
 146         linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, mask);
 147         linkmode_set_bit(ETHTOOL_LINK_MODE_BNC_BIT, mask);
 148 
 149         linkmode_andnot(phydev->supported, phydev->supported, mask);
 150         linkmode_copy(phydev->advertising, phydev->supported);
 151         pdata->phy_speed = SPEED_UNKNOWN;
 152 
 153         return 0;
 154 err:
 155         xge_mdio_remove(ndev);
 156 
 157         return ret;
 158 }

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