Commit 515d8467 authored by David S. Miller's avatar David S. Miller

Merge branch 'net-phy-aquantia-improve-and-extend-driver'

Heiner Kallweit says:

====================
net: phy: aquantia: improve and extend driver

This series improves and extends the Aquantia PHY driver.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f88d5d68 dc59d9bb
......@@ -20,6 +20,10 @@
#define PHY_ID_AQCS109 0x03a1b5c2
#define PHY_ID_AQR405 0x03a1b4b0
#define MDIO_AN_VEND_PROV 0xc400
#define MDIO_AN_VEND_PROV_1000BASET_FULL BIT(15)
#define MDIO_AN_VEND_PROV_1000BASET_HALF BIT(14)
#define MDIO_AN_TX_VEND_STATUS1 0xc800
#define MDIO_AN_TX_VEND_STATUS1_10BASET (0x0 << 1)
#define MDIO_AN_TX_VEND_STATUS1_100BASETX (0x1 << 1)
......@@ -35,6 +39,10 @@
#define MDIO_AN_TX_VEND_INT_MASK2 0xd401
#define MDIO_AN_TX_VEND_INT_MASK2_LINK BIT(0)
#define MDIO_AN_RX_LP_STAT1 0xe820
#define MDIO_AN_RX_LP_STAT1_1000BASET_FULL BIT(15)
#define MDIO_AN_RX_LP_STAT1_1000BASET_HALF BIT(14)
/* Vendor specific 1, MDIO_MMD_VEND1 */
#define VEND1_GLOBAL_INT_STD_STATUS 0xfc00
#define VEND1_GLOBAL_INT_VEND_STATUS 0xfc01
......@@ -64,10 +72,40 @@
static int aqr_config_aneg(struct phy_device *phydev)
{
linkmode_copy(phydev->supported, phy_10gbit_features);
linkmode_copy(phydev->advertising, phydev->supported);
bool changed = false;
u16 reg;
int ret;
if (phydev->autoneg == AUTONEG_DISABLE)
return genphy_c45_pma_setup_forced(phydev);
ret = genphy_c45_an_config_aneg(phydev);
if (ret < 0)
return ret;
if (ret > 0)
changed = true;
/* Clause 45 has no standardized support for 1000BaseT, therefore
* use vendor registers for this mode.
*/
reg = 0;
if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
phydev->advertising))
reg |= MDIO_AN_VEND_PROV_1000BASET_FULL;
if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
phydev->advertising))
reg |= MDIO_AN_VEND_PROV_1000BASET_HALF;
return 0;
ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_VEND_PROV,
MDIO_AN_VEND_PROV_1000BASET_HALF |
MDIO_AN_VEND_PROV_1000BASET_FULL, reg);
if (ret < 0)
return ret;
if (ret > 0)
changed = true;
return genphy_c45_check_and_restart_aneg(phydev, changed);
}
static int aqr_config_intr(struct phy_device *phydev)
......@@ -120,36 +158,31 @@ static int aqr_ack_interrupt(struct phy_device *phydev)
static int aqr_read_status(struct phy_device *phydev)
{
int reg;
int val;
reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
if (reg & MDIO_STAT1_LSTATUS)
phydev->link = 1;
else
phydev->link = 0;
reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_STATUS1);
mdelay(10);
reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_STATUS1);
switch (reg & MDIO_AN_TX_VEND_STATUS1_RATE_MASK) {
case MDIO_AN_TX_VEND_STATUS1_2500BASET:
phydev->speed = SPEED_2500;
break;
case MDIO_AN_TX_VEND_STATUS1_1000BASET:
phydev->speed = SPEED_1000;
break;
case MDIO_AN_TX_VEND_STATUS1_100BASETX:
phydev->speed = SPEED_100;
break;
default:
phydev->speed = SPEED_10000;
break;
if (phydev->autoneg == AUTONEG_ENABLE) {
val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RX_LP_STAT1);
if (val < 0)
return val;
linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
phydev->lp_advertising,
val & MDIO_AN_RX_LP_STAT1_1000BASET_FULL);
linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
phydev->lp_advertising,
val & MDIO_AN_RX_LP_STAT1_1000BASET_HALF);
}
phydev->duplex = DUPLEX_FULL;
return 0;
return genphy_c45_read_status(phydev);
}
static int aqcs109_config_init(struct phy_device *phydev)
{
/* AQCS109 belongs to a chip family partially supporting 10G and 5G.
* PMA speed ability bits are the same for all members of the family,
* AQCS109 however supports speeds up to 2.5G only.
*/
return phy_set_max_speed(phydev, SPEED_2500);
}
static struct phy_driver aqr_driver[] = {
......@@ -208,6 +241,7 @@ static struct phy_driver aqr_driver[] = {
.name = "Aquantia AQCS109",
.aneg_done = genphy_c45_aneg_done,
.get_features = genphy_c45_pma_read_abilities,
.config_init = aqcs109_config_init,
.config_aneg = aqr_config_aneg,
.config_intr = aqr_config_intr,
.ack_interrupt = aqr_ack_interrupt,
......
......@@ -275,7 +275,7 @@ int genphy_c45_read_lpa(struct phy_device *phydev)
if (val < 0)
return val;
mii_lpa_to_linkmode_lpa_t(phydev->lp_advertising, val);
mii_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, val);
phydev->pause = val & LPA_PAUSE_CAP ? 1 : 0;
phydev->asym_pause = val & LPA_PAUSE_ASYM ? 1 : 0;
......@@ -454,6 +454,39 @@ int genphy_c45_pma_read_abilities(struct phy_device *phydev)
}
EXPORT_SYMBOL_GPL(genphy_c45_pma_read_abilities);
/**
* genphy_c45_read_status - read PHY status
* @phydev: target phy_device struct
*
* Reads status from PHY and sets phy_device members accordingly.
*/
int genphy_c45_read_status(struct phy_device *phydev)
{
int ret;
ret = genphy_c45_read_link(phydev);
if (ret)
return ret;
phydev->speed = SPEED_UNKNOWN;
phydev->duplex = DUPLEX_UNKNOWN;
phydev->pause = 0;
phydev->asym_pause = 0;
if (phydev->autoneg == AUTONEG_ENABLE) {
ret = genphy_c45_read_lpa(phydev);
if (ret)
return ret;
phy_resolve_aneg_linkmode(phydev);
} else {
ret = genphy_c45_read_pma(phydev);
}
return ret;
}
EXPORT_SYMBOL_GPL(genphy_c45_read_status);
/* The gen10g_* functions are the old Clause 45 stub */
int gen10g_config_aneg(struct phy_device *phydev)
......
......@@ -1107,6 +1107,7 @@ int genphy_c45_an_config_aneg(struct phy_device *phydev);
int genphy_c45_an_disable_aneg(struct phy_device *phydev);
int genphy_c45_read_mdix(struct phy_device *phydev);
int genphy_c45_pma_read_abilities(struct phy_device *phydev);
int genphy_c45_read_status(struct phy_device *phydev);
/* The gen10g_* functions are the old Clause 45 stub */
int gen10g_config_aneg(struct phy_device *phydev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment