|
@@ -682,70 +682,6 @@ static int bgmac_phy_write(struct bgmac *bgmac, u8 phyaddr, u8 reg, u16 value)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyforce */
|
|
|
-static void bgmac_phy_force(struct bgmac *bgmac)
|
|
|
-{
|
|
|
- u16 ctl;
|
|
|
- u16 mask = ~(BGMAC_PHY_CTL_SPEED | BGMAC_PHY_CTL_SPEED_MSB |
|
|
|
- BGMAC_PHY_CTL_ANENAB | BGMAC_PHY_CTL_DUPLEX);
|
|
|
-
|
|
|
- if (bgmac->phyaddr == BGMAC_PHY_NOREGS)
|
|
|
- return;
|
|
|
-
|
|
|
- if (bgmac->autoneg)
|
|
|
- return;
|
|
|
-
|
|
|
- ctl = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL);
|
|
|
- ctl &= mask;
|
|
|
- if (bgmac->full_duplex)
|
|
|
- ctl |= BGMAC_PHY_CTL_DUPLEX;
|
|
|
- if (bgmac->speed == BGMAC_SPEED_100)
|
|
|
- ctl |= BGMAC_PHY_CTL_SPEED_100;
|
|
|
- else if (bgmac->speed == BGMAC_SPEED_1000)
|
|
|
- ctl |= BGMAC_PHY_CTL_SPEED_1000;
|
|
|
- bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL, ctl);
|
|
|
-}
|
|
|
-
|
|
|
-/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyadvertise */
|
|
|
-static void bgmac_phy_advertise(struct bgmac *bgmac)
|
|
|
-{
|
|
|
- u16 adv;
|
|
|
-
|
|
|
- if (bgmac->phyaddr == BGMAC_PHY_NOREGS)
|
|
|
- return;
|
|
|
-
|
|
|
- if (!bgmac->autoneg)
|
|
|
- return;
|
|
|
-
|
|
|
- /* Adv selected 10/100 speeds */
|
|
|
- adv = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV);
|
|
|
- adv &= ~(BGMAC_PHY_ADV_10HALF | BGMAC_PHY_ADV_10FULL |
|
|
|
- BGMAC_PHY_ADV_100HALF | BGMAC_PHY_ADV_100FULL);
|
|
|
- if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_10)
|
|
|
- adv |= BGMAC_PHY_ADV_10HALF;
|
|
|
- if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_100)
|
|
|
- adv |= BGMAC_PHY_ADV_100HALF;
|
|
|
- if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_10)
|
|
|
- adv |= BGMAC_PHY_ADV_10FULL;
|
|
|
- if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_100)
|
|
|
- adv |= BGMAC_PHY_ADV_100FULL;
|
|
|
- bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV, adv);
|
|
|
-
|
|
|
- /* Adv selected 1000 speeds */
|
|
|
- adv = bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV2);
|
|
|
- adv &= ~(BGMAC_PHY_ADV2_1000HALF | BGMAC_PHY_ADV2_1000FULL);
|
|
|
- if (!bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_1000)
|
|
|
- adv |= BGMAC_PHY_ADV2_1000HALF;
|
|
|
- if (bgmac->full_duplex && bgmac->speed & BGMAC_SPEED_1000)
|
|
|
- adv |= BGMAC_PHY_ADV2_1000FULL;
|
|
|
- bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_ADV2, adv);
|
|
|
-
|
|
|
- /* Restart */
|
|
|
- bgmac_phy_write(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL,
|
|
|
- bgmac_phy_read(bgmac, bgmac->phyaddr, BGMAC_PHY_CTL) |
|
|
|
- BGMAC_PHY_CTL_RESTART);
|
|
|
-}
|
|
|
-
|
|
|
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyinit */
|
|
|
static void bgmac_phy_init(struct bgmac *bgmac)
|
|
|
{
|
|
@@ -876,19 +812,28 @@ static void bgmac_clear_mib(struct bgmac *bgmac)
|
|
|
}
|
|
|
|
|
|
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_speed */
|
|
|
-static void bgmac_speed(struct bgmac *bgmac, int speed)
|
|
|
+static void bgmac_mac_speed(struct bgmac *bgmac)
|
|
|
{
|
|
|
u32 mask = ~(BGMAC_CMDCFG_ES_MASK | BGMAC_CMDCFG_HD);
|
|
|
u32 set = 0;
|
|
|
|
|
|
- if (speed & BGMAC_SPEED_10)
|
|
|
+ switch (bgmac->mac_speed) {
|
|
|
+ case SPEED_10:
|
|
|
set |= BGMAC_CMDCFG_ES_10;
|
|
|
- if (speed & BGMAC_SPEED_100)
|
|
|
+ break;
|
|
|
+ case SPEED_100:
|
|
|
set |= BGMAC_CMDCFG_ES_100;
|
|
|
- if (speed & BGMAC_SPEED_1000)
|
|
|
+ break;
|
|
|
+ case SPEED_1000:
|
|
|
set |= BGMAC_CMDCFG_ES_1000;
|
|
|
- if (!bgmac->full_duplex)
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ bgmac_err(bgmac, "Unsupported speed: %d\n", bgmac->mac_speed);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (bgmac->mac_duplex == DUPLEX_HALF)
|
|
|
set |= BGMAC_CMDCFG_HD;
|
|
|
+
|
|
|
bgmac_cmdcfg_maskset(bgmac, mask, set, true);
|
|
|
}
|
|
|
|
|
@@ -897,10 +842,9 @@ static void bgmac_miiconfig(struct bgmac *bgmac)
|
|
|
u8 imode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >>
|
|
|
BGMAC_DS_MM_SHIFT;
|
|
|
if (imode == 0 || imode == 1) {
|
|
|
- if (bgmac->autoneg)
|
|
|
- bgmac_speed(bgmac, BGMAC_SPEED_100);
|
|
|
- else
|
|
|
- bgmac_speed(bgmac, bgmac->speed);
|
|
|
+ bgmac->mac_speed = SPEED_100;
|
|
|
+ bgmac->mac_duplex = DUPLEX_FULL;
|
|
|
+ bgmac_mac_speed(bgmac);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1108,13 +1052,6 @@ static void bgmac_chip_init(struct bgmac *bgmac, bool full_init)
|
|
|
|
|
|
bgmac_write(bgmac, BGMAC_RXMAX_LENGTH, 32 + ETHER_MAX_LEN);
|
|
|
|
|
|
- if (!bgmac->autoneg) {
|
|
|
- bgmac_speed(bgmac, bgmac->speed);
|
|
|
- bgmac_phy_force(bgmac);
|
|
|
- } else if (bgmac->speed) { /* if there is anything to adv */
|
|
|
- bgmac_phy_advertise(bgmac);
|
|
|
- }
|
|
|
-
|
|
|
if (full_init) {
|
|
|
bgmac_dma_init(bgmac);
|
|
|
if (1) /* FIXME: is there any case we don't want IRQs? */
|
|
@@ -1294,61 +1231,16 @@ static int bgmac_get_settings(struct net_device *net_dev,
|
|
|
{
|
|
|
struct bgmac *bgmac = netdev_priv(net_dev);
|
|
|
|
|
|
- cmd->supported = SUPPORTED_10baseT_Half |
|
|
|
- SUPPORTED_10baseT_Full |
|
|
|
- SUPPORTED_100baseT_Half |
|
|
|
- SUPPORTED_100baseT_Full |
|
|
|
- SUPPORTED_1000baseT_Half |
|
|
|
- SUPPORTED_1000baseT_Full |
|
|
|
- SUPPORTED_Autoneg;
|
|
|
-
|
|
|
- if (bgmac->autoneg) {
|
|
|
- WARN_ON(cmd->advertising);
|
|
|
- if (bgmac->full_duplex) {
|
|
|
- if (bgmac->speed & BGMAC_SPEED_10)
|
|
|
- cmd->advertising |= ADVERTISED_10baseT_Full;
|
|
|
- if (bgmac->speed & BGMAC_SPEED_100)
|
|
|
- cmd->advertising |= ADVERTISED_100baseT_Full;
|
|
|
- if (bgmac->speed & BGMAC_SPEED_1000)
|
|
|
- cmd->advertising |= ADVERTISED_1000baseT_Full;
|
|
|
- } else {
|
|
|
- if (bgmac->speed & BGMAC_SPEED_10)
|
|
|
- cmd->advertising |= ADVERTISED_10baseT_Half;
|
|
|
- if (bgmac->speed & BGMAC_SPEED_100)
|
|
|
- cmd->advertising |= ADVERTISED_100baseT_Half;
|
|
|
- if (bgmac->speed & BGMAC_SPEED_1000)
|
|
|
- cmd->advertising |= ADVERTISED_1000baseT_Half;
|
|
|
- }
|
|
|
- } else {
|
|
|
- switch (bgmac->speed) {
|
|
|
- case BGMAC_SPEED_10:
|
|
|
- ethtool_cmd_speed_set(cmd, SPEED_10);
|
|
|
- break;
|
|
|
- case BGMAC_SPEED_100:
|
|
|
- ethtool_cmd_speed_set(cmd, SPEED_100);
|
|
|
- break;
|
|
|
- case BGMAC_SPEED_1000:
|
|
|
- ethtool_cmd_speed_set(cmd, SPEED_1000);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- cmd->duplex = bgmac->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
|
|
|
-
|
|
|
- cmd->autoneg = bgmac->autoneg;
|
|
|
-
|
|
|
- return 0;
|
|
|
+ return phy_ethtool_gset(bgmac->phy_dev, cmd);
|
|
|
}
|
|
|
|
|
|
-#if 0
|
|
|
static int bgmac_set_settings(struct net_device *net_dev,
|
|
|
struct ethtool_cmd *cmd)
|
|
|
{
|
|
|
struct bgmac *bgmac = netdev_priv(net_dev);
|
|
|
|
|
|
- return -1;
|
|
|
+ return phy_ethtool_sset(bgmac->phy_dev, cmd);
|
|
|
}
|
|
|
-#endif
|
|
|
|
|
|
static void bgmac_get_drvinfo(struct net_device *net_dev,
|
|
|
struct ethtool_drvinfo *info)
|
|
@@ -1359,6 +1251,7 @@ static void bgmac_get_drvinfo(struct net_device *net_dev,
|
|
|
|
|
|
static const struct ethtool_ops bgmac_ethtool_ops = {
|
|
|
.get_settings = bgmac_get_settings,
|
|
|
+ .set_settings = bgmac_set_settings,
|
|
|
.get_drvinfo = bgmac_get_drvinfo,
|
|
|
};
|
|
|
|
|
@@ -1377,9 +1270,35 @@ static int bgmac_mii_write(struct mii_bus *bus, int mii_id, int regnum,
|
|
|
return bgmac_phy_write(bus->priv, mii_id, regnum, value);
|
|
|
}
|
|
|
|
|
|
+static void bgmac_adjust_link(struct net_device *net_dev)
|
|
|
+{
|
|
|
+ struct bgmac *bgmac = netdev_priv(net_dev);
|
|
|
+ struct phy_device *phy_dev = bgmac->phy_dev;
|
|
|
+ bool update = false;
|
|
|
+
|
|
|
+ if (phy_dev->link) {
|
|
|
+ if (phy_dev->speed != bgmac->mac_speed) {
|
|
|
+ bgmac->mac_speed = phy_dev->speed;
|
|
|
+ update = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (phy_dev->duplex != bgmac->mac_duplex) {
|
|
|
+ bgmac->mac_duplex = phy_dev->duplex;
|
|
|
+ update = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (update) {
|
|
|
+ bgmac_mac_speed(bgmac);
|
|
|
+ phy_print_status(phy_dev);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int bgmac_mii_register(struct bgmac *bgmac)
|
|
|
{
|
|
|
struct mii_bus *mii_bus;
|
|
|
+ struct phy_device *phy_dev;
|
|
|
+ char bus_id[MII_BUS_ID_SIZE + 3];
|
|
|
int i, err = 0;
|
|
|
|
|
|
mii_bus = mdiobus_alloc();
|
|
@@ -1411,8 +1330,22 @@ static int bgmac_mii_register(struct bgmac *bgmac)
|
|
|
|
|
|
bgmac->mii_bus = mii_bus;
|
|
|
|
|
|
+ /* Connect to the PHY */
|
|
|
+ snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, mii_bus->id,
|
|
|
+ bgmac->phyaddr);
|
|
|
+ phy_dev = phy_connect(bgmac->net_dev, bus_id, &bgmac_adjust_link,
|
|
|
+ PHY_INTERFACE_MODE_MII);
|
|
|
+ if (IS_ERR(phy_dev)) {
|
|
|
+ bgmac_err(bgmac, "PHY connecton failed\n");
|
|
|
+ err = PTR_ERR(phy_dev);
|
|
|
+ goto err_unregister_bus;
|
|
|
+ }
|
|
|
+ bgmac->phy_dev = phy_dev;
|
|
|
+
|
|
|
return err;
|
|
|
|
|
|
+err_unregister_bus:
|
|
|
+ mdiobus_unregister(mii_bus);
|
|
|
err_free_irq:
|
|
|
kfree(mii_bus->irq);
|
|
|
err_free_bus:
|
|
@@ -1467,9 +1400,6 @@ static int bgmac_probe(struct bcma_device *core)
|
|
|
bcma_set_drvdata(core, bgmac);
|
|
|
|
|
|
/* Defaults */
|
|
|
- bgmac->autoneg = true;
|
|
|
- bgmac->full_duplex = true;
|
|
|
- bgmac->speed = BGMAC_SPEED_10 | BGMAC_SPEED_100 | BGMAC_SPEED_1000;
|
|
|
memcpy(bgmac->net_dev->dev_addr, mac, ETH_ALEN);
|
|
|
|
|
|
/* On BCM4706 we need common core to access PHY */
|