lkml.org 
[lkml]   [2020]   [Jul]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH net-next v1] net: phy: at803x: add mdix configuration support for AR9331 and AR8035
    Date
    This patch add MDIX configuration ability for AR9331 and AR8035. Theoretically
    it should work on other Atheros PHYs, but I was able to test only this
    two.

    Since I have no certified reference HW able to detect or configure MDIX, this
    functionality was confirmed by oscilloscope.

    Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
    ---
    drivers/net/phy/at803x.c | 78 ++++++++++++++++++++++++++++++++++++++++
    1 file changed, 78 insertions(+)

    diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
    index 96c61aa75bd7..101651b2de54 100644
    --- a/drivers/net/phy/at803x.c
    +++ b/drivers/net/phy/at803x.c
    @@ -21,6 +21,17 @@
    #include <linux/regulator/consumer.h>
    #include <dt-bindings/net/qca-ar803x.h>

    +#define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10
    +#define AT803X_SFC_ASSERT_CRS BIT(11)
    +#define AT803X_SFC_FORCE_LINK BIT(10)
    +#define AT803X_SFC_MDI_CROSSOVER_MODE_M GENMASK(6, 5)
    +#define AT803X_SFC_AUTOMATIC_CROSSOVER 0x3
    +#define AT803X_SFC_MANUAL_MDIX 0x1
    +#define AT803X_SFC_MANUAL_MDI 0x0
    +#define AT803X_SFC_SQE_TEST BIT(2)
    +#define AT803X_SFC_POLARITY_REVERSAL BIT(1)
    +#define AT803X_SFC_DISABLE_JABBER BIT(0)
    +
    #define AT803X_SPECIFIC_STATUS 0x11
    #define AT803X_SS_SPEED_MASK (3 << 14)
    #define AT803X_SS_SPEED_1000 (2 << 14)
    @@ -703,6 +714,12 @@ static int at803x_read_status(struct phy_device *phydev)
    return ss;

    if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) {
    + int sfc;
    +
    + sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL);
    + if (sfc < 0)
    + return sfc;
    +
    switch (ss & AT803X_SS_SPEED_MASK) {
    case AT803X_SS_SPEED_10:
    phydev->speed = SPEED_10;
    @@ -718,10 +735,23 @@ static int at803x_read_status(struct phy_device *phydev)
    phydev->duplex = DUPLEX_FULL;
    else
    phydev->duplex = DUPLEX_HALF;
    +
    if (ss & AT803X_SS_MDIX)
    phydev->mdix = ETH_TP_MDI_X;
    else
    phydev->mdix = ETH_TP_MDI;
    +
    + switch (FIELD_GET(AT803X_SFC_MDI_CROSSOVER_MODE_M, sfc)) {
    + case AT803X_SFC_MANUAL_MDI:
    + phydev->mdix_ctrl = ETH_TP_MDI;
    + break;
    + case AT803X_SFC_MANUAL_MDIX:
    + phydev->mdix_ctrl = ETH_TP_MDI_X;
    + break;
    + case AT803X_SFC_AUTOMATIC_CROSSOVER:
    + phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
    + break;
    + }
    }

    if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
    @@ -730,6 +760,50 @@ static int at803x_read_status(struct phy_device *phydev)
    return 0;
    }

    +static int at803x_config_mdix(struct phy_device *phydev, u8 ctrl)
    +{
    + u16 val;
    +
    + switch (ctrl) {
    + case ETH_TP_MDI:
    + val = AT803X_SFC_MANUAL_MDI;
    + break;
    + case ETH_TP_MDI_X:
    + val = AT803X_SFC_MANUAL_MDIX;
    + break;
    + case ETH_TP_MDI_AUTO:
    + val = AT803X_SFC_AUTOMATIC_CROSSOVER;
    + break;
    + default:
    + return 0;
    + }
    +
    + return phy_modify_changed(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL,
    + AT803X_SFC_MDI_CROSSOVER_MODE_M,
    + FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val));
    +}
    +
    +static int at803x_config_aneg(struct phy_device *phydev)
    +{
    + int ret;
    +
    + ret = at803x_config_mdix(phydev, phydev->mdix_ctrl);
    + if (ret < 0)
    + return ret;
    +
    + /* Changes of the midx bits are disruptive to the normal operation;
    + * therefore any changes to these registers must be followed by a
    + * software reset to take effect.
    + */
    + if (ret == 1) {
    + ret = genphy_soft_reset(phydev);
    + if (ret < 0)
    + return ret;
    + }
    +
    + return genphy_config_aneg(phydev);
    +}
    +
    static int at803x_get_downshift(struct phy_device *phydev, u8 *d)
    {
    int val;
    @@ -979,6 +1053,7 @@ static struct phy_driver at803x_driver[] = {
    .flags = PHY_POLL_CABLE_TEST,
    .probe = at803x_probe,
    .remove = at803x_remove,
    + .config_aneg = at803x_config_aneg,
    .config_init = at803x_config_init,
    .soft_reset = genphy_soft_reset,
    .set_wol = at803x_set_wol,
    @@ -1061,6 +1136,9 @@ static struct phy_driver at803x_driver[] = {
    .config_intr = &at803x_config_intr,
    .cable_test_start = at803x_cable_test_start,
    .cable_test_get_status = at803x_cable_test_get_status,
    + .read_status = at803x_read_status,
    + .soft_reset = genphy_soft_reset,
    + .config_aneg = at803x_config_aneg,
    } };

    module_phy_driver(at803x_driver);
    --
    2.27.0
    \
     
     \ /
      Last update: 2020-07-19 10:06    [W:3.147 / U:0.888 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site