Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Applied Micro X-Gene SoC Ethernet v2 Driver
0004  *
0005  * Copyright (c) 2017, Applied Micro Circuits Corporation
0006  * Author(s): Iyappan Subramanian <isubramanian@apm.com>
0007  *        Keyur Chudgar <kchudgar@apm.com>
0008  */
0009 
0010 #include "main.h"
0011 
0012 static int xge_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 data)
0013 {
0014     struct xge_pdata *pdata = bus->priv;
0015     u32 done, val = 0;
0016     u8 wait = 10;
0017 
0018     SET_REG_BITS(&val, PHY_ADDR, phy_id);
0019     SET_REG_BITS(&val, REG_ADDR, reg);
0020     xge_wr_csr(pdata, MII_MGMT_ADDRESS, val);
0021 
0022     xge_wr_csr(pdata, MII_MGMT_CONTROL, data);
0023     do {
0024         usleep_range(5, 10);
0025         done = xge_rd_csr(pdata, MII_MGMT_INDICATORS);
0026     } while ((done & MII_MGMT_BUSY) && wait--);
0027 
0028     if (done & MII_MGMT_BUSY) {
0029         dev_err(&bus->dev, "MII_MGMT write failed\n");
0030         return -ETIMEDOUT;
0031     }
0032 
0033     return 0;
0034 }
0035 
0036 static int xge_mdio_read(struct mii_bus *bus, int phy_id, int reg)
0037 {
0038     struct xge_pdata *pdata = bus->priv;
0039     u32 data, done, val = 0;
0040     u8 wait = 10;
0041 
0042     SET_REG_BITS(&val, PHY_ADDR, phy_id);
0043     SET_REG_BITS(&val, REG_ADDR, reg);
0044     xge_wr_csr(pdata, MII_MGMT_ADDRESS, val);
0045 
0046     xge_wr_csr(pdata, MII_MGMT_COMMAND, MII_READ_CYCLE);
0047     do {
0048         usleep_range(5, 10);
0049         done = xge_rd_csr(pdata, MII_MGMT_INDICATORS);
0050     } while ((done & MII_MGMT_BUSY) && wait--);
0051 
0052     if (done & MII_MGMT_BUSY) {
0053         dev_err(&bus->dev, "MII_MGMT read failed\n");
0054         return -ETIMEDOUT;
0055     }
0056 
0057     data = xge_rd_csr(pdata, MII_MGMT_STATUS);
0058     xge_wr_csr(pdata, MII_MGMT_COMMAND, 0);
0059 
0060     return data;
0061 }
0062 
0063 static void xge_adjust_link(struct net_device *ndev)
0064 {
0065     struct xge_pdata *pdata = netdev_priv(ndev);
0066     struct phy_device *phydev = ndev->phydev;
0067 
0068     if (phydev->link) {
0069         if (pdata->phy_speed != phydev->speed) {
0070             pdata->phy_speed = phydev->speed;
0071             xge_mac_set_speed(pdata);
0072             xge_mac_enable(pdata);
0073             phy_print_status(phydev);
0074         }
0075     } else {
0076         if (pdata->phy_speed != SPEED_UNKNOWN) {
0077             pdata->phy_speed = SPEED_UNKNOWN;
0078             xge_mac_disable(pdata);
0079             phy_print_status(phydev);
0080         }
0081     }
0082 }
0083 
0084 void xge_mdio_remove(struct net_device *ndev)
0085 {
0086     struct xge_pdata *pdata = netdev_priv(ndev);
0087     struct mii_bus *mdio_bus = pdata->mdio_bus;
0088 
0089     if (ndev->phydev)
0090         phy_disconnect(ndev->phydev);
0091 
0092     if (mdio_bus->state == MDIOBUS_REGISTERED)
0093         mdiobus_unregister(mdio_bus);
0094 
0095     mdiobus_free(mdio_bus);
0096 }
0097 
0098 int xge_mdio_config(struct net_device *ndev)
0099 {
0100     __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
0101     struct xge_pdata *pdata = netdev_priv(ndev);
0102     struct device *dev = &pdata->pdev->dev;
0103     struct mii_bus *mdio_bus;
0104     struct phy_device *phydev;
0105     int ret;
0106 
0107     mdio_bus = mdiobus_alloc();
0108     if (!mdio_bus)
0109         return -ENOMEM;
0110 
0111     mdio_bus->name = "APM X-Gene Ethernet (v2) MDIO Bus";
0112     mdio_bus->read = xge_mdio_read;
0113     mdio_bus->write = xge_mdio_write;
0114     mdio_bus->priv = pdata;
0115     mdio_bus->parent = dev;
0116     snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(dev));
0117     pdata->mdio_bus = mdio_bus;
0118 
0119     mdio_bus->phy_mask = 0x1;
0120     ret = mdiobus_register(mdio_bus);
0121     if (ret)
0122         goto err;
0123 
0124     phydev = phy_find_first(mdio_bus);
0125     if (!phydev) {
0126         dev_err(dev, "no PHY found\n");
0127         ret = -ENODEV;
0128         goto err;
0129     }
0130     phydev = phy_connect(ndev, phydev_name(phydev),
0131                  &xge_adjust_link,
0132                  pdata->resources.phy_mode);
0133 
0134     if (IS_ERR(phydev)) {
0135         netdev_err(ndev, "Could not attach to PHY\n");
0136         ret = PTR_ERR(phydev);
0137         goto err;
0138     }
0139 
0140     linkmode_set_bit_array(phy_10_100_features_array,
0141                    ARRAY_SIZE(phy_10_100_features_array),
0142                    mask);
0143     linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, mask);
0144     linkmode_set_bit(ETHTOOL_LINK_MODE_AUI_BIT, mask);
0145     linkmode_set_bit(ETHTOOL_LINK_MODE_MII_BIT, mask);
0146     linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, mask);
0147     linkmode_set_bit(ETHTOOL_LINK_MODE_BNC_BIT, mask);
0148 
0149     linkmode_andnot(phydev->supported, phydev->supported, mask);
0150     linkmode_copy(phydev->advertising, phydev->supported);
0151     pdata->phy_speed = SPEED_UNKNOWN;
0152 
0153     return 0;
0154 err:
0155     xge_mdio_remove(ndev);
0156 
0157     return ret;
0158 }