0001
0002
0003
0004
0005
0006
0007
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 }